]> git.netwichtig.de Git - user/henk/code/inspircd.git/commitdiff
OOPS! We try again, since I'm smoking craq. LF is 0x0a NOT CR.
authorpeavey <peavey@e03df62e-2008-0410-955e-edbf42e46eb7>
Mon, 16 Jul 2007 17:30:04 +0000 (17:30 +0000)
committerpeavey <peavey@e03df62e-2008-0410-955e-edbf42e46eb7>
Mon, 16 Jul 2007 17:30:04 +0000 (17:30 +0000)
git-svn-id: http://svn.inspircd.org/repository/trunk/inspircd@7456 e03df62e-2008-0410-955e-edbf42e46eb7

397 files changed:
conf/aliases/anope.conf.example
conf/aliases/atheme.conf.example
conf/aliases/ircservices.conf.example
conf/inspircd.censor.example
conf/inspircd.filter.example
conf/inspircd.helpop-full.example
conf/inspircd.helpop.example
conf/inspircd.motd.example
conf/inspircd.quotes.example
conf/inspircd.rules.example
configure
docs/COPYING
docs/README
docs/inspircd.conf.example
docs/rfc/rfc1035.txt
docs/rfc/rfc1413.txt
docs/rfc/rfc1459.txt
extras/m_sqllog.mysql.sql
extras/m_sqllog.postgresql.sql
extras/m_sqllog.sqlite3.sql
extras/m_sqloper.mysql.sql
extras/m_sqloper.postgresql.sql
extras/m_sqloper.sqlite3.sql
http/index.html
include/base.h
include/channels.h
include/command_parse.h
include/commands/cmd_admin.h
include/commands/cmd_away.h
include/commands/cmd_clearcache.h
include/commands/cmd_commands.h
include/commands/cmd_connect.h
include/commands/cmd_die.h
include/commands/cmd_eline.h
include/commands/cmd_gline.h
include/commands/cmd_info.h
include/commands/cmd_invite.h
include/commands/cmd_ison.h
include/commands/cmd_join.h
include/commands/cmd_kick.h
include/commands/cmd_kill.h
include/commands/cmd_kline.h
include/commands/cmd_links.h
include/commands/cmd_list.h
include/commands/cmd_loadmodule.h
include/commands/cmd_lusers.h
include/commands/cmd_map.h
include/commands/cmd_mode.h
include/commands/cmd_modules.h
include/commands/cmd_motd.h
include/commands/cmd_names.h
include/commands/cmd_nick.h
include/commands/cmd_notice.h
include/commands/cmd_oper.h
include/commands/cmd_part.h
include/commands/cmd_pass.h
include/commands/cmd_ping.h
include/commands/cmd_pong.h
include/commands/cmd_privmsg.h
include/commands/cmd_qline.h
include/commands/cmd_quit.h
include/commands/cmd_rehash.h
include/commands/cmd_reloadmodule.h
include/commands/cmd_restart.h
include/commands/cmd_rules.h
include/commands/cmd_server.h
include/commands/cmd_squit.h
include/commands/cmd_stats.h
include/commands/cmd_summon.h
include/commands/cmd_time.h
include/commands/cmd_topic.h
include/commands/cmd_trace.h
include/commands/cmd_unloadmodule.h
include/commands/cmd_user.h
include/commands/cmd_userhost.h
include/commands/cmd_users.h
include/commands/cmd_version.h
include/commands/cmd_wallops.h
include/commands/cmd_who.h
include/commands/cmd_whois.h
include/commands/cmd_whowas.h
include/commands/cmd_zline.h
include/configreader.h
include/connection.h
include/ctables.h
include/cull_list.h
include/dns.h
include/dynamic.h
include/exitcodes.h
include/globals.h
include/hash_map.h
include/hashcomp.h
include/inspircd.h
include/inspsocket.h
include/inspstring.h
include/mode.h
include/modes/cmode_b.h
include/modes/cmode_h.h
include/modes/cmode_i.h
include/modes/cmode_k.h
include/modes/cmode_l.h
include/modes/cmode_m.h
include/modes/cmode_n.h
include/modes/cmode_o.h
include/modes/cmode_p.h
include/modes/cmode_s.h
include/modes/cmode_t.h
include/modes/cmode_v.h
include/modes/umode_i.h
include/modes/umode_n.h
include/modes/umode_o.h
include/modes/umode_s.h
include/modes/umode_w.h
include/modules.h
include/snomasks.h
include/socket.h
include/socketengine.h
include/socketengine_epoll.h
include/socketengine_iocp.h
include/socketengine_kqueue.h
include/socketengine_ports.h
include/socketengine_select.h
include/timer.h
include/typedefs.h
include/u_listmode.h
include/users.h
include/wildcard.h
include/xline.h
make/configure.pm
make/gnutlscert.pm
make/opensslcert.pm
make/utilities.pm
src/base.cpp
src/channels.cpp
src/cmd_admin.cpp
src/cmd_away.cpp
src/cmd_clearcache.cpp
src/cmd_commands.cpp
src/cmd_connect.cpp
src/cmd_die.cpp
src/cmd_eline.cpp
src/cmd_gline.cpp
src/cmd_info.cpp
src/cmd_invite.cpp
src/cmd_ison.cpp
src/cmd_join.cpp
src/cmd_kick.cpp
src/cmd_kill.cpp
src/cmd_kline.cpp
src/cmd_links.cpp
src/cmd_list.cpp
src/cmd_loadmodule.cpp
src/cmd_lusers.cpp
src/cmd_map.cpp
src/cmd_mode.cpp
src/cmd_modules.cpp
src/cmd_motd.cpp
src/cmd_names.cpp
src/cmd_nick.cpp
src/cmd_notice.cpp
src/cmd_oper.cpp
src/cmd_part.cpp
src/cmd_pass.cpp
src/cmd_ping.cpp
src/cmd_pong.cpp
src/cmd_privmsg.cpp
src/cmd_qline.cpp
src/cmd_quit.cpp
src/cmd_rehash.cpp
src/cmd_reloadmodule.cpp
src/cmd_restart.cpp
src/cmd_rules.cpp
src/cmd_server.cpp
src/cmd_squit.cpp
src/cmd_stats.cpp
src/cmd_summon.cpp
src/cmd_time.cpp
src/cmd_topic.cpp
src/cmd_trace.cpp
src/cmd_unloadmodule.cpp
src/cmd_user.cpp
src/cmd_userhost.cpp
src/cmd_users.cpp
src/cmd_version.cpp
src/cmd_wallops.cpp
src/cmd_who.cpp
src/cmd_whois.cpp
src/cmd_whowas.cpp
src/cmd_zline.cpp
src/command_parse.cpp
src/commands.cpp
src/configreader.cpp
src/cull_list.cpp
src/dns.cpp
src/dynamic.cpp
src/hashcomp.cpp
src/helperfuncs.cpp
src/inspircd.cpp
src/inspsocket.cpp
src/inspstring.cpp
src/mode.cpp
src/modes/Makefile
src/modes/cmode_b.cpp
src/modes/cmode_h.cpp
src/modes/cmode_i.cpp
src/modes/cmode_k.cpp
src/modes/cmode_l.cpp
src/modes/cmode_m.cpp
src/modes/cmode_n.cpp
src/modes/cmode_o.cpp
src/modes/cmode_p.cpp
src/modes/cmode_s.cpp
src/modes/cmode_t.cpp
src/modes/cmode_v.cpp
src/modes/umode_i.cpp
src/modes/umode_n.cpp
src/modes/umode_o.cpp
src/modes/umode_s.cpp
src/modes/umode_w.cpp
src/modules.cpp
src/modules/extra/README
src/modules/extra/m_filter_pcre.cpp
src/modules/extra/m_httpclienttest.cpp
src/modules/extra/m_mysql.cpp
src/modules/extra/m_pgsql.cpp
src/modules/extra/m_sqlauth.cpp
src/modules/extra/m_sqlite3.cpp
src/modules/extra/m_sqllog.cpp
src/modules/extra/m_sqloper.cpp
src/modules/extra/m_sqlutils.cpp
src/modules/extra/m_sqlutils.h
src/modules/extra/m_sqlv2.h
src/modules/extra/m_ssl_gnutls.cpp
src/modules/extra/m_ssl_openssl.cpp
src/modules/extra/m_ssl_oper_cert.cpp
src/modules/extra/m_sslinfo.cpp
src/modules/extra/m_testclient.cpp
src/modules/extra/m_ziplink.cpp
src/modules/httpclient.h
src/modules/httpd.h
src/modules/m_alias.cpp
src/modules/m_alltime.cpp
src/modules/m_antibear.cpp
src/modules/m_antibottler.cpp
src/modules/m_auditorium.cpp
src/modules/m_banexception.cpp
src/modules/m_banredirect.cpp
src/modules/m_blockamsg.cpp
src/modules/m_blockcaps.cpp
src/modules/m_blockcolor.cpp
src/modules/m_botmode.cpp
src/modules/m_cban.cpp
src/modules/m_censor.cpp
src/modules/m_cgiirc.cpp
src/modules/m_chancreate.cpp
src/modules/m_chanfilter.cpp
src/modules/m_chanprotect.cpp
src/modules/m_check.cpp
src/modules/m_chghost.cpp
src/modules/m_chgident.cpp
src/modules/m_chgname.cpp
src/modules/m_cloaking.cpp
src/modules/m_clones.cpp
src/modules/m_conn_join.cpp
src/modules/m_conn_umodes.cpp
src/modules/m_conn_waitpong.cpp
src/modules/m_connflood.cpp
src/modules/m_cycle.cpp
src/modules/m_dccallow.cpp
src/modules/m_deaf.cpp
src/modules/m_denychans.cpp
src/modules/m_devoice.cpp
src/modules/m_dnsbl.cpp
src/modules/m_filter.cpp
src/modules/m_filter.h
src/modules/m_foobar.cpp
src/modules/m_globalload.cpp
src/modules/m_globops.cpp
src/modules/m_hash.h
src/modules/m_helpop.cpp
src/modules/m_hidechans.cpp
src/modules/m_hideoper.cpp
src/modules/m_hostchange.cpp
src/modules/m_http_client.cpp
src/modules/m_httpd.cpp
src/modules/m_httpd_stats.cpp
src/modules/m_ident.cpp
src/modules/m_invisible.cpp
src/modules/m_inviteexception.cpp
src/modules/m_joinflood.cpp
src/modules/m_jumpserver.cpp
src/modules/m_kicknorejoin.cpp
src/modules/m_knock.cpp
src/modules/m_lockserv.cpp
src/modules/m_md5.cpp
src/modules/m_messageflood.cpp
src/modules/m_namesx.cpp
src/modules/m_nicklock.cpp
src/modules/m_noctcp.cpp
src/modules/m_noinvite.cpp
src/modules/m_nokicks.cpp
src/modules/m_nonicks.cpp
src/modules/m_nonotice.cpp
src/modules/m_oper_hash.cpp
src/modules/m_operchans.cpp
src/modules/m_operjoin.cpp
src/modules/m_operlevels.cpp
src/modules/m_operlog.cpp
src/modules/m_opermodes.cpp
src/modules/m_opermotd.cpp
src/modules/m_override.cpp
src/modules/m_randquote.cpp
src/modules/m_redirect.cpp
src/modules/m_regonlycreate.cpp
src/modules/m_remove.cpp
src/modules/m_restrictbanned.cpp
src/modules/m_restrictchans.cpp
src/modules/m_restrictmsg.cpp
src/modules/m_safelist.cpp
src/modules/m_sajoin.cpp
src/modules/m_samode.cpp
src/modules/m_sanick.cpp
src/modules/m_sapart.cpp
src/modules/m_saquit.cpp
src/modules/m_securelist.cpp
src/modules/m_seenicks.cpp
src/modules/m_services.cpp
src/modules/m_services_account.cpp
src/modules/m_sethost.cpp
src/modules/m_setident.cpp
src/modules/m_setidle.cpp
src/modules/m_setname.cpp
src/modules/m_sha256.cpp
src/modules/m_showwhois.cpp
src/modules/m_silence.cpp
src/modules/m_silence_ext.cpp
src/modules/m_spanningtree/README
src/modules/m_spanningtree/handshaketimer.cpp
src/modules/m_spanningtree/handshaketimer.h
src/modules/m_spanningtree/link.h
src/modules/m_spanningtree/main.cpp
src/modules/m_spanningtree/main.h
src/modules/m_spanningtree/rconnect.cpp
src/modules/m_spanningtree/rconnect.h
src/modules/m_spanningtree/resolvers.cpp
src/modules/m_spanningtree/resolvers.h
src/modules/m_spanningtree/rsquit.cpp
src/modules/m_spanningtree/rsquit.h
src/modules/m_spanningtree/timesynctimer.cpp
src/modules/m_spanningtree/timesynctimer.h
src/modules/m_spanningtree/treeserver.cpp
src/modules/m_spanningtree/treeserver.h
src/modules/m_spanningtree/treesocket.h
src/modules/m_spanningtree/treesocket1.cpp
src/modules/m_spanningtree/treesocket2.cpp
src/modules/m_spanningtree/utils.cpp
src/modules/m_spanningtree/utils.h
src/modules/m_spy.cpp
src/modules/m_ssl_dummy.cpp
src/modules/m_sslmodes.cpp
src/modules/m_stripcolor.cpp
src/modules/m_svshold.cpp
src/modules/m_swhois.cpp
src/modules/m_taxonomy.cpp
src/modules/m_testcommand.cpp
src/modules/m_timedbans.cpp
src/modules/m_tline.cpp
src/modules/m_uhnames.cpp
src/modules/m_uninvite.cpp
src/modules/m_userip.cpp
src/modules/m_vhost.cpp
src/modules/m_watch.cpp
src/modules/m_xmlsocket.cpp
src/modules/transport.h
src/snomasks.cpp
src/socket.cpp
src/socketengine.cpp
src/socketengine_epoll.cpp
src/socketengine_iocp.cpp
src/socketengine_kqueue.cpp
src/socketengine_ports.cpp
src/socketengine_select.cpp
src/timer.cpp
src/userprocess.cpp
src/users.cpp
src/version.sh
src/wildcard.cpp
src/xline.cpp
win/cert.pem
win/colours.h
win/configure.cpp
win/inspircd.nsi
win/inspircd_memory_functions.cpp
win/inspircd_win32wrapper.cpp
win/inspircd_win32wrapper.h
win/key.pem
win/makeinstaller.bat

index 9b20fafcb7f02eea91b91f751ecb5e6787f3904c..03e68d9d8da867cc8b824491e12e721bbf808b1a 100644 (file)
@@ -1 +1,25 @@
-# Aliases for nickserv, chanserv, operserv, memoserv\r<alias text="NICKSERV" replace="PRIVMSG NickServ :$2-" requires="NickServ" uline="yes">\r<alias text="CHANSERV" replace="PRIVMSG ChanServ :$2-" requires="ChanServ" uline="yes">\r<alias text="OPERSERV" replace="PRIVMSG OperServ :$2-" requires="OperServ" uline="yes" operonly="yes">\r<alias text="MEMOSERV" replace="PRIVMSG MemoServ :$2-" requires="MemoServ" uline="yes">\r<alias text="HOSTSERV" replace="PRIVMSG HostServ :$2-" requires="MemoServ" uline="yes">\r<alias text="BOTSERV" replace="PRIVMSG BotServ :$2-" requires="BotServ" uline="yes">\r\r# Note: We can't have a shorthand version of this, it conflicts with HS for helpserv\r<alias text="HELPSERV" replace="PRIVMSG HelpServ :$2-" requires="HelpServ" uline="yes">\r\r# Shorthand aliases for nickserv, chanserv, operserv, memoserv\r<alias text="NS" replace="PRIVMSG NickServ :$2-" requires="NickServ" uline="yes">\r<alias text="CS" replace="PRIVMSG ChanServ :$2-" requires="ChanServ" uline="yes">\r<alias text="OS" replace="PRIVMSG OperServ :$2-" requires="OperServ" uline="yes" operonly="yes">\r<alias text="MS" replace="PRIVMSG MemoServ :$2-" requires="MemoServ" uline="yes">\r<alias text="HS" replace="PRIVMSG HostServ :$2-" requires="HostServ" uline="yes">\r<alias text="BS" replace="PRIVMSG BotServ :$2-" requires="BotServ" uline="yes">\r\r\r# /id [channel] <password>\r# Identify for a channel or nickname\r<alias text="ID" format="#*" replace="PRIVMSG ChanServ :IDENTIFY $2 $3" requires="ChanServ" uline="yes">\r<alias text="ID" format="*" replace="PRIVMSG NickServ :IDENTIFY $2" requires="NickServ" uline="yes">\r\r
\ No newline at end of file
+# Aliases for nickserv, chanserv, operserv, memoserv
+<alias text="NICKSERV" replace="PRIVMSG NickServ :$2-" requires="NickServ" uline="yes">
+<alias text="CHANSERV" replace="PRIVMSG ChanServ :$2-" requires="ChanServ" uline="yes">
+<alias text="OPERSERV" replace="PRIVMSG OperServ :$2-" requires="OperServ" uline="yes" operonly="yes">
+<alias text="MEMOSERV" replace="PRIVMSG MemoServ :$2-" requires="MemoServ" uline="yes">
+<alias text="HOSTSERV" replace="PRIVMSG HostServ :$2-" requires="MemoServ" uline="yes">
+<alias text="BOTSERV" replace="PRIVMSG BotServ :$2-" requires="BotServ" uline="yes">
+
+# Note: We can't have a shorthand version of this, it conflicts with HS for helpserv
+<alias text="HELPSERV" replace="PRIVMSG HelpServ :$2-" requires="HelpServ" uline="yes">
+
+# Shorthand aliases for nickserv, chanserv, operserv, memoserv
+<alias text="NS" replace="PRIVMSG NickServ :$2-" requires="NickServ" uline="yes">
+<alias text="CS" replace="PRIVMSG ChanServ :$2-" requires="ChanServ" uline="yes">
+<alias text="OS" replace="PRIVMSG OperServ :$2-" requires="OperServ" uline="yes" operonly="yes">
+<alias text="MS" replace="PRIVMSG MemoServ :$2-" requires="MemoServ" uline="yes">
+<alias text="HS" replace="PRIVMSG HostServ :$2-" requires="HostServ" uline="yes">
+<alias text="BS" replace="PRIVMSG BotServ :$2-" requires="BotServ" uline="yes">
+
+
+# /id [channel] <password>
+# Identify for a channel or nickname
+<alias text="ID" format="#*" replace="PRIVMSG ChanServ :IDENTIFY $2 $3" requires="ChanServ" uline="yes">
+<alias text="ID" format="*" replace="PRIVMSG NickServ :IDENTIFY $2" requires="NickServ" uline="yes">
+
index 17f6d2907dd63b5842d3e75b4d45e19f13aecd9c..d6771f9652130020bd0fd88bbd82c13d505b6c1c 100644 (file)
@@ -1 +1,19 @@
-# Aliases for nickserv, chanserv, operserv, memoserv\r<alias text="NICKSERV" replace="PRIVMSG NickServ :$2-" requires="NickServ" uline="yes">\r<alias text="CHANSERV" replace="PRIVMSG ChanServ :$2-" requires="ChanServ" uline="yes">\r<alias text="OPERSERV" replace="PRIVMSG OperServ :$2-" requires="OperServ" uline="yes" operonly="yes">\r<alias text="MEMOSERV" replace="PRIVMSG MemoServ :$2-" requires="MemoServ" uline="yes">\r<alias text="GAMESERV" replace="PRIVMSG GameServ :$2-" requires="GameServ" uline="yes">\r\r# Shorthand aliases for nickserv, chanserv, operserv, memoserv\r<alias text="NS" replace="PRIVMSG NickServ :$2-" requires="NickServ" uline="yes">\r<alias text="CS" replace="PRIVMSG ChanServ :$2-" requires="ChanServ" uline="yes">\r<alias text="OS" replace="PRIVMSG OperServ :$2-" requires="OperServ" uline="yes" operonly="yes">\r<alias text="MS" replace="PRIVMSG MemoServ :$2-" requires="MemoServ" uline="yes">\r<alias text="GS" replace="PRIVMSG GameServ :$2-" requires="GameServ" uline="yes">\r\r# /id [channel] <password>\r# Identify for a channel or nickname\r<alias text="ID" format="#*" replace="PRIVMSG ChanServ :IDENTIFY $2 $3" requires="ChanServ" uline="yes">\r<alias text="ID" format="*" replace="PRIVMSG NickServ :IDENTIFY $2-" requires="NickServ" uline="yes">\r\r
\ No newline at end of file
+# Aliases for nickserv, chanserv, operserv, memoserv
+<alias text="NICKSERV" replace="PRIVMSG NickServ :$2-" requires="NickServ" uline="yes">
+<alias text="CHANSERV" replace="PRIVMSG ChanServ :$2-" requires="ChanServ" uline="yes">
+<alias text="OPERSERV" replace="PRIVMSG OperServ :$2-" requires="OperServ" uline="yes" operonly="yes">
+<alias text="MEMOSERV" replace="PRIVMSG MemoServ :$2-" requires="MemoServ" uline="yes">
+<alias text="GAMESERV" replace="PRIVMSG GameServ :$2-" requires="GameServ" uline="yes">
+
+# Shorthand aliases for nickserv, chanserv, operserv, memoserv
+<alias text="NS" replace="PRIVMSG NickServ :$2-" requires="NickServ" uline="yes">
+<alias text="CS" replace="PRIVMSG ChanServ :$2-" requires="ChanServ" uline="yes">
+<alias text="OS" replace="PRIVMSG OperServ :$2-" requires="OperServ" uline="yes" operonly="yes">
+<alias text="MS" replace="PRIVMSG MemoServ :$2-" requires="MemoServ" uline="yes">
+<alias text="GS" replace="PRIVMSG GameServ :$2-" requires="GameServ" uline="yes">
+
+# /id [channel] <password>
+# Identify for a channel or nickname
+<alias text="ID" format="#*" replace="PRIVMSG ChanServ :IDENTIFY $2 $3" requires="ChanServ" uline="yes">
+<alias text="ID" format="*" replace="PRIVMSG NickServ :IDENTIFY $2-" requires="NickServ" uline="yes">
+
index 52512a9e59e7558a5950f68ae9ddad9e28c989f8..edfe784a2b7b34b5965b5695a867b3e1e79d27f0 100644 (file)
@@ -1 +1,19 @@
-# Aliases for nickserv, chanserv, operserv, memoserv\r<alias text="NICKSERV" replace="PRIVMSG NickServ :$2-" requires="NickServ" uline="yes">\r<alias text="CHANSERV" replace="PRIVMSG ChanServ :$2-" requires="ChanServ" uline="yes">\r<alias text="OPERSERV" replace="PRIVMSG OperServ :$2-" requires="OperServ" uline="yes" operonly="yes">\r<alias text="MEMOSERV" replace="PRIVMSG MemoServ :$2-" requires="MemoServ" uline="yes">\r<alias text="STATSERV" replace="PRIVMSG StatServ :$2-" requires="StatServ" uline="yes" operonly="yes">\r\r# Shorthand aliases for nickserv, chanserv, operserv, memoserv\r<alias text="NS" replace="PRIVMSG NickServ :$2-" requires="NickServ" uline="yes">\r<alias text="CS" replace="PRIVMSG ChanServ :$2-" requires="ChanServ" uline="yes">\r<alias text="OS" replace="PRIVMSG OperServ :$2-" requires="OperServ" uline="yes" operonly="yes">\r<alias text="MS" replace="PRIVMSG MemoServ :$2-" requires="MemoServ" uline="yes">\r<alias text="SS" replace="PRIVMSG StatServ :$2-" requires="StatServ" uline="yes" operonly="yes">\r\r# /id [channel] <password>\r# Identify for a channel or nickname\r<alias text="ID" format="#*" replace="PRIVMSG ChanServ :IDENTIFY $2 $3" requires="ChanServ" uline="yes">\r<alias text="ID" format="*" replace="PRIVMSG NickServ :IDENTIFY $2" requires="NickServ" uline="yes">\r\r
\ No newline at end of file
+# Aliases for nickserv, chanserv, operserv, memoserv
+<alias text="NICKSERV" replace="PRIVMSG NickServ :$2-" requires="NickServ" uline="yes">
+<alias text="CHANSERV" replace="PRIVMSG ChanServ :$2-" requires="ChanServ" uline="yes">
+<alias text="OPERSERV" replace="PRIVMSG OperServ :$2-" requires="OperServ" uline="yes" operonly="yes">
+<alias text="MEMOSERV" replace="PRIVMSG MemoServ :$2-" requires="MemoServ" uline="yes">
+<alias text="STATSERV" replace="PRIVMSG StatServ :$2-" requires="StatServ" uline="yes" operonly="yes">
+
+# Shorthand aliases for nickserv, chanserv, operserv, memoserv
+<alias text="NS" replace="PRIVMSG NickServ :$2-" requires="NickServ" uline="yes">
+<alias text="CS" replace="PRIVMSG ChanServ :$2-" requires="ChanServ" uline="yes">
+<alias text="OS" replace="PRIVMSG OperServ :$2-" requires="OperServ" uline="yes" operonly="yes">
+<alias text="MS" replace="PRIVMSG MemoServ :$2-" requires="MemoServ" uline="yes">
+<alias text="SS" replace="PRIVMSG StatServ :$2-" requires="StatServ" uline="yes" operonly="yes">
+
+# /id [channel] <password>
+# Identify for a channel or nickname
+<alias text="ID" format="#*" replace="PRIVMSG ChanServ :IDENTIFY $2 $3" requires="ChanServ" uline="yes">
+<alias text="ID" format="*" replace="PRIVMSG NickServ :IDENTIFY $2" requires="NickServ" uline="yes">
+
index 108f88c125922786b04dcbd3d25d0f4eca3838c5..05d9ce6fa8fc3bd58185ea2ec44e3cd0152b33c0 100644 (file)
@@ -1 +1,15 @@
-# Configuration file for m_censor.so (1.0.0.0)\r# C.J.Edwards May 2004.\r#\r\r# The tags for this module are formatted as follows:\r#\r# <badword    text="simple word"\r#            replace="text to replace with">\r#\r# You can specify <badword text="simple word" replace="">\r# to block lines containing the word\r\r<badword text="shit" replace="poo">\r<badword text="fuck" replace="(censored)">\r\r
\ No newline at end of file
+# Configuration file for m_censor.so (1.0.0.0)
+# C.J.Edwards May 2004.
+#
+
+# The tags for this module are formatted as follows:
+#
+# <badword     text="simple word"
+#              replace="text to replace with">
+#
+# You can specify <badword text="simple word" replace="">
+# to block lines containing the word
+
+<badword text="shit" replace="poo">
+<badword text="fuck" replace="(censored)">
+
index f4487a71922ddc2d95d4274ab982ef3d3a8341c5..7623a44721c9d0f6c947343fa722c0a196ee4d4e 100644 (file)
@@ -1 +1,52 @@
-# Configuration file for m_filter.so and m_filter_pcre.so\r\r# The tags for this module are formatted as follows:\r#\r# <keyword      pattern="any glob pattern here"\r#               reason="reason for filtering"\r#               action="action to take"\r#               flags="filter flags"\r#         duration="optional length of gline">\r#\r# Valid actions for 'action' are:\r#\r# block         This blocks the line, sends out a notice to all opers with\r#               +s and informs the user that their message was blocked.\r#\r# silent        This blocks the line only, and informs the user their message\r#               was blocked, but does not notify opers.\r#\r# none          This action causes nothing to be done except logging. This\r#               is the default action if none is specified.\r#\r# kill          This disconnects the user, with the 'reason' parameter as\r#               the kill reason.\r#\r# gline         G-LINE the user for 'duration' length of time. Durations may\r#               be specified using the notation 1y2d3h4m6s in a similar way to\r#               other glines, omitting the duration or setting it to 0 makes\r#               any glines set by this filter be permanent.\r#\r# You can add filters from IRC using the /FILTER command. If you do this, they\r# will be set globally to your entire network.\r#\r# Valid characters for 'flags' are one or more of:\r#\r# p: Block private and channel messages\r# n: Block private and channel notices\r# P: Block part messages\r# q: Block quit messages\r# o: Don't match against opers\r# *: Represents all of the above flags\r# -: Does nothing, a non-op for when you do not want to specify any flags \r\r# Example filters for m_filter:\r#\r# <keyword pattern="*qwerty*" reason="You qwertied!" action="block" flags="pn">\r# <keyword pattern="*killmenow*" reason="As you request." action="kill" flags="*">\r# <keyword pattern="*blah*" reason="Dont blah!" action="gline" duration="1d6h" flags="-">\r\r# An example regexp filter for m_filter_pcre:\r#\r# <keyword pattern="^blah.*?$" reason="Dont blah!" action="gline" duration="1d6h" flags="pnPq">\r\r
\ No newline at end of file
+# Configuration file for m_filter.so and m_filter_pcre.so
+
+# The tags for this module are formatted as follows:
+#
+# <keyword      pattern="any glob pattern here"
+#               reason="reason for filtering"
+#               action="action to take"
+#               flags="filter flags"
+#              duration="optional length of gline">
+#
+# Valid actions for 'action' are:
+#
+# block         This blocks the line, sends out a notice to all opers with
+#               +s and informs the user that their message was blocked.
+#
+# silent        This blocks the line only, and informs the user their message
+#               was blocked, but does not notify opers.
+#
+# none          This action causes nothing to be done except logging. This
+#               is the default action if none is specified.
+#
+# kill          This disconnects the user, with the 'reason' parameter as
+#               the kill reason.
+#
+# gline         G-LINE the user for 'duration' length of time. Durations may
+#               be specified using the notation 1y2d3h4m6s in a similar way to
+#               other glines, omitting the duration or setting it to 0 makes
+#               any glines set by this filter be permanent.
+#
+# You can add filters from IRC using the /FILTER command. If you do this, they
+# will be set globally to your entire network.
+#
+# Valid characters for 'flags' are one or more of:
+#
+# p: Block private and channel messages
+# n: Block private and channel notices
+# P: Block part messages
+# q: Block quit messages
+# o: Don't match against opers
+# *: Represents all of the above flags
+# -: Does nothing, a non-op for when you do not want to specify any flags 
+
+# Example filters for m_filter:
+#
+# <keyword pattern="*qwerty*" reason="You qwertied!" action="block" flags="pn">
+# <keyword pattern="*killmenow*" reason="As you request." action="kill" flags="*">
+# <keyword pattern="*blah*" reason="Dont blah!" action="gline" duration="1d6h" flags="-">
+
+# An example regexp filter for m_filter_pcre:
+#
+# <keyword pattern="^blah.*?$" reason="Dont blah!" action="gline" duration="1d6h" flags="pnPq">
+
index 64437a4d74b7810c9e55a92e12625b689d07391d..a4b4f1e11f791514301d54e71ba8b377e07fa0ca 100644 (file)
@@ -1 +1,519 @@
-#####################\r#  Helpop Standard  #\r#####################\r\r<helpop key="start" value="InspIRCd help system\r-\rThis system provides help for commands and modes.\rSpecify your question or a command name as the\rparameter for this command. If you are an oper\ryou must prefix your query with a ? symbol.\r-\r/HELPOP COMMANDS      -      To see a list of user commands\r/HELPOP COPER         -      To see a list of oper commands\r/HELPOP UMODES        -      To see a list of user modes\r/HELPOP CHMODES       -      To see a list of channel modes">\r\r<helpop key="nohelp" value="There is no help for the topic\ryou searched for. Please try again.">\r\r#####################\r#   User Commands   #\r#####################\r\r<helpop key="commands" value="User Commands\r-------------\rUSER      NICK     QUIT     VERSION    PING\rPONG      ADMIN    PRIVMSG  INFO       TIME\rWHOIS     NOTICE   JOIN     NAMES      PART\rKICK      MODE     TOPIC    WHO        MOTD\rRULES     OPER     LIST     LUSERS     STATS\rUSERHOST  AWAY     ISON     SUMMON     USERS\rINVITE    PASS     WHOWAS   LINKS      MAP\rCOMMANDS  MODULES  KNOCK    SILENCE    DEVOICE\rREMOVE    UNINVITE VHOST    WATCH      USERIP">\r\r<helpop key="watch" value="/WATCH [C|S|+/-[NICK]]\rAdds or deletes a user from the watch list. C clears the list\rand S queries the status.">\r\r<helpop key="vhost" value="/VHOST [username] [password]\rAuthenticate for a vhost.">\r\r<helpop key="kick" value="/REMOVE [channel] [nick] {[reason]}\rRemoves a user from a channel you specify. You must be\rAt least a channel halfoperator to remove a user.\rA removed user will part with a message stating they\rwere removed from the channel and by whom.">\r\r<helpop key="devoice" value="/DEVOICE [channel]\rDevoices yourself from the specified channel.">\r\r<helpop key="silence" value="/SILENCE [+/-]<hostmask> [p|c|i|n|t|a|x]\r p        Block private messages\r c        Block channel messages\r i        Block invites\r n        Block private notices\r t        Block channel notices\r a        Block all of the above\r x        Exception\rA serverside /ignore of the given hostmask.\r/SILENCE without a parameter will list the hostmasks that you have silenced.">\r\r<helpop key="knock" value="/KNOCK [channel]\rSends a notice to a channel indicating you wish to join.">\r\r<helpop key="user" value="/USER [ident] [local host] [remote host] :[GECOS]\rThis command is used by your client to register your irc session.\rYou should not use it during an established connection.">\r\r<helpop key="nick" value="/NICK [new nick]\rChange your nickname to [new nick].">\r\r<helpop key="quit" value="/QUIT [reason]\rQuit from IRC and end your current session.">\r\r<helpop key="version" value="/VERSION\rReturns the server's version number.">\r\r<helpop key="ping" value="/PING [server]\rPing a server. Target server will answer with a PONG.">\r\r<helpop key="pong" value="/PONG [server]\rYour client should send this to answer server PINGs. You\rshould not issue this command manually.">\r\r<helpop key="admin" value="/ADMIN [server]\rFetches the administrative information on the given server.">\r\r<helpop key="privmsg" value="/MSG [target] [text]\rSends a message to a user or channel specified in [target].">\r\r<helpop key="notice" value="/NOTICE [target] [text]\rSends a notice to a user or channel specified in [target].">\r\r<helpop key="join" value="/JOIN [channel]{,[channel]} [key]{,[key]}\rJoins one or more channels you provide the names for.">\r\r<helpop key="names" value="/NAMES [channel]{,[channel]}\rReturn a list of users on the channels you provide.">\r\r<helpop key="part" value="/PART [channel]{,[channel] [reason]}\rLeaves one or more channels you specify.">\r\r<helpop key="kick" value="/KICK [channel] [nick] {[reason]}\rKicks a user from a channel you specify. You must be\rAt least a channel halfoperator to kick a user.">\r\r<helpop key="mode" value="/MODE [target] [+|-][modes]{[+|-][modes]} {mode parameters}\rSets the mode for a channel or a nickname specified in [target]\rA user may only set modes upon themselves, and may not set the\r+o usermode, and a user may only change channel modes of\rchannels where they are at least a halfoperator.">\r\r<helpop key="topic" value="/TOPIC [channel] {topic}\rSets or retrieves the channel topic. If a channel topic is\rgiven in the command and the channel is either not +t, or\rYou are at least a halfoperator, the channel topic will be\rchanged to the new one you provide.">\r\r<helpop key="who" value="/WHO [ [search-pattern] [ohurmaiMplf] ]\rLooks up the information of users matching the range you provide.\rYou may only /WHO nicknames in channels or on servers where you\rshare a common channel with them, or ones which are not +i (unless\ryou are an IRC operator). The search-pattern may be a special\rsequence of characters determined by the flags given below, or\rit may be one of a nickname, a channel, a hostmask, an ip address\rmask or a server mask.\r-\rValid WHO flags\r--------------- \rThe following flags after the mask have the following affects:\r-\r o      Show online IRC operators matching the mask\r u      Unlimit the results past the maximum /who results value\r        (IRC operators only)\r r      Show all users whose realnames match the mask. When this\r        flag is set it overrides the meaning of the search-pattern,\r        which must contain a glob pattern intended to match GECOS\r        (realname) fields.\r h      Show real hostnames rather than masked hostnames (IRC\r        operators only)\r m      Search for all users with a given set of user modes. When\r        this flag is set it overrides the meaning of the\r        search-pattern, which must contain the mode sequence to\r        search for, for example to find all users with +i and\r        without +s, issue the command WHO +i-s m.\r a      Show all users who have an away message matching the given mask\r p      Show all users who are connected on the given port number\r i      Show all users who have an ident (username) matching the given mask\r M      Show all users who have metadata attached to them with\r        the given key name\r l      Show only local users\r f      Show only remote (far) users\r-\rYou may combine multiple flags in one WHO command except where stated in the table above.">\r\r<helpop key="motd" value="/MOTD [server]\rShow the message of the day for [server]. Messages of the\rday contain important server rules and notice and should be\rread before using a server in any way!">\r\r<helpop key="rules" value="/RULES\rShow the rules file for the local server. This is similar in\reffect to /MOTD except that rules are optional. All users are\rsent the MOTD when they connect without having to request it.">\r\r<helpop key="oper" value="/OPER [login] [password]\rAttempts to authenticate a user as an IRC operator.\rPlease be aware that both successful and unsuccessful oper attempts\rAre logged, and sent to online IRC operators.">\r\r<helpop key="list" value="/LIST [pattern]\rCreates a list of all existing channels matching the glob pattern\r[pattern], e.g. *chat* or bot*.">\r\r<helpop key="lusers" value="/LUSERS\rShows a count of local and remote users, servers and channels.">\r\r<helpop key="userhost" value="/USERHOST [nickname]\rReturns the hostname and nickname of a user, and some other\rmiscellaneous information.">\r\r<helpop key="userip" value="/USERIP [nickname]\rReturns the ip and nickname of a user.">\r\r<helpop key="away" value="/AWAY {message}\rIf a message is given, marks you as being away, otherwise\rremoves your away status and previous message.">\r\r<helpop key="ison" value="/ISON [nick] {[nick]...}\rReturns a subset of the nicks you give, showing only those\rthat are currently online.">\r\r<helpop key="summon" value="/SUMMON [user]\rSummons a user from the shell where the ircd is running onto irc\rThis command is deprecated in the current protocol.">\r\r<helpop key="users" value="/USERS\rShows users logged into the shell where the ircd is running.\rThis command is deprecated in the current protocol.">\r\r<helpop key="invite" value="/INVITE [nick] [channel]\rInvites a user to a channel. If the channel is NOT +i, any\ruser, channel op or not, may invite any other user to the\rchannel, so long as they are a member of that channel.\rOtherwise, if +i is set only channel halfoperators\rand above may invite users into the channel.">\r\r<helpop key="pass" value="/PASS [password]\rThis command is used by your irc client when setting up\ryour irc session, and should not be issued by a fully\rconnected client.">\r\r<helpop key="whowas" value="/WHOWAS [nick]\rReturns a list of times the user was last seen on irc\ralong with the time they were last seen and their server.">\r\r<helpop key="links" value="/LINKS\rShows all servers linked to this one. Note that in this\rserver implementation all links will be flattened as\ra tree based layout is not in use.">\r\r<helpop key="map" value="/MAP\rShows a graphical representation of all users and servers\ron the network. The tree diagram is inaccurate in this\rimplementation as a tree based network is not in place.">\r\r#####################\r#   Oper Commands   #\r#####################\r\r<helpop key="coper" value="Oper Commands\r-------------\rDIE        RESTART     KILL         REHASH         TRACE\rCONNECT    SQUIT       MODULES      MKPASSWD       SHUN\rKLINE      QLINE       GLINE        ELINE          ZLINE\rSAJOIN     SAPART      SAMODE       SAQUIT         SANICK\rSETIDLE    SETHOST     SETNAME      SETIDENT       SWHOIS\rOPERMOTD   CHGHOST     CHGNAME      CHGIDENT       CBAN\rNICKLOCK   NICKUNLOCK  LOADMODULE   UNLOADMODULE   GLOBOPS\rSPYLIST    SPYNAMES    GLOADMODULE  GUNLOADMODULE  MKSHA256\rFREEZE     UNFREEZE    OPERPERMS    RCONNECT">\r\r<helpop key="rconnect" value="/RCONNECT [source mask] [target mask]\rAll servers matching [source mask] will try to connect to\rthe first server in the config file matching [target mask].">\r\r<helpop key="operperms" value="/OPERPERMS [nick]\rList all commands an oper has access to use.">\r\r<helpop key="freeze" value="/FREEZE [nick]\rPrevents the user from sending commands until they reconnect.\rUser is also notified they have been frozen.">\r\r<helpop key="unfreeze" value="/UNFREEZE [nick]\rUnfreezes a user frozen by the /FREEZE command.">\r\r<helpop key="spylist" value="/SPYLIST\rOperates the same as /LIST but includes +s and +p channels.">\r\r<helpop key="spynames" value="/SPYNAMES [channel]\rOperates the same as /name but works on +s and +p channels.">\r\r<helpop key="globops" value="/GLOBOPS [message]\rSends a message to all +g users.">\r\r<helpop key="cban  " value="/CBAN [channel] {[duration] :[reason]}\rSets or removes a channel ban. You must specify at least\r3 parameters to add a ban, and one parameter to remove a ban.\rThe duration may be specified in seconds, or in the following format\r1y2w3d4h5m6s - meaning one year, two weeks, three days, 4 hours,\r5 minutes and 6 seconds. All fields in this format are optional.">\r\r<helpop key="sajoin" value="/SAJOIN [nick] [channel]\rForces the user to join the channel.">\r\r<helpop key="sapart" value="/SAPART [nick] [channel]\rForces the user to part the channel.">\r\r<helpop key="samode" value="/SAMODE [#chan/nick] +/-[modes] {[parameters for modes]}\rGives the channel or nick the modes specified.">\r\r<helpop key="sanick" value="/SANICK [nick] [new nick]\rChanges the users nick to the new nick.">\r\r<helpop key="saquit" value="/SAQUIT [nick] [reason]\rForces user to quit with the specified reason.">\r\r<helpop key="setidle" value="/SETIDLE [idle time]\rSets your idle time (in seconds).">\r\r<helpop key="sethost" value="/SETHOST [host]\rSets your host to the specified host.">\r\r<helpop key="setident" value="/SETIDENT [ident]\rSets your ident to the specified ident.">\r\r<helpop key="setname" value="/SETNAME [name]\rSets your name to the specified name.">\r\r<helpop key="swhois" line="/SWHOIS [nick] [swhois]\rSets the users swhois field to the given swhois.">\r\r<helpop key="mkpasswd" value="/MKPASSWD [hashtype] [plaintext]\rEncodes the plaintext to an MD5 hash and displays the result.">\r\r<helpop key="opermotd" value="/OPERMOTD\rRe-displays the Oper MOTD.">\r\r<helpop key="nicklock" value="/NICKLOCK [nick] [new nick]\rChanges user's nick to the new nick, and forces\rit to remain as such for the remainder of the session.">\r\r<helpop key="nickunlock" value="/NICKUNLOCK [nick]\rAllows the user to change nicks.">\r\r<helpop key="chghost" value="/CHGHOST [nickname] [new hostname]\rChanges the hostname of the user to the new hostname.">\r\r<helpop key="chgname" value="/CHGNAME [nickname] [new name]\rChanges the name of the user to the new name.">\r\r<helpop key="chgident" value="/CHGIDENT [nickname] [new ident]\rChanges the ident of the user to the new ident.">\r\r<helpop key="shun" value="/SHUN [user@host] {[duration] :[reason]}\rSets or removes a shun (serverside ignore) on a host and ident mask.\rYou must specify at least 3 parameters to add a shun, and one\rparameter to remove a shun (just the user@host section).\rThe duration may be specified in seconds, or in the following format\r1y2w3d4h5m6s - meaning one year, two weeks, three days, 4 hours,\r5 minutes and 6 seconds. All fields in this format are optional.">\r\r<helpop key="die" value="/DIE [password]\rIf the correct password is provided, and you are an operator,\rThis command will shut down the local server.">\r\r<helpop key="restart" value="/RESTART [password]\rIf the correct password is provided, and you are an operator,\rThis command will restart the local server.">\r\r<helpop key="commands" value="/COMMANDS\rShows all currently available commands.">\r\r<helpop key="kill" value="/KILL [user] [reason]\rThis command will disconnect a user from IRC with the given reason.">\r\r<helpop key="rehash" value="/REHASH\rThis command will cause the server configuration file to be\rre-read and values re-initialized.">\r\r<helpop key="trace" value="/TRACE [nick|user@host|servermask]\rThis command will provide a list of all users and servers which\rmust be passed through or over to reach a given object (server or user).">\r\r<helpop key="connect" value="/CONNECT [servermask]\rCreate a mesh connection to the given servermask. You must have\rconfigured the server for linking in your configuration file,\rand provided a password.">\r\r<helpop key="squit" value="/SQUIT\rDisconnects the local server from the mesh network, causing every\rother server in the network to drop it.">\r\r<helpop key="modules" value="/MODULES\rLists currently loaded modules, their memory offsets and version\rnumbers and flags. If you are not an operator, you will see reduced\rdetail.">\r\r<helpop key="loadmodule" value="/LOADMODULE [filename.so]\rLoads a module into the IRCd.">\r\r<helpop key="unloadmodule" value="/UNLOADMODULE [filename.so]\rUnloads a module from the IRCd. The module cannot have the static\rflag set (see the output of /MODULES).">\r\r<helpop key="gloadmodule" value="/GLOADMODULE [filename.so]\rGlobally loads a module into the network.">\r\r<helpop key="gunloadmodule" value="/GUNLOADMODULE [filename.so]\rGlobally unloads a module from the network. The module cannot \rhave the static flag set (see the output of /MODULES).">\r\r<helpop key="kline" value="/KLINE [user@host] {[duration] :[reason]}\rSets or removes a k-line (host based ban) on a host and ident mask.\rYou must specify at least 3 parameters to add a ban, and one\rparameter to remove a ban (just the user@host section).\rThe duration may be specified in seconds, or in the following format\r1y2w3d4h5m6s - meaning one year, two weeks, three days, 4 hours,\r5 minutes and 6 seconds. All fields in this format are optional.">\r\r<helpop key="zline" value="/ZLINE [ipmask] {[duration] :[reason]}\rSets or removes a z-line (ip based ban) on an ip range mask.\rYou must specify at least 3 parameters to add a ban, and one\rparameter to remove a ban (just the user@host section).\rThe duration may be specified in seconds, or in the following format\r1y2w3d4h5m6s - meaning one year, two weeks, three days, 4 hours,\r5 minutes and 6 seconds. All fields in this format are optional.">\r\r<helpop key="qline" value="/QLINE [nickmask] {[duration] :[reason]}\rSets or removes a q-line (nick based ban) on a nick mask.\rYou must specify at least 3 parameters to add a ban, and one\rparameter to remove a ban (just the user@host section).\rThe duration may be specified in seconds, or in the following format\r1y2w3d4h5m6s - meaning one year, two weeks, three days, 4 hours,\r5 minutes and 6 seconds. All fields in this format are optional.">\r\r<helpop key="gline" value="/GLINE [user@host] {[duration] :[reason]}\rSets or removes a g-line (global host based ban) on host mask.\rYou must specify at least 3 parameters to add a ban, and one\rparameter to remove a ban (just the user@host section).\rThe duration may be specified in seconds, or in the following format\r1y2w3d4h5m6s - meaning one year, two weeks, three days, 4 hours,\r5 minutes and 6 seconds. All fields in this format are optional.">\r\r<helpop key="eline" value="/ELINE [user@host] {[duration] :[reason]}\rSets or removes a e-line (local ban exception) on host mask.\rYou must specify at least 3 parameters to add an exception, and one\rparameter to remove an exception (just the user@host section).\rThe duration may be specified in seconds, or in the following format\r1y2w3d4h5m6s - meaning one year, two weeks, three days, 4 hours,\r5 minutes and 6 seconds. All fields in this format are optional.">\r\r######################\r# User/Channel Modes #\r######################\r\r<helpop key="umodes" value="User Modes\r----------\ro                Is an IRC operator\ri                Is invisible to /WHO\rw                Can receive wallops messages\rs                Can receive server notices\rn [mask]         Can receive server notices specified by [mask]\rx                Cloaked hostname (requires cloaking module)\rg                Can receive globops (requires globops module)\rh                Will receive helpops notification (requires helpop module)\rr                Nickname is registered\rR                Only registered users can PRIVMSG this nickname\rB                Is a bot\rG                Messages are censored to user\rW                Can see when a user uses WHOIS on them\rS                mIRC colour codes are stripped to the user\rD                User can not receive PRIVMSGs">\r\r<helpop key="chmodes" value="Channel Modes\r-------------\rv [nickname]       Gives voice to [nickname] (can talk on +m channel)\rh [nickname]       Gives halfops to [nickname]\ro [nickname]       Gives ops to [nickname]\rb [hostmask]       Bans [hostmask] on the channel\ra [nickname]       Give protected status to [nickname] (+q only)\rq [nickname]       Give founder status to [nickname] (ulines only)\ri                  Make the channel invite only, must /INVITE users\rk [key]            Set the channel key (password) to [key]\rl [limit]          Set the maximum possible users to [limit]\rm                  Enable moderation. Only +vo(h) can speak\rn                  Only users who are members of the channel may message it\rp                  Make channel private (hide from /LIST)\rs                  Make channel secret (can't be used at the same time as +p)\rO                  Channel is IRCops only (can only be set by IRCops)\rt                  Only halfops and above can change the topic\rQ                  Only U-Lined servers/nicks can kick\rT                  Only halfops/ops can send NOTICEs to the channel\rC                  No CTCPs allowed to the channel\rc                  mIRC colour codes blocked on the channel\rS                  mIRC colour codes are stripped from the channel\re [hostmask]       Ban exception on [hostmask]\rK                  No /KNOCK allowed to channel\rL [channel]        If the channel is full, redirect users to [channel]\rN                  No nick changes while on the channel\rG                  Censors channel based on network censor config\rg [word]           All messages containing the word are blocked\rI [hostmask]       Invite exception allows user to join a channel with +i\rj [joins]:[sec]    Prevents join flooding\rJ [seconds]        Prevents auto-rejoin on kick\rf [*][lines]:[sec] Kick on text flood. With * user is banned\rV                  No invites allowed\rr                  Channel is registered\rR                  Only registered users can join\rM                  Non-registered users can't chat\rz                  SSL clients only\rx                  Join exception mask. Avoids +ibkO\r-------------\rNOTE: A large number of these modes are dependent upon server-side modules\rbeing loaded by a server/network administrator. The actual modes available\ron your network may be very different to this list. Please consult your\rhelp channel if you have any questions.">\r\r######################\r#   Stats Symbols    #\r######################\r\r<helpop key="stats" value="/STATS [symbol]\rShows various server statistics. Depending on configuration this\rcommand may be reserved for oper-only use.\r-\rValid symbols are:\r-\rm  Show command statistics, number of times commands have been used\rz  Show memory usage statistics\ro  Show a list of all valid oper usernames and hostmasks\rl  Show all inbound and outbound server and client connections\ru  Show server uptime\rk  Show k-lines (local bans)\rg  Show g-lines (global bans)\rq  Show q-lines (nick mask bans)\rZ  Show z-lines (ip mask bans)\rY  Show connection classes\rC  Show link blocks\rU  Show u-lined servers\rP  Show online opers and their idle times\rI  Show connect class permissions\re  Show e-lines (local ban exemptions)\rC  Show channel bans\rs  Show filters\r-\rNote that all /STATS use is broadcast to online IRC operators.">\r\r
\ No newline at end of file
+#####################
+#  Helpop Standard  #
+#####################
+
+<helpop key="start" value="InspIRCd help system
+-
+This system provides help for commands and modes.
+Specify your question or a command name as the
+parameter for this command. If you are an oper
+you must prefix your query with a ? symbol.
+-
+/HELPOP COMMANDS      -      To see a list of user commands
+/HELPOP COPER         -      To see a list of oper commands
+/HELPOP UMODES        -      To see a list of user modes
+/HELPOP CHMODES       -      To see a list of channel modes">
+
+<helpop key="nohelp" value="There is no help for the topic
+you searched for. Please try again.">
+
+#####################
+#   User Commands   #
+#####################
+
+<helpop key="commands" value="User Commands
+-------------
+USER      NICK     QUIT     VERSION    PING
+PONG      ADMIN    PRIVMSG  INFO       TIME
+WHOIS     NOTICE   JOIN     NAMES      PART
+KICK      MODE     TOPIC    WHO        MOTD
+RULES     OPER     LIST     LUSERS     STATS
+USERHOST  AWAY     ISON     SUMMON     USERS
+INVITE    PASS     WHOWAS   LINKS      MAP
+COMMANDS  MODULES  KNOCK    SILENCE    DEVOICE
+REMOVE    UNINVITE VHOST    WATCH      USERIP">
+
+<helpop key="watch" value="/WATCH [C|S|+/-[NICK]]
+Adds or deletes a user from the watch list. C clears the list
+and S queries the status.">
+
+<helpop key="vhost" value="/VHOST [username] [password]
+Authenticate for a vhost.">
+
+<helpop key="kick" value="/REMOVE [channel] [nick] {[reason]}
+Removes a user from a channel you specify. You must be
+At least a channel halfoperator to remove a user.
+A removed user will part with a message stating they
+were removed from the channel and by whom.">
+
+<helpop key="devoice" value="/DEVOICE [channel]
+Devoices yourself from the specified channel.">
+
+<helpop key="silence" value="/SILENCE [+/-]<hostmask> [p|c|i|n|t|a|x]
+ p        Block private messages
+ c        Block channel messages
+ i        Block invites
+ n        Block private notices
+ t        Block channel notices
+ a        Block all of the above
+ x        Exception
+A serverside /ignore of the given hostmask.
+/SILENCE without a parameter will list the hostmasks that you have silenced.">
+
+<helpop key="knock" value="/KNOCK [channel]
+Sends a notice to a channel indicating you wish to join.">
+
+<helpop key="user" value="/USER [ident] [local host] [remote host] :[GECOS]
+This command is used by your client to register your irc session.
+You should not use it during an established connection.">
+
+<helpop key="nick" value="/NICK [new nick]
+Change your nickname to [new nick].">
+
+<helpop key="quit" value="/QUIT [reason]
+Quit from IRC and end your current session.">
+
+<helpop key="version" value="/VERSION
+Returns the server's version number.">
+
+<helpop key="ping" value="/PING [server]
+Ping a server. Target server will answer with a PONG.">
+
+<helpop key="pong" value="/PONG [server]
+Your client should send this to answer server PINGs. You
+should not issue this command manually.">
+
+<helpop key="admin" value="/ADMIN [server]
+Fetches the administrative information on the given server.">
+
+<helpop key="privmsg" value="/MSG [target] [text]
+Sends a message to a user or channel specified in [target].">
+
+<helpop key="notice" value="/NOTICE [target] [text]
+Sends a notice to a user or channel specified in [target].">
+
+<helpop key="join" value="/JOIN [channel]{,[channel]} [key]{,[key]}
+Joins one or more channels you provide the names for.">
+
+<helpop key="names" value="/NAMES [channel]{,[channel]}
+Return a list of users on the channels you provide.">
+
+<helpop key="part" value="/PART [channel]{,[channel] [reason]}
+Leaves one or more channels you specify.">
+
+<helpop key="kick" value="/KICK [channel] [nick] {[reason]}
+Kicks a user from a channel you specify. You must be
+At least a channel halfoperator to kick a user.">
+
+<helpop key="mode" value="/MODE [target] [+|-][modes]{[+|-][modes]} {mode parameters}
+Sets the mode for a channel or a nickname specified in [target]
+A user may only set modes upon themselves, and may not set the
++o usermode, and a user may only change channel modes of
+channels where they are at least a halfoperator.">
+
+<helpop key="topic" value="/TOPIC [channel] {topic}
+Sets or retrieves the channel topic. If a channel topic is
+given in the command and the channel is either not +t, or
+You are at least a halfoperator, the channel topic will be
+changed to the new one you provide.">
+
+<helpop key="who" value="/WHO [ [search-pattern] [ohurmaiMplf] ]
+Looks up the information of users matching the range you provide.
+You may only /WHO nicknames in channels or on servers where you
+share a common channel with them, or ones which are not +i (unless
+you are an IRC operator). The search-pattern may be a special
+sequence of characters determined by the flags given below, or
+it may be one of a nickname, a channel, a hostmask, an ip address
+mask or a server mask.
+-
+Valid WHO flags
+--------------- 
+The following flags after the mask have the following affects:
+-
+ o      Show online IRC operators matching the mask
+ u      Unlimit the results past the maximum /who results value
+        (IRC operators only)
+ r      Show all users whose realnames match the mask. When this
+        flag is set it overrides the meaning of the search-pattern,
+        which must contain a glob pattern intended to match GECOS
+        (realname) fields.
+ h      Show real hostnames rather than masked hostnames (IRC
+        operators only)
+ m      Search for all users with a given set of user modes. When
+        this flag is set it overrides the meaning of the
+        search-pattern, which must contain the mode sequence to
+        search for, for example to find all users with +i and
+        without +s, issue the command WHO +i-s m.
+ a      Show all users who have an away message matching the given mask
+ p      Show all users who are connected on the given port number
+ i      Show all users who have an ident (username) matching the given mask
+ M      Show all users who have metadata attached to them with
+        the given key name
+ l      Show only local users
+ f      Show only remote (far) users
+-
+You may combine multiple flags in one WHO command except where stated in the table above.">
+
+<helpop key="motd" value="/MOTD [server]
+Show the message of the day for [server]. Messages of the
+day contain important server rules and notice and should be
+read before using a server in any way!">
+
+<helpop key="rules" value="/RULES
+Show the rules file for the local server. This is similar in
+effect to /MOTD except that rules are optional. All users are
+sent the MOTD when they connect without having to request it.">
+
+<helpop key="oper" value="/OPER [login] [password]
+Attempts to authenticate a user as an IRC operator.
+Please be aware that both successful and unsuccessful oper attempts
+Are logged, and sent to online IRC operators.">
+
+<helpop key="list" value="/LIST [pattern]
+Creates a list of all existing channels matching the glob pattern
+[pattern], e.g. *chat* or bot*.">
+
+<helpop key="lusers" value="/LUSERS
+Shows a count of local and remote users, servers and channels.">
+
+<helpop key="userhost" value="/USERHOST [nickname]
+Returns the hostname and nickname of a user, and some other
+miscellaneous information.">
+
+<helpop key="userip" value="/USERIP [nickname]
+Returns the ip and nickname of a user.">
+
+<helpop key="away" value="/AWAY {message}
+If a message is given, marks you as being away, otherwise
+removes your away status and previous message.">
+
+<helpop key="ison" value="/ISON [nick] {[nick]...}
+Returns a subset of the nicks you give, showing only those
+that are currently online.">
+
+<helpop key="summon" value="/SUMMON [user]
+Summons a user from the shell where the ircd is running onto irc
+This command is deprecated in the current protocol.">
+
+<helpop key="users" value="/USERS
+Shows users logged into the shell where the ircd is running.
+This command is deprecated in the current protocol.">
+
+<helpop key="invite" value="/INVITE [nick] [channel]
+Invites a user to a channel. If the channel is NOT +i, any
+user, channel op or not, may invite any other user to the
+channel, so long as they are a member of that channel.
+Otherwise, if +i is set only channel halfoperators
+and above may invite users into the channel.">
+
+<helpop key="pass" value="/PASS [password]
+This command is used by your irc client when setting up
+your irc session, and should not be issued by a fully
+connected client.">
+
+<helpop key="whowas" value="/WHOWAS [nick]
+Returns a list of times the user was last seen on irc
+along with the time they were last seen and their server.">
+
+<helpop key="links" value="/LINKS
+Shows all servers linked to this one. Note that in this
+server implementation all links will be flattened as
+a tree based layout is not in use.">
+
+<helpop key="map" value="/MAP
+Shows a graphical representation of all users and servers
+on the network. The tree diagram is inaccurate in this
+implementation as a tree based network is not in place.">
+
+#####################
+#   Oper Commands   #
+#####################
+
+<helpop key="coper" value="Oper Commands
+-------------
+DIE        RESTART     KILL         REHASH         TRACE
+CONNECT    SQUIT       MODULES      MKPASSWD       SHUN
+KLINE      QLINE       GLINE        ELINE          ZLINE
+SAJOIN     SAPART      SAMODE       SAQUIT         SANICK
+SETIDLE    SETHOST     SETNAME      SETIDENT       SWHOIS
+OPERMOTD   CHGHOST     CHGNAME      CHGIDENT       CBAN
+NICKLOCK   NICKUNLOCK  LOADMODULE   UNLOADMODULE   GLOBOPS
+SPYLIST    SPYNAMES    GLOADMODULE  GUNLOADMODULE  MKSHA256
+FREEZE     UNFREEZE    OPERPERMS    RCONNECT">
+
+<helpop key="rconnect" value="/RCONNECT [source mask] [target mask]
+All servers matching [source mask] will try to connect to
+the first server in the config file matching [target mask].">
+
+<helpop key="operperms" value="/OPERPERMS [nick]
+List all commands an oper has access to use.">
+
+<helpop key="freeze" value="/FREEZE [nick]
+Prevents the user from sending commands until they reconnect.
+User is also notified they have been frozen.">
+
+<helpop key="unfreeze" value="/UNFREEZE [nick]
+Unfreezes a user frozen by the /FREEZE command.">
+
+<helpop key="spylist" value="/SPYLIST
+Operates the same as /LIST but includes +s and +p channels.">
+
+<helpop key="spynames" value="/SPYNAMES [channel]
+Operates the same as /name but works on +s and +p channels.">
+
+<helpop key="globops" value="/GLOBOPS [message]
+Sends a message to all +g users.">
+
+<helpop key="cban  " value="/CBAN [channel] {[duration] :[reason]}
+Sets or removes a channel ban. You must specify at least
+3 parameters to add a ban, and one parameter to remove a ban.
+The duration may be specified in seconds, or in the following format
+1y2w3d4h5m6s - meaning one year, two weeks, three days, 4 hours,
+5 minutes and 6 seconds. All fields in this format are optional.">
+
+<helpop key="sajoin" value="/SAJOIN [nick] [channel]
+Forces the user to join the channel.">
+
+<helpop key="sapart" value="/SAPART [nick] [channel]
+Forces the user to part the channel.">
+
+<helpop key="samode" value="/SAMODE [#chan/nick] +/-[modes] {[parameters for modes]}
+Gives the channel or nick the modes specified.">
+
+<helpop key="sanick" value="/SANICK [nick] [new nick]
+Changes the users nick to the new nick.">
+
+<helpop key="saquit" value="/SAQUIT [nick] [reason]
+Forces user to quit with the specified reason.">
+
+<helpop key="setidle" value="/SETIDLE [idle time]
+Sets your idle time (in seconds).">
+
+<helpop key="sethost" value="/SETHOST [host]
+Sets your host to the specified host.">
+
+<helpop key="setident" value="/SETIDENT [ident]
+Sets your ident to the specified ident.">
+
+<helpop key="setname" value="/SETNAME [name]
+Sets your name to the specified name.">
+
+<helpop key="swhois" line="/SWHOIS [nick] [swhois]
+Sets the users swhois field to the given swhois.">
+
+<helpop key="mkpasswd" value="/MKPASSWD [hashtype] [plaintext]
+Encodes the plaintext to an MD5 hash and displays the result.">
+
+<helpop key="opermotd" value="/OPERMOTD
+Re-displays the Oper MOTD.">
+
+<helpop key="nicklock" value="/NICKLOCK [nick] [new nick]
+Changes user's nick to the new nick, and forces
+it to remain as such for the remainder of the session.">
+
+<helpop key="nickunlock" value="/NICKUNLOCK [nick]
+Allows the user to change nicks.">
+
+<helpop key="chghost" value="/CHGHOST [nickname] [new hostname]
+Changes the hostname of the user to the new hostname.">
+
+<helpop key="chgname" value="/CHGNAME [nickname] [new name]
+Changes the name of the user to the new name.">
+
+<helpop key="chgident" value="/CHGIDENT [nickname] [new ident]
+Changes the ident of the user to the new ident.">
+
+<helpop key="shun" value="/SHUN [user@host] {[duration] :[reason]}
+Sets or removes a shun (serverside ignore) on a host and ident mask.
+You must specify at least 3 parameters to add a shun, and one
+parameter to remove a shun (just the user@host section).
+The duration may be specified in seconds, or in the following format
+1y2w3d4h5m6s - meaning one year, two weeks, three days, 4 hours,
+5 minutes and 6 seconds. All fields in this format are optional.">
+
+<helpop key="die" value="/DIE [password]
+If the correct password is provided, and you are an operator,
+This command will shut down the local server.">
+
+<helpop key="restart" value="/RESTART [password]
+If the correct password is provided, and you are an operator,
+This command will restart the local server.">
+
+<helpop key="commands" value="/COMMANDS
+Shows all currently available commands.">
+
+<helpop key="kill" value="/KILL [user] [reason]
+This command will disconnect a user from IRC with the given reason.">
+
+<helpop key="rehash" value="/REHASH
+This command will cause the server configuration file to be
+re-read and values re-initialized.">
+
+<helpop key="trace" value="/TRACE [nick|user@host|servermask]
+This command will provide a list of all users and servers which
+must be passed through or over to reach a given object (server or user).">
+
+<helpop key="connect" value="/CONNECT [servermask]
+Create a mesh connection to the given servermask. You must have
+configured the server for linking in your configuration file,
+and provided a password.">
+
+<helpop key="squit" value="/SQUIT
+Disconnects the local server from the mesh network, causing every
+other server in the network to drop it.">
+
+<helpop key="modules" value="/MODULES
+Lists currently loaded modules, their memory offsets and version
+numbers and flags. If you are not an operator, you will see reduced
+detail.">
+
+<helpop key="loadmodule" value="/LOADMODULE [filename.so]
+Loads a module into the IRCd.">
+
+<helpop key="unloadmodule" value="/UNLOADMODULE [filename.so]
+Unloads a module from the IRCd. The module cannot have the static
+flag set (see the output of /MODULES).">
+
+<helpop key="gloadmodule" value="/GLOADMODULE [filename.so]
+Globally loads a module into the network.">
+
+<helpop key="gunloadmodule" value="/GUNLOADMODULE [filename.so]
+Globally unloads a module from the network. The module cannot 
+have the static flag set (see the output of /MODULES).">
+
+<helpop key="kline" value="/KLINE [user@host] {[duration] :[reason]}
+Sets or removes a k-line (host based ban) on a host and ident mask.
+You must specify at least 3 parameters to add a ban, and one
+parameter to remove a ban (just the user@host section).
+The duration may be specified in seconds, or in the following format
+1y2w3d4h5m6s - meaning one year, two weeks, three days, 4 hours,
+5 minutes and 6 seconds. All fields in this format are optional.">
+
+<helpop key="zline" value="/ZLINE [ipmask] {[duration] :[reason]}
+Sets or removes a z-line (ip based ban) on an ip range mask.
+You must specify at least 3 parameters to add a ban, and one
+parameter to remove a ban (just the user@host section).
+The duration may be specified in seconds, or in the following format
+1y2w3d4h5m6s - meaning one year, two weeks, three days, 4 hours,
+5 minutes and 6 seconds. All fields in this format are optional.">
+
+<helpop key="qline" value="/QLINE [nickmask] {[duration] :[reason]}
+Sets or removes a q-line (nick based ban) on a nick mask.
+You must specify at least 3 parameters to add a ban, and one
+parameter to remove a ban (just the user@host section).
+The duration may be specified in seconds, or in the following format
+1y2w3d4h5m6s - meaning one year, two weeks, three days, 4 hours,
+5 minutes and 6 seconds. All fields in this format are optional.">
+
+<helpop key="gline" value="/GLINE [user@host] {[duration] :[reason]}
+Sets or removes a g-line (global host based ban) on host mask.
+You must specify at least 3 parameters to add a ban, and one
+parameter to remove a ban (just the user@host section).
+The duration may be specified in seconds, or in the following format
+1y2w3d4h5m6s - meaning one year, two weeks, three days, 4 hours,
+5 minutes and 6 seconds. All fields in this format are optional.">
+
+<helpop key="eline" value="/ELINE [user@host] {[duration] :[reason]}
+Sets or removes a e-line (local ban exception) on host mask.
+You must specify at least 3 parameters to add an exception, and one
+parameter to remove an exception (just the user@host section).
+The duration may be specified in seconds, or in the following format
+1y2w3d4h5m6s - meaning one year, two weeks, three days, 4 hours,
+5 minutes and 6 seconds. All fields in this format are optional.">
+
+######################
+# User/Channel Modes #
+######################
+
+<helpop key="umodes" value="User Modes
+----------
+o                Is an IRC operator
+i                Is invisible to /WHO
+w                Can receive wallops messages
+s                Can receive server notices
+n [mask]         Can receive server notices specified by [mask]
+x                Cloaked hostname (requires cloaking module)
+g                Can receive globops (requires globops module)
+h                Will receive helpops notification (requires helpop module)
+r                Nickname is registered
+R                Only registered users can PRIVMSG this nickname
+B                Is a bot
+G                Messages are censored to user
+W                Can see when a user uses WHOIS on them
+S                mIRC colour codes are stripped to the user
+D                User can not receive PRIVMSGs">
+
+<helpop key="chmodes" value="Channel Modes
+-------------
+v [nickname]       Gives voice to [nickname] (can talk on +m channel)
+h [nickname]       Gives halfops to [nickname]
+o [nickname]       Gives ops to [nickname]
+b [hostmask]       Bans [hostmask] on the channel
+a [nickname]       Give protected status to [nickname] (+q only)
+q [nickname]       Give founder status to [nickname] (ulines only)
+i                  Make the channel invite only, must /INVITE users
+k [key]            Set the channel key (password) to [key]
+l [limit]          Set the maximum possible users to [limit]
+m                  Enable moderation. Only +vo(h) can speak
+n                  Only users who are members of the channel may message it
+p                  Make channel private (hide from /LIST)
+s                  Make channel secret (can't be used at the same time as +p)
+O                  Channel is IRCops only (can only be set by IRCops)
+t                  Only halfops and above can change the topic
+Q                  Only U-Lined servers/nicks can kick
+T                  Only halfops/ops can send NOTICEs to the channel
+C                  No CTCPs allowed to the channel
+c                  mIRC colour codes blocked on the channel
+S                  mIRC colour codes are stripped from the channel
+e [hostmask]       Ban exception on [hostmask]
+K                  No /KNOCK allowed to channel
+L [channel]        If the channel is full, redirect users to [channel]
+N                  No nick changes while on the channel
+G                  Censors channel based on network censor config
+g [word]           All messages containing the word are blocked
+I [hostmask]       Invite exception allows user to join a channel with +i
+j [joins]:[sec]    Prevents join flooding
+J [seconds]        Prevents auto-rejoin on kick
+f [*][lines]:[sec] Kick on text flood. With * user is banned
+V                  No invites allowed
+r                  Channel is registered
+R                  Only registered users can join
+M                  Non-registered users can't chat
+z                  SSL clients only
+x                  Join exception mask. Avoids +ibkO
+-------------
+NOTE: A large number of these modes are dependent upon server-side modules
+being loaded by a server/network administrator. The actual modes available
+on your network may be very different to this list. Please consult your
+help channel if you have any questions.">
+
+######################
+#   Stats Symbols    #
+######################
+
+<helpop key="stats" value="/STATS [symbol]
+Shows various server statistics. Depending on configuration this
+command may be reserved for oper-only use.
+-
+Valid symbols are:
+-
+m  Show command statistics, number of times commands have been used
+z  Show memory usage statistics
+o  Show a list of all valid oper usernames and hostmasks
+l  Show all inbound and outbound server and client connections
+u  Show server uptime
+k  Show k-lines (local bans)
+g  Show g-lines (global bans)
+q  Show q-lines (nick mask bans)
+Z  Show z-lines (ip mask bans)
+Y  Show connection classes
+C  Show link blocks
+U  Show u-lined servers
+P  Show online opers and their idle times
+I  Show connect class permissions
+e  Show e-lines (local ban exemptions)
+C  Show channel bans
+s  Show filters
+-
+Note that all /STATS use is broadcast to online IRC operators.">
+
index 109a934a39debe1cea8fe1324fa5f027b17b228f..a02847ad04106c8bd1d27a85f12c0c405317461c 100644 (file)
@@ -1 +1,83 @@
-# Sample configuration file for m_helpop.so\r# You can either copy this into your conf folder and set up the module to use it,\r# or you can customize the responses for your network and/or add more.\r#\r# The way the new helpop system works is simple. You use one or more helpop tags.\r#   <helpop key="moo" value="something here">.\r# key is what the user is looking for (i.e. /helpop moo), and value is what they get back\r# (note that it can span multiple lines!).\r#   -- w00t 16/dec/2006\r#\r\r<helpop key="start" value="     InspIRCd help system\r     --------------------\r-\rThis system provides help for commands and modes.\rSpecify your question or a command name as the\rparameter for this command.\r-\r/HELPOP COMMANDS      -      To see a list of commands\r/HELPOP UMODES        -      To see a list of user modes\r/HELPOP CHMODES       -      To see a list of channel modes">\r\r<helpop key="nohelp" value="There is no help for the topic\rYou searched for. Please try again.">\r\r<helpop key="commands" value="User Commands\r-------------\rUSER     NICK    QUIT    VERSION     PING\rPONG     ADMIN   PRIVMSG INFO        TIME\rWHOIS    NOTICE  JOIN    NAMES       PART\rKICK     MODE    TOPIC   WHO         MOTD\rRULES    OPER    LIST    LUSERS      STATS\rUSERHOST AWAY    ISON    SUMMON      USERS\rINVITE   PASS    WHOWAS  LINKS       MAP\rCOMMANDS MODULES\r \rOper Commands\r-------------\rDIE      RESTART KILL    REHASH      TRACE\rCONNECT  SQUIT   MODULES KLINE       ZLINE\rQLINE    GLINE   ELINE">\r\r\r<helpop key="umodes" value="User Modes\r----------\ro                Is an IRC operator\ri                Is invisible to /WHO\rw                Can receive wallops messages\rs                Can receive server notices\rn [mask]         Can receive server notices specified by [mask], or * for all.\rx                Cloaked hostname (requires cloaking module)\rh                Will receive helpops notification (requires helpop module)">\r\r<helpop key="chmodes" value="Channel Modes\r-------------\rv [nickname]     Gives voice to [nickname] (can talk on +m channel)\rh [nickname]     Gives halfops to [nickname] (requires halfop module)\ro [nickname]     Gives ops to [nickname]\rb [hostmask]     Bans [hostmask] on the channel\ra [nickname]     Give protected status to [nickname] (+q only)\rq [nickname]     Give founder status to [nickname] (ulines only)\ri                Make the channel invite only, must /INVITE users\rk [key]          Set the channel key (password) to [key]\rl [limit]        Set the maximum possible users to [limit]\rm                Enable moderation. Only +vo(h) can speak\rn                Only users who are members of the channel may message it\rp                Make channel private (hide from /LIST)\rs                Make channel secret (can't be used at the same time as +p)\rO                Channel is IRCops only (can only be set by IRCops)\rt                Only halfops and above can change the topic\rQ                Only U-Lined servers/nicks can kick\rT                Only halfops/ops can send NOTICEs to the channel\rC                No CTCPs allowed to the channel\rc                mIRC colour codes blocked on the channel\rK                No /KNOCK allowed to channel (if knock module is loaded)\rL [channel]      If the channel is full, redirect users to [channel]\rN                No nickchanges while on the channel\r-------------\rNOTE: A large number of these modes are dependent upon server-side modules\rbeing loaded by a server/network administrator. The actual modes available\ron your network may be very different to this list. Please consult your\rhelp channel if you have any questions.">\r\r
\ No newline at end of file
+# Sample configuration file for m_helpop.so
+# You can either copy this into your conf folder and set up the module to use it,
+# or you can customize the responses for your network and/or add more.
+#
+# The way the new helpop system works is simple. You use one or more helpop tags.
+#   <helpop key="moo" value="something here">.
+# key is what the user is looking for (i.e. /helpop moo), and value is what they get back
+# (note that it can span multiple lines!).
+#   -- w00t 16/dec/2006
+#
+
+<helpop key="start" value="     InspIRCd help system
+     --------------------
+-
+This system provides help for commands and modes.
+Specify your question or a command name as the
+parameter for this command.
+-
+/HELPOP COMMANDS      -      To see a list of commands
+/HELPOP UMODES        -      To see a list of user modes
+/HELPOP CHMODES       -      To see a list of channel modes">
+
+<helpop key="nohelp" value="There is no help for the topic
+You searched for. Please try again.">
+
+<helpop key="commands" value="User Commands
+-------------
+USER     NICK    QUIT    VERSION     PING
+PONG     ADMIN   PRIVMSG INFO        TIME
+WHOIS    NOTICE  JOIN    NAMES       PART
+KICK     MODE    TOPIC   WHO         MOTD
+RULES    OPER    LIST    LUSERS      STATS
+USERHOST AWAY    ISON    SUMMON      USERS
+INVITE   PASS    WHOWAS  LINKS       MAP
+COMMANDS MODULES
+Oper Commands
+-------------
+DIE      RESTART KILL    REHASH      TRACE
+CONNECT  SQUIT   MODULES KLINE       ZLINE
+QLINE    GLINE   ELINE">
+
+
+<helpop key="umodes" value="User Modes
+----------
+o                Is an IRC operator
+i                Is invisible to /WHO
+w                Can receive wallops messages
+s                Can receive server notices
+n [mask]         Can receive server notices specified by [mask], or * for all.
+x                Cloaked hostname (requires cloaking module)
+h                Will receive helpops notification (requires helpop module)">
+
+<helpop key="chmodes" value="Channel Modes
+-------------
+v [nickname]     Gives voice to [nickname] (can talk on +m channel)
+h [nickname]     Gives halfops to [nickname] (requires halfop module)
+o [nickname]     Gives ops to [nickname]
+b [hostmask]     Bans [hostmask] on the channel
+a [nickname]     Give protected status to [nickname] (+q only)
+q [nickname]     Give founder status to [nickname] (ulines only)
+i                Make the channel invite only, must /INVITE users
+k [key]          Set the channel key (password) to [key]
+l [limit]        Set the maximum possible users to [limit]
+m                Enable moderation. Only +vo(h) can speak
+n                Only users who are members of the channel may message it
+p                Make channel private (hide from /LIST)
+s                Make channel secret (can't be used at the same time as +p)
+O                Channel is IRCops only (can only be set by IRCops)
+t                Only halfops and above can change the topic
+Q                Only U-Lined servers/nicks can kick
+T                Only halfops/ops can send NOTICEs to the channel
+C                No CTCPs allowed to the channel
+c                mIRC colour codes blocked on the channel
+K                No /KNOCK allowed to channel (if knock module is loaded)
+L [channel]      If the channel is full, redirect users to [channel]
+N                No nickchanges while on the channel
+-------------
+NOTE: A large number of these modes are dependent upon server-side modules
+being loaded by a server/network administrator. The actual modes available
+on your network may be very different to this list. Please consult your
+help channel if you have any questions.">
+
index 06f1e5d66cd7972697ec4035f6b862a916681c5e..6653792acb97034d5f8f617c33c1994026fe1693 100644 (file)
@@ -1 +1,40 @@
-\r _____                        _____   _____    _____      _\r|_   _|                      |_   _| |  __ \  / ____|    | |\r  | |    _ __    ___   _ __    | |   | |__) || |       __| |\r  | |   | '_ \  / __| | '_ \   | |   |  _  / | |      / _` |\r _| |_  | | | | \__ \ | |_) | _| |_  | | \ \ | |____ | (_| |\r|_____| |_| |_| |___/ | .__/ |_____| |_|  \_\ \_____| \__,_|\r    __________________| |_______________________________\r   |__________________|_|_______________________________|\r\r                        Putting the ricer in IRCer since 2007\r\r       //\ \r       V  \    WELCOME TO AN INSPIRCD NETWORK\r        \  \_    If you see this, I am probably new\r         \,'.`-.   If I'm not new, my owner is lazy.\r          |\ `. `. \r          ( \  `. `-.                        _,.-:\\r           \ \   `.  `-._             __..--' ,-';/\r            \ `.   `-.   `-..___..---'   _.--' ,'/\r             `. `.    `-._        __..--'    ,' /\r               `. `-_     ``--..''       _.-' ,'\r                 `-_ `-.___        __,--'   ,'\r                    `-.__  `----"""    __.-'\r                         `--..____..--'\r  \r        -- To change, see inspircd.motd.example --\r       /                                          \\r      /     * Web: http://www.inspircd.org         \\r      |     * Blog: http://www.inspircd.com        |\r      |     * IRC: irc.inspircd.org #inspircd      |\r      |     * Docs: http://www.inspircd.org/wiki   |\r      |                                            |\r      | We hope you like this software. Please do  |\r      | make  sure  you  put  some  effort  into   |\r      | your configuration though so you like it.  |\r      | Enjoy.                                     |\r      |                                            |\r      \                   -- The InspIRCd Team    /\r       -------------------------------------------
\ No newline at end of file
+
+ _____                        _____   _____    _____      _
+|_   _|                      |_   _| |  __ \  / ____|    | |
+  | |    _ __    ___   _ __    | |   | |__) || |       __| |
+  | |   | '_ \  / __| | '_ \   | |   |  _  / | |      / _` |
+ _| |_  | | | | \__ \ | |_) | _| |_  | | \ \ | |____ | (_| |
+|_____| |_| |_| |___/ | .__/ |_____| |_|  \_\ \_____| \__,_|
+    __________________| |_______________________________
+   |__________________|_|_______________________________|
+
+                        Putting the ricer in IRCer since 2007
+
+       //\ 
+       V  \    WELCOME TO AN INSPIRCD NETWORK
+        \  \_    If you see this, I am probably new
+         \,'.`-.   If I'm not new, my owner is lazy.
+          |\ `. `. 
+          ( \  `. `-.                        _,.-:\
+           \ \   `.  `-._             __..--' ,-';/
+            \ `.   `-.   `-..___..---'   _.--' ,'/
+             `. `.    `-._        __..--'    ,' /
+               `. `-_     ``--..''       _.-' ,'
+                 `-_ `-.___        __,--'   ,'
+                    `-.__  `----"""    __.-'
+                         `--..____..--'
+  
+        -- To change, see inspircd.motd.example --
+       /                                          \
+      /     * Web: http://www.inspircd.org         \
+      |     * Blog: http://www.inspircd.com        |
+      |     * IRC: irc.inspircd.org #inspircd      |
+      |     * Docs: http://www.inspircd.org/wiki   |
+      |                                            |
+      | We hope you like this software. Please do  |
+      | make  sure  you  put  some  effort  into   |
+      | your configuration though so you like it.  |
+      | Enjoy.                                     |
+      |                                            |
+      \                   -- The InspIRCd Team    /
+       -------------------------------------------
\ No newline at end of file
index 12ff74e4ba55bef3b42cb0c258e7b7291510327b..9b2bc0f6a6b809b0216e47a1878a0a0bed356b7c 100644 (file)
@@ -1 +1,175 @@
-Men are from Mars. Women are from Venus. Computers are from hell\rComputer /nm./: a device designed to speed and automate errors\rHardware /nm./: the part of the computer that you can kick.\rManiac /n./ An early computer built by nuts.\rRAM /abr./: Rarely Adequate Memory.\rProgrammer /n./ A red-eyed, mumbling mammal capable of conversing with inanimate objects\rMultitasking /adj./ 3 PCs and a chair with wheels\rPlonk /excl./: The sound a newbie makes as he falls to the bottom of a kill file\rhURL /n./: a link to a web site that makes you want to puke\rSUPERCOMPUTER: what it sounded like before you bought it.\rIf it's really a supercomputer, how come the bullets don't bounce off when I shoot it?  . The Covert Comic. \rA computer is like an Old Testament god, with a lot of rules and no mercy.  . Joseph Campbell\rI dropped my computer on my foot! That Megahurtz!!\rA computer's attention span is as long as it's power cord\r586: The average IQ needed to understand a PC\rMemory is like an orgasm. It's a lot better if you don't have to fake it\rIf it jams, force it. If it breaks, it needed replacing anyway.\rA bus station is where a bus stops. A train station is where a train stops. On my desk I have a workstation..\rWant to come see my HARD DRIVE ? I promise it isn't 3.5 inches and it ain't floppy.  . Geek pick-up line.\rIf you torture the data enough, it will confess.  . Ronald Coase\rIf you give someone a program, you will frustrate them for a day; if you teach them how to program, you will frustrate them for a lifetime\rASCII stupid question, get a stupid ANSI!\rUse the source, Luke...\rProgramming is an art form that fights back\rMacOS, Windows, BeOS: they're all just Xerox copies\rWhenever you think you have a clever programming trick... forget it!\rManaging senior programmers is like herding cats.  . Dave Platt\rYour program is sick ! Shoot it and put it out of its memory\r/* You are not expected to understand this */\rTo define recursion, we must first define recursion\rERROR: Computer possessed; Load EXOR.SYS ? [Y/N]\rLinux is only free if your time is worthless\rLinux: find out what you've been missing while you've been rebooting Windows NT\runzip; strip; touch; finger; mount; fsck; more; yes; unmount; sleep\rProfanity is the one language all programmers know best\rIt's 5.50 a.m.... Do you know where your stack pointer is?\r#define QUESTION ((bb) || !(bb))  . Shakespeare\rThe more I C, the less I see.\rConfucius say: He who play in root, eventually kill tree.\rUnix is the answer, but only if you phrase the question very carefully\rC++: Hard to learn and built to stay that way\rJava is, in many ways, C++--  . Michael Feldman.\rThey don't make bugs like Bunny anymore  . Olav Mjelde\rIf debugging is the process of removing software bugs, then programming must be the process of putting them in\rWhen the only tool you own is a hammer, every problem you encounter resembles a nail\rSystem Error: press F13 to continue...\rTo err is human, but for a real disaster you need a computer\rComputers make very fast, very accurate mistakes\rLife would be so much easier if we only had the source code\rWho is this 'General Failure' and why is he reading my disk?\rhAS aNYONE sEEN MY cAPSLOCK kEY?\rInspIRCd, now with excessive ammounts of Cheeze\rI'm in the computer business, I make Out-Of-Order signs\rKevorkian Virus: helps your computer shut down whenever it wants to.\r      [OUT OF QUOTES, PLEASE ORDER MORE]\rError, no keyboard . press F1 to continue.\rInsert Something Funkeh.. err.. There! -->\rCannot delete tmp150---3.tmp: There is not enough free disk space. Delete one or more files to free disk space, and then try again\rFile not found. Should I fake it ? (Y/N)\rThe definition of an upgrade: Take old bugs out, put new ones in\rIf it's not on fire, it's a software problem\rMy software never has bugs. It just develops random features\rIt's a little-known fact that the Y1K problem caused the Dark Ages\rArtificial Intelligence usually beats natural stupidity\rMaking fun of AOL users is like making fun of the kid in the wheel chair\rDaddy, why doesn't this magnet pick up this floppy disk?\rDaddy, what does FORMATTING DRIVE C mean?\rSee daddy ? All the keys are in alphabetical order now.\rIf you can't beat your computer at chess, do what I did . try kick-boxing.\rEnter any 11-digit prime number to continue...\rASCII and ye shall receive.\rThe web is a dominatrix. Every where I turn, I see little buttons ordering me to Submit.\r<FrostyCoolSlug> NO, You cannot dial 999, I'm downloading my mail ;/\r640K ought to be enough for anybody.  . Bill Gates, 1981\rWindows not found, [P]arty, [C]elebrate, [D]rink?\rEnglish, the Microsoft of languages...\rIt's been said that Bill Gates named his company after his dick...\rEver notice how fast Windows runs ?  -- Neither did I\rIf at first you don't succeed, work for Microsoft\rWe are Microsoft. Resistance Is Futile. You Will Be Assimilated\r"Microsoft Works."  . Oxymoron\rWindows isn't a virus, viruses do something\rPANIC! buffer = :NickServ WRITE_DB(3). <-- JUST KIDDING!\rIt just keeps going and going and going and going and goi <BANG>\rAll that I know is that nukes are comming from 127.0.0.1\rI know all about the irc and the mirc cops.\rM re ink n ed d, ple s  r fil\rPlease refrain from feeding the IRC Operators. Thank you.\rI know all about mirc stuff, hmm.. I think this channel is experiencing packet loss..\rMacDonalds claims Macintosh stole their next idea of the iMac\rI can't hold her any longer, captain, she's gonna bl.. sorry, got caught up in the moment\rI recommend purchasing a Cyrix CPU for testing nuclear meltdowns\rIs it an international rule to have the worst picture possible on your driver license?\rHave you hugged your services coder, today?\rEver wonder why they make the colon flash on alarm clocks?\rWhats this?.. blue screen with a VXD error?!.. I'VE BEEN NUKED!\rdo-do-bop-doo-doo-do-do-doo.. For those of you who know that song, you have problems..\rbe wery wery quiet... hunting wabbit...\rI've been IRC Nuked"Great warrior?  War does not make one great." - Yoda\r"I find your lack of faith.....disturbing." - Darth Vader\r"I have a bad feeling about this.."--All of the Star Wars characters.\rCan I upgrade my Hard Drive to a WARP drive?\rCanadian DOS prompt: EH?\>\rCanadian DOS: "Yer sure, eh?" [y/n]\rCONGRESS.SYS Corrupted: Re-boot Washington D.C (Y/n)?\rI don't have a solution but I admire the problem.\rFamous Last Words: Trust me. I know what I'm doing.\rHey Captain, I just created a black ho-÷p!%$û NO CARRIER\rI like work ... I can sit and watch it for hours.\rAccess denied--nah nah na nah nah!\rBad command. Bad, bad command! Sit! Stay! Staaay..\rError: Keyboard not attached. Press F1 to continue.\r*grumble* "You're just supposed to sit here?"\r"Hey, what's this button d..<BOOM>" -W. Crusher\r"He has become One with Himself!" "He's passed out!" "That too."-B5\rFor a funny quote, call back later.\rFamous last words: 'You saw a WHAT around the corner?!'\rI like work ... I can sit and watch it for hours.\rIf debugging is the process of removing bugs, then programming must be the process of putting them in.\rCopywight 1994 Elmer Fudd. All wights wesewved.\rCannot find REALITY.SYS. Universe halted.\rBUFFERS=20 FILES=15 2nd down, 4th quarter, 5 yards to go!\rMy software never has bugs. It just develops random features.\rWhy doesn't DOS ever say 'EXCELLENT command or filename!?\rWho's General Failure & why's he reading my disk?\rShell to DOS... Come in DOS, do you copy? Shell to DOS...\rComputing Definition - Network-Admin: Primary person who just got set up for the blame of the system crash.\rAn expert is a person who has made all the mistakes which can be made in a very narrow field.\rFamous last words: This is the safe way to do it.......\rFamous Last Words: Trust me. I know what I'm doing.\rClinton, "I didn't say that - er, well - yes, but I didn't mean..."\rCLINTON LEGACY??...even Pharaoh had only ten plagues...\rIBM             I Bought McIntosh\rIBM             I Bring Manuals\rIBM             I've Been Moved\rIBM             Idolized By Management\rIBM             Impenetrable Brain Matter\rIBM             Imperialism By Marketing\rIBM             Incorrigible Boisterous Mammoth\rIBM             Inertia Breeds Mediocrity\rIBM             Ingenuity Becomes Mysterious\rIBM             Ingrained Batch Mentality\rIBM             Innovation By Management\rIBM             Insipid Belligerent Mossbacks\rIBM             Insipidly Bankrolling Millions\rIBM             Inspect Before Multiusing\rIBM             Install Bigger Memory\rIBM             Institution By Machiavelli\rIBM             Insultingly Boring Merchandisers\rIBM             Intellectuals Being Moronized\rIBM             Intelligence Belittling Meaning\rIBM             Intimidated, Buffaloed Management\rIBM             Into Building Money\rIBM             Intolerant of Beards & Moustaches\rIBM             Invest Before Multi-tasking\rIBM             Investigate Baffling Malodor\rIBM             Irresponsible Behave Multinational\rIBM             It Beats Mattel\rIBM             It's a Big Mess\rIBM             It's Better Manually\rIBM             Itty Bitty Machine\rIBM             Institute for Black Magic\r100,000 lemmings can't be wrong.\rMurphy's Eighth Law: If everything seems to be going well, you have obviously overlooked something.\rRules of the game: Do not believe in miracles - rely on them.\rRules of the game: Any given program, once running, is obsolete.\rComputing Definition - Error: What someone else has made when they disagree with your computer output.\rBackup not found: (A)bort (R)etry (P)anic\rWinErr 653: Multitasking attempted - system confused.\rCannot join #real_life (invite only)\r"Unfortunatly, no one can be told what the Matrix is. You have to see it for yourself." - Matrix\r"Reality is a thing of the past" - Matrix\r"The future will not be user friendly" - Matrix\r"The general idea in chat is to make yourself understandable... ..." - Peer\r"heh i am talkin to someone...she not dead...yet anyways" - Stinky\r
\ No newline at end of file
+Men are from Mars. Women are from Venus. Computers are from hell
+Computer /nm./: a device designed to speed and automate errors
+Hardware /nm./: the part of the computer that you can kick.
+Maniac /n./ An early computer built by nuts.
+RAM /abr./: Rarely Adequate Memory.
+Programmer /n./ A red-eyed, mumbling mammal capable of conversing with inanimate objects
+Multitasking /adj./ 3 PCs and a chair with wheels
+Plonk /excl./: The sound a newbie makes as he falls to the bottom of a kill file
+hURL /n./: a link to a web site that makes you want to puke
+SUPERCOMPUTER: what it sounded like before you bought it.
+If it's really a supercomputer, how come the bullets don't bounce off when I shoot it?  . The Covert Comic. 
+A computer is like an Old Testament god, with a lot of rules and no mercy.  . Joseph Campbell
+I dropped my computer on my foot! That Megahurtz!!
+A computer's attention span is as long as it's power cord
+586: The average IQ needed to understand a PC
+Memory is like an orgasm. It's a lot better if you don't have to fake it
+If it jams, force it. If it breaks, it needed replacing anyway.
+A bus station is where a bus stops. A train station is where a train stops. On my desk I have a workstation..
+Want to come see my HARD DRIVE ? I promise it isn't 3.5 inches and it ain't floppy.  . Geek pick-up line.
+If you torture the data enough, it will confess.  . Ronald Coase
+If you give someone a program, you will frustrate them for a day; if you teach them how to program, you will frustrate them for a lifetime
+ASCII stupid question, get a stupid ANSI!
+Use the source, Luke...
+Programming is an art form that fights back
+MacOS, Windows, BeOS: they're all just Xerox copies
+Whenever you think you have a clever programming trick... forget it!
+Managing senior programmers is like herding cats.  . Dave Platt
+Your program is sick ! Shoot it and put it out of its memory
+/* You are not expected to understand this */
+To define recursion, we must first define recursion
+ERROR: Computer possessed; Load EXOR.SYS ? [Y/N]
+Linux is only free if your time is worthless
+Linux: find out what you've been missing while you've been rebooting Windows NT
+unzip; strip; touch; finger; mount; fsck; more; yes; unmount; sleep
+Profanity is the one language all programmers know best
+It's 5.50 a.m.... Do you know where your stack pointer is?
+#define QUESTION ((bb) || !(bb))  . Shakespeare
+The more I C, the less I see.
+Confucius say: He who play in root, eventually kill tree.
+Unix is the answer, but only if you phrase the question very carefully
+C++: Hard to learn and built to stay that way
+Java is, in many ways, C++--  . Michael Feldman.
+They don't make bugs like Bunny anymore  . Olav Mjelde
+If debugging is the process of removing software bugs, then programming must be the process of putting them in
+When the only tool you own is a hammer, every problem you encounter resembles a nail
+System Error: press F13 to continue...
+To err is human, but for a real disaster you need a computer
+Computers make very fast, very accurate mistakes
+Life would be so much easier if we only had the source code
+Who is this 'General Failure' and why is he reading my disk?
+hAS aNYONE sEEN MY cAPSLOCK kEY?
+InspIRCd, now with excessive ammounts of Cheeze
+I'm in the computer business, I make Out-Of-Order signs
+Kevorkian Virus: helps your computer shut down whenever it wants to.
+      [OUT OF QUOTES, PLEASE ORDER MORE]
+Error, no keyboard . press F1 to continue.
+Insert Something Funkeh.. err.. There! -->
+Cannot delete tmp150---3.tmp: There is not enough free disk space. Delete one or more files to free disk space, and then try again
+File not found. Should I fake it ? (Y/N)
+The definition of an upgrade: Take old bugs out, put new ones in
+If it's not on fire, it's a software problem
+My software never has bugs. It just develops random features
+It's a little-known fact that the Y1K problem caused the Dark Ages
+Artificial Intelligence usually beats natural stupidity
+Making fun of AOL users is like making fun of the kid in the wheel chair
+Daddy, why doesn't this magnet pick up this floppy disk?
+Daddy, what does FORMATTING DRIVE C mean?
+See daddy ? All the keys are in alphabetical order now.
+If you can't beat your computer at chess, do what I did . try kick-boxing.
+Enter any 11-digit prime number to continue...
+ASCII and ye shall receive.
+The web is a dominatrix. Every where I turn, I see little buttons ordering me to Submit.
+<FrostyCoolSlug> NO, You cannot dial 999, I'm downloading my mail ;/
+640K ought to be enough for anybody.  . Bill Gates, 1981
+Windows not found, [P]arty, [C]elebrate, [D]rink?
+English, the Microsoft of languages...
+It's been said that Bill Gates named his company after his dick...
+Ever notice how fast Windows runs ?  -- Neither did I
+If at first you don't succeed, work for Microsoft
+We are Microsoft. Resistance Is Futile. You Will Be Assimilated
+"Microsoft Works."  . Oxymoron
+Windows isn't a virus, viruses do something
+PANIC! buffer = :NickServ WRITE_DB(3). <-- JUST KIDDING!
+It just keeps going and going and going and going and goi <BANG>
+All that I know is that nukes are comming from 127.0.0.1
+I know all about the irc and the mirc cops.
+M re ink n ed d, ple s  r fil
+Please refrain from feeding the IRC Operators. Thank you.
+I know all about mirc stuff, hmm.. I think this channel is experiencing packet loss..
+MacDonalds claims Macintosh stole their next idea of the iMac
+I can't hold her any longer, captain, she's gonna bl.. sorry, got caught up in the moment
+I recommend purchasing a Cyrix CPU for testing nuclear meltdowns
+Is it an international rule to have the worst picture possible on your driver license?
+Have you hugged your services coder, today?
+Ever wonder why they make the colon flash on alarm clocks?
+Whats this?.. blue screen with a VXD error?!.. I'VE BEEN NUKED!
+do-do-bop-doo-doo-do-do-doo.. For those of you who know that song, you have problems..
+be wery wery quiet... hunting wabbit...
+I've been IRC Nuked"Great warrior?  War does not make one great." - Yoda
+"I find your lack of faith.....disturbing." - Darth Vader
+"I have a bad feeling about this.."--All of the Star Wars characters.
+Can I upgrade my Hard Drive to a WARP drive?
+Canadian DOS prompt: EH?\>
+Canadian DOS: "Yer sure, eh?" [y/n]
+CONGRESS.SYS Corrupted: Re-boot Washington D.C (Y/n)?
+I don't have a solution but I admire the problem.
+Famous Last Words: Trust me. I know what I'm doing.
+Hey Captain, I just created a black ho-÷p!%$û NO CARRIER
+I like work ... I can sit and watch it for hours.
+Access denied--nah nah na nah nah!
+Bad command. Bad, bad command! Sit! Stay! Staaay..
+Error: Keyboard not attached. Press F1 to continue.
+*grumble* "You're just supposed to sit here?"
+"Hey, what's this button d..<BOOM>" -W. Crusher
+"He has become One with Himself!" "He's passed out!" "That too."-B5
+For a funny quote, call back later.
+Famous last words: 'You saw a WHAT around the corner?!'
+I like work ... I can sit and watch it for hours.
+If debugging is the process of removing bugs, then programming must be the process of putting them in.
+Copywight 1994 Elmer Fudd. All wights wesewved.
+Cannot find REALITY.SYS. Universe halted.
+BUFFERS=20 FILES=15 2nd down, 4th quarter, 5 yards to go!
+My software never has bugs. It just develops random features.
+Why doesn't DOS ever say 'EXCELLENT command or filename!?
+Who's General Failure & why's he reading my disk?
+Shell to DOS... Come in DOS, do you copy? Shell to DOS...
+Computing Definition - Network-Admin: Primary person who just got set up for the blame of the system crash.
+An expert is a person who has made all the mistakes which can be made in a very narrow field.
+Famous last words: This is the safe way to do it.......
+Famous Last Words: Trust me. I know what I'm doing.
+Clinton, "I didn't say that - er, well - yes, but I didn't mean..."
+CLINTON LEGACY??...even Pharaoh had only ten plagues...
+IBM             I Bought McIntosh
+IBM             I Bring Manuals
+IBM             I've Been Moved
+IBM             Idolized By Management
+IBM             Impenetrable Brain Matter
+IBM             Imperialism By Marketing
+IBM             Incorrigible Boisterous Mammoth
+IBM             Inertia Breeds Mediocrity
+IBM             Ingenuity Becomes Mysterious
+IBM             Ingrained Batch Mentality
+IBM             Innovation By Management
+IBM             Insipid Belligerent Mossbacks
+IBM             Insipidly Bankrolling Millions
+IBM             Inspect Before Multiusing
+IBM             Install Bigger Memory
+IBM             Institution By Machiavelli
+IBM             Insultingly Boring Merchandisers
+IBM             Intellectuals Being Moronized
+IBM             Intelligence Belittling Meaning
+IBM             Intimidated, Buffaloed Management
+IBM             Into Building Money
+IBM             Intolerant of Beards & Moustaches
+IBM             Invest Before Multi-tasking
+IBM             Investigate Baffling Malodor
+IBM             Irresponsible Behave Multinational
+IBM             It Beats Mattel
+IBM             It's a Big Mess
+IBM             It's Better Manually
+IBM             Itty Bitty Machine
+IBM             Institute for Black Magic
+100,000 lemmings can't be wrong.
+Murphy's Eighth Law: If everything seems to be going well, you have obviously overlooked something.
+Rules of the game: Do not believe in miracles - rely on them.
+Rules of the game: Any given program, once running, is obsolete.
+Computing Definition - Error: What someone else has made when they disagree with your computer output.
+Backup not found: (A)bort (R)etry (P)anic
+WinErr 653: Multitasking attempted - system confused.
+Cannot join #real_life (invite only)
+"Unfortunatly, no one can be told what the Matrix is. You have to see it for yourself." - Matrix
+"Reality is a thing of the past" - Matrix
+"The future will not be user friendly" - Matrix
+"The general idea in chat is to make yourself understandable... ..." - Peer
+"heh i am talkin to someone...she not dead...yet anyways" - Stinky
index 100db84d077f3ef219fcf0e76d24394287f446e5..e51f0afd9cd50c25678c03f4366a5e4990c90c04 100644 (file)
@@ -1 +1,3 @@
-This is the InspIRCd rules file. \r \rPlace any network or server rules here :) \r
\ No newline at end of file
+This is the InspIRCd rules file. 
+Place any network or server rules here :) 
index 28cf979672b379bbbf12f852b6313237f27cd95a..0e9511b87bd7ac4abc7c60e49cae1d73c3d6a8fb 100755 (executable)
--- a/configure
+++ b/configure
@@ -1 +1,1802 @@
-#!/usr/bin/perl\r###################################################\r# InspIRCd Configuration Script\r#\r# Copyright 2002-2007 The InspIRCd Development Team\r#  http://www.inspircd.org/wiki/index.php/Credits\r#\r# Licensed under GPL, please see the COPYING file\r# for more information\r#\r# $Id$\r#\r###################################################\r\rrequire 5.6.0;\ruse Socket;\ruse Cwd;\ruse Getopt::Long;\r\r# Utility functions for our buildsystem\ruse make::utilities;\ruse make::configure;\ruse make::gnutlscert;\ruse make::opensslcert;\r\rGetOptions (\r    'enable-gnutls' => \$opt_use_gnutls,\r   'rebuild' => \$opt_rebuild,\r    'enable-openssl' => \$opt_use_openssl,\r 'disable-interactive' => \$opt_nointeractive,\r  'with-nick-length=i' => \$opt_nick_length,\r     'with-channel-length=i' => \$opt_chan_length,\r  'with-max-clients=i' => \$opt_maxclients,\r      'enable-ports' => \$opt_ports,\r 'enable-epoll' => \$opt_epoll,\r 'enable-kqueue' => \$opt_kqueue,\r       'disable-ports' => \$opt_noports,\r      'disable-epoll' => \$opt_noepoll,\r      'disable-kqueue' => \$opt_nokqueue,\r    'enable-ipv6' => \$opt_ipv6,\r   'enable-remote-ipv6' => \$opt_ipv6links,\r       'disable-remote-ipv6' => \$opt_noipv6links,\r    'with-cc=s' => \$opt_cc,\r       'with-ident-length=i' => \$opt_ident,\r  'with-quit-length=i' => \$opt_quit,\r    'with-topic-length=i' => \$opt_topic,\r  'with-maxbuf=i' => \$opt_maxbuf,\r       'with-kick-length=i' => \$opt_kick,\r    'with-gecos-length=i' => \$opt_gecos,\r  'with-away-length=i' => \$opt_away,\r    'with-max-modes=i' => \$opt_modes,\r     'prefix=s' => \$opt_base_dir,\r  'config-dir=s' => \$opt_config_dir,\r    'module-dir=s' => \$opt_module_dir,\r    'binary-dir=s' => \$opt_binary_dir,\r    'library-dir=s' => \$opt_library_dir,\r  'disable-debuginfo' => sub { $opt_disable_debug = 1 },\r 'help'  => sub { showhelp(); },\r        'modupdate' => sub { modupdate(); },\r   'update' => sub { update(); },\r 'svnupdate' => sub { svnupdate(); },\r   'clean' => sub { clean(); },\r);\r\rmy $non_interactive = (\r       (defined $opt_library_dir) ||\r  (defined $opt_base_dir) ||\r     (defined $opt_config_dir) ||\r   (defined $opt_module_dir) ||\r   (defined $opt_base_dir) ||\r     (defined $opt_binary_dir) ||\r   (defined $opt_nointeractive) ||\r        (defined $opt_away) ||\r (defined $opt_gecos) ||\r        (defined $opt_kick) ||\r (defined $opt_maxclients) ||\r   (defined $opt_modes) ||\r        (defined $opt_topic) ||\r        (defined $opt_quit) ||\r (defined $opt_ident) ||\r        (defined $opt_cc) ||\r   (defined $opt_ipv6) ||\r (defined $opt_ipv6links) ||\r    (defined $opt_noipv6links) ||\r  (defined $opt_kqueue) ||\r       (defined $opt_epoll) ||\r        (defined $opt_ports) ||\r        (defined $opt_maxchans) ||\r     (defined $opt_opermaxchans) ||\r (defined $opt_chan_length) ||\r  (defined $opt_nick_length) ||\r  (defined $opt_use_openssl) ||\r  (defined $opt_nokqueue) ||\r     (defined $opt_noepoll) ||\r      (defined $opt_noports) ||\r      (defined $opt_maxbuf) ||\r       (defined $opt_use_gnutls)\r);\rmy $interactive = !$non_interactive;\r\r\rchomp($topdir = getcwd());\r$this = resolve_directory($topdir);                                              # PWD, Regardless.\r@modlist = ();                                                                       # Declare for Module List..\r%config = ();                                                                       # Initiate Configuration Hash..\r$config{ME}              = resolve_directory($topdir);                          # Present Working Directory\r\r$config{BASE_DIR}     = $config{ME};\r\rif (defined $opt_base_dir)\r{\r        $config{BASE_DIR} = $opt_base_dir;\r}\r\r$config{CONFIG_DIR}        = resolve_directory($config{BASE_DIR}."/conf");        # Configuration Directory\r$config{MODULE_DIR}    = resolve_directory($config{BASE_DIR}."/modules");     # Modules Directory\r$config{BINARY_DIR}  = resolve_directory($config{BASE_DIR}."/bin");         # Binary Directory\r$config{LIBRARY_DIR} = resolve_directory($config{BASE_DIR}."/lib");          # Library Directory\r\rif (defined $opt_config_dir)\r{\r    $config{CONFIG_DIR} = $opt_config_dir;\r}\rif (defined $opt_module_dir)\r{\r        $config{MODULE_DIR} = $opt_module_dir;\r}\rif (defined $opt_binary_dir)\r{\r        $config{BINARY_DIR} = $opt_binary_dir;\r}\rif (defined $opt_library_dir)\r{\r       $config{LIBRARY_DIR} = $opt_library_dir;\r}\rchomp($config{HAS_GNUTLS}   = `libgnutls-config --version 2>/dev/null | cut -c 1,2,3`); # GNUTLS Version.\rchomp($config{HAS_OPENSSL}  = `pkg-config --modversion openssl 2>/dev/null`);              # Openssl version\rchomp($gnutls_ver = $config{HAS_GNUTLS});\rchomp($openssl_ver = $config{HAS_OPENSSL});\r$config{USE_GNUTLS}         = "n";\rif (defined $opt_use_gnutls)\r{\r      $config{USE_GNUTLS} = "y";                                      # Use gnutls.\r}\r$config{USE_OPENSSL}    = "n";                                          # Use openssl.\rif (defined $opt_use_openssl)\r{\r $config{USE_OPENSSL} = "y";\r}\r\r# no, let's not change these.\r$config{OPTIMITEMP}         = "0";                                         # Default Optimisation Value\rif (!defined $opt_disable_debug)\r{\r        $config{OPTIMISATI}      = "-g1";                               # Optimisation Flag\r}\relse\r{\r   $config{OPTIMISATI}      = "-O2";                               # DEBUGGING OFF!\r}\r\r$config{NICK_LENGT}  = "31";                                        # Default Nick Length\rif (defined $opt_nick_length)\r{\r  $config{NICK_LENGT} = $opt_nick_length;\r}\r$config{CHAN_LENGT}    = "64";                                        # Default Channel Name Length\rif (defined $opt_chan_length)\r{\r  $config{CHAN_LENGT} = $opt_chan_length;\r}\r$config{MAXI_MODES}    = "20";                                        # Default Max. Number of Modes set at once.\rif (defined $opt_modes)\r{\r  $config{MAXI_MODES} = $opt_modes;\r}\r$config{HAS_STRLCPY}        = "false";                                      # strlcpy Check.\r$config{HAS_STDINT}     = "false";                                     # stdint.h check\r$config{USE_KQUEUE}     = "y";                                         # kqueue enabled\rif (defined $opt_kqueue)\r{\r    $config{USE_KQUEUE} = "y";\r}\rif (defined $opt_nokqueue)\r{\r      $config{USE_KQUEUE} = "n";\r}\r$config{USE_EPOLL}   = "y";                                        # epoll enabled\rif (defined $opt_epoll)\r{\r      $config{USE_EPOLL} = "y";\r}\rif (defined $opt_noepoll)\r{\r        $config{USE_EPOLL} = "n";\r}\r$config{USE_PORTS}    = "y";                                        # epoll enabled\rif (defined $opt_ports)\r{\r      $config{USE_PORTS} = "y";\r}\rif (defined $opt_noports)\r{\r        $config{USE_PORTS} = "n";\r}\r$config{IPV6}              = "n";                                           # IPv6 support (experimental)\rif (defined $opt_ipv6)\r{\r $config{IPV6} = "y";\r}\r$config{SUPPORT_IP6LINKS}   = "y";                                       # IPv4 supporting IPv6 links (experimental)\rif (defined $opt_ipv6links)\r{\r      $config{SUPPORT_IP6LINKS} = "y";\r}\rif (defined $opt_noipv6links)\r{\r     $config{SUPPORT_IP6LINKS} = "n";\r}\r$config{STATIC_LINK}     = "no";                                     # are doing static modules?\rchomp($config{MAX_CLIENT_T} = `sh -c \"ulimit -n\"`);                       # FD Limit\rchomp($config{MAX_DESCRIPTORS} = `sh -c \"ulimit -n\"`);             # Hard FD Limit\rchomp($config{GCCVER}       = `g++ -dumpversion | cut -c 1`);           # Major GCC Version\r$config{_SOMAXCONN} = SOMAXCONN;                                    # Max connections in accept queue\r$config{OSNAME}                   = $^O;                                      # Operating System Name\r$config{IS_DARWIN}          = "NO";                                     # Is OSX?\r$config{STARTSCRIPT}          = "inspircd";                   # start script?\r$config{DESTINATION}          = "BASE";                         # Is target path.\r$config{EXTRA_DIR}          = "";                                             # Is empty.\rif ($config{OSNAME} =~ /darwin/i)\r{\r        $config{IS_DARWIN} = "YES";\r    $config{STARTSCRIPT}          = "org.inspircd.plist";           # start script for OSX.\r        $config{DESTINATION}          = "LAUNCHDPATH";                          # Is OSX target.\r       $config{EXTRA_DIR}            = " launchd_dir";                         # Is OSX specific path.\r}\r$config{CC}               = "g++";                                            # C++ compiler\rif (defined $opt_cc)\r{\r  $config{CC} = $opt_cc;\r}\r$exec = $config{CC} . " -dumpversion | cut -c 1";\rchomp($config{GCCVER}                = `$exec`);                             # Major GCC Version\r$config{MAKEORDER}          = "ircd mods";                          # build order\r$config{STATICLIBS}               = "";                                   # library archive path\r$config{MAX_IDENT}               = "12";                                 # max ident size\r$config{MAX_QUIT}              = "255";                                # max quit message size\r$config{MAX_TOPIC}              = "307";                                # max topic size\r$config{MAX_KICK}              = "255";                                # max kick message size\r$config{MAX_GECOS}              = "128";                                # max GECOS size\r$config{MAX_AWAY}              = "200";                                # max AWAY size\r$config{MAXBUF}                 = "512";                                # Max buffer size\rif (defined $opt_ident)\r{\r    $config{MAX_IDENT} = $opt_ident;\r}\rif (defined $opt_quit)\r{\r    $config{MAX_QUIT} = $opt_quit;\r}\rif (defined $opt_topic)\r{\r     $config{MAX_TOPIC} = $opt_topic;\r}\rif (defined $opt_kick)\r{\r    $config{MAX_KICK} = $opt_kick;\r}\rif (defined $opt_gecos)\r{\r     $config{MAX_GECOS} = $opt_gecos;\r}\rif (defined $opt_away)\r{\r    $config{MAX_AWAY} = $opt_away;\r}\r\r$config{HAS_OPENSSL} =~ /^([-[:digit:].]+)([a-z])?(\-[a-z][0-9])?$/;\r$config{HAS_OPENSSL} = $1;\r\rif ($config{GCCVER} eq "") {\r        print $config{CC} . " was not found! You require g++ (the GNU C++ compiler, part of GCC) to build InspIRCd!\n";\r        exit;\r}\r\r# Minihack! Convert Cygwin to 'Cyg-Static' so i can\r# Keep my dynamic module experiments here for later\r# consideration!\r\rif ($config{OSNAME} =~ /CYGWIN/i)\r{\r $config{OSNAME} = "CYG-STATIC";\r}\r\rif (!$config{MAX_CLIENT_T}) { \r      $config{MAX_CLIENT_T} = 1024;                            # Set a reasonable 'Default'\r  $fd_scan_fail = "true";                                # Used Later\r}\r\r# Get and Set some important vars..\rgetmodules();\r\rsub clean\r{\r  system("rm -rf .config.cache");\r}\r\rsub update\r{\r        eval {\r         chomp($topdir = getcwd());\r             $this = resolve_directory($topdir);                                          # PWD, Regardless.\r                getmodules();\r          # Does the cache file exist?\r           if (!getcache()) {\r                     # No, No it doesn't.. *BASH*\r                   print "You have not run ./configure before. Please do this before trying to run the update script.\n";\r                 exit 0;\r                } else {\r                       # We've Loaded the cache file and all our variables..\r                  print "Updating Files..\n";\r                    getosflags();\r                  if ($opt_disable_debug == 1)\r                   {\r                              print "Disabling debug information (-g).\n";\r                           $config{OPTIMISATI} = "";\r                              getosflags();\r                  }\r                      $has_epoll = $config{HAS_EPOLL};\r                       $has_ports = $config{HAS_PORTS};\r                       $has_kqueue = $config{HAS_KQUEUE};\r                     writefiles(1);\r                 makecache();\r                   print "Complete.\n";\r                   exit;\r          }\r      };\r     if ($@)\r        {\r              print "Configure update failed: $@\n";\r }\r      exit;\r}\r\rsub modupdate\r{\r       eval {\r         chomp($topdir = getcwd());\r             $this = resolve_directory($topdir);                                          # PWD, Regardless.\r                getmodules();\r          # Does the cache file exist?\r           if (!getcache()) {\r                     # No, No it doesn't.. *BASH*\r                   print "You have not run ./configure before. Please do this before trying to run the update script.\n";\r                 exit 0;\r                } else {\r                       # We've Loaded the cache file and all our variables..\r                  print "Updating Files..\n";\r                    getosflags();\r                  $has_epoll = $config{HAS_EPOLL};\r                       $has_ports = $config{HAS_PORTS};\r                       $has_kqueue = $config{HAS_KQUEUE};\r                     writefiles(0);\r                 makecache();\r                   print "Complete.\n";\r                   exit;\r          }\r      };\r     if ($@)\r        {\r              print "Module update failed: $@\n";\r    }\r      exit;\r}\r\r\r\rsub svnupdate\r{\r     my $fail = 0;\r  open(FH,"<.svn/entries") or $fail = 1;\r if ($fail) {\r           print "This is not an SVN copy of InspIRCd.\n";\r                exit;\r  }\r      else\r   {\r              close(FH);\r     }\r      system("svn update");\r  system("perl configure -update");\r      if (defined $opt_rebuild) {\r            system("make install");\r        }\r      exit;\r}\r\rprint "Running non-interactive configure...\n" unless $interactive;\rprint "Checking for cache from previous configure... ";\rprint ((getcache() eq "true") ? "found\n" : "not found\n");\rprint "Checking operating system version... ";\rprint getosflags() . "\n";\r\rif (defined $opt_maxclients)\r{\r     $config{MAX_CLIENT} = $opt_maxclients;\r}\r\rif (!$config{MAX_CLIENT}) { \r # If the cache hasn't set the max clients, copy the variable of MAX_CLIENT_T, this\r     # allows us to keep _T for testing purposes. (ie. "Are you sure you want to go\r # higher than the found value" :))\r     $config{MAX_CLIENT} = $config{MAX_CLIENT_T};\r}\r\rprintf "Checking if stdint.h exists... ";\r$config{HAS_STDINT} = "true";\rmy $fail = 0;\ropen(STDINT, "</usr/include/stdint.h") or $config{HAS_STDINT} = "false";\rif ($config{HAS_STDINT} eq "true") {\r    close(STDINT);\r}\rprint "yes\n" if $config{HAS_STDINT} eq "true";\rprint "no\n" if $config{HAS_STDINT} eq "false";\r\r\rprintf "Checking if strlcpy exists... ";\r# Perform the strlcpy() test..\r$config{HAS_STRLCPY} = "false";\rmy $fail = 0;\ropen(STRLCPY, "</usr/include/string.h") or $fail = 1;\rif (!$fail) {\r   while (chomp($line = <STRLCPY>)) {\r             # try and find the delcaration of:\r             # size_t strlcpy(...)\r          if ($line =~ /size_t(\0x9|\s)+strlcpy/) {\r                      $config{HAS_STRLCPY} = "true";\r         }\r      }\r      close(STRLCPY);\r}\rprint "yes\n" if $config{HAS_STRLCPY} eq "true";\rprint "no\n" if $config{HAS_STRLCPY} eq "false";\r\r\rprintf "Checking if kqueue exists... ";\r$has_kqueue = 0;\r$fail = 0;\ropen(KQUEUE, "</usr/include/sys/event.h") or $fail = 1;\rif (!$fail) {\r        while (chomp($line = <KQUEUE>)) {\r              # try and find the delcaration of:\r             # int kqueue(void);\r            if ($line =~ /int(\0x9|\s)+kqueue/) {\r                  $has_kqueue = 1;\r               }\r      }\r      close(KQUEUE);\r}\rprint "yes\n" if $has_kqueue == 1;\rprint "no\n" if $has_kqueue == 0;\r\rprintf "Checking if epoll exists... ";\r$has_epoll = 0;\r$fail = 0;\ropen(EPOLL, "</usr/include/sys/epoll.h") or $fail = 1;\rif (!$fail) {\r  $has_epoll = 1;\r        close(EPOLL);\r}\rif ($has_epoll) {\r      my $kernel = `uname -r`;\r       chomp($kernel);\r        if (($kernel =~ /^2\.0\./) || ($kernel =~ /^2\.2\./) || ($kernel =~ /^2\.4\./)) {\r              $has_epoll = 0;\r        }\r}\rprint "yes\n" if $has_epoll == 1;\rprint "no\n" if $has_epoll == 0;\r\rprintf "Checking if Solaris I/O completion ports are available... ";\r$has_ports = 0;\rmy $system = `uname -s`;\rchomp ($system);\r$has_ports = 1 if ($system eq "SunOS");\r\rif ($has_ports) {\r      my $kernel = `uname -r`;\r       chomp($kernel);\r        if (($kernel !~ /^5\.1./)) {\r           $has_ports = 0;\r        }\r}\rprint "yes\n" if $has_ports == 1;\rprint "no\n" if $has_ports == 0;\r\rif (($config{OSNAME} =~ /CYGWIN/) || ($config{OSNAME} eq "CYG-STATIC")) {\r      $config{HAS_STRLCPY} = "true";\r}\r\r$config{HAS_EPOLL} = $has_epoll;\r$config{HAS_KQUEUE} = $has_kqueue; \r\rprintf "Checking for libgnutls... ";\rif (($config{HAS_GNUTLS}) && (($config{HAS_GNUTLS} >= 1.2) || ($config{HAS_GNUTLS} eq "y"))) {\r    print "yes\n";\r $config{HAS_GNUTLS} = "y";\r} else {\r    print "no\n";\r  $config{HAS_GNUTLS} = "n";\r}\r\rprintf "Checking for openssl... ";\rif (($config{HAS_OPENSSL}) && (($config{HAS_OPENSSL} >= 0.8) || ($config{HAS_OPENSSL} eq "y"))) {\r     print "yes\n";\r $config{HAS_OPENSSL} = "y";\r} else {\r   print "no\n";\r  $config{HAS_OPENSSL} = "n";\r}\r\r################################################################################\r#                         BEGIN INTERACTIVE PART                              #\r################################################################################\r\r# Clear the Screen..\rif ($interactive)\r{\r     system("clear");\r       $wholeos = $^O;\r\r       my $rev = getrevision();\r       # Display Introduction Message..\r       print "\rWelcome to the \033[1mInspIRCd\033[0m Configuration program! (\033[1minteractive mode\033[0m)\r\033[1mPackage maintainers: Type ./configure --help for non-interactive help\033[0m\r\r*** If you are unsure of any of these values, leave it blank for    ***\r*** standard settings that will work, and your server will run      ***\r*** using them. Please consult your IRC network admin if in doubt.  ***\r\rPress \033[1m<RETURN>\033[0m to accept the default for any option, or enter\ra new value. Please note: You will \033[1mHAVE\033[0m to read the docs\rdir, otherwise you won't have a config file!\r\rYour operating system is: \033[1;32m$config{OSNAME}\033[0m ($wholeos)\rMaximum file descriptors: \033[1;32m$config{MAX_CLIENT_T}\033[0m\rYour InspIRCd revision ID is \033[1;32mr$rev\033[0m";\r      if ($rev eq "r0") {\r            print " (Non-SVN build)";\r      }\r      print ".\n\n";\r\r        $config{CHANGE_COMPILER} = "n";\r        print "I have detected the following compiler: \033[1;32m$config{CC}\033[0m (version \033[1;32m$config{GCCVER}.x\033[0m)\n";\r\r  while (($config{GCCVER} < 3) || ($config{GCCVER} eq "")) {\r             print "\033[1;32mIMPORTANT!\033[0m A GCC 2.x compiler has been detected, and\rshould NOT be used. You should probably specify a newer compiler.\n\n";\r           yesno(CHANGE_COMPILER,"Do you want to change the compiler?");\r          if ($config{CHANGE_COMPILER} =~ /y/i) {\r                        print "What command do you want to use to invoke your compiler?\n";\r                    print "[\033[1;32m$config{CC}\033[0m] -> ";\r                    chomp($config{CC} = <STDIN>);\r                  if ($config{CC} eq "") {\r                               $config{CC} = "g++";\r                   }\r                      chomp($foo = `$config{CC} -dumpversion | cut -c 1`);\r                   if ($foo ne "") {\r                              chomp($config{GCCVER}       = `$config{CC} -dumpversion | cut -c 1`); # we must redo these if we change compilers\r                              print "Queried compiler: \033[1;32m$config{CC}\033[0m (version \033[1;32m$config{GCCVER}.x\033[0m)\n";\r                         if ($config{GCCVER} < 3) {\r                                     print "\033[1;32mGCC 2.x WILL NOT WORK!\033[0m. Let's try that again, shall we?\n";\r                            }\r                      }\r                      else {\r                         print "\033[1;32mWARNING!\033[0m Could not execute the compiler you specified. You may want to try again.\n";\r                  }\r              }\r      }\r\r     print "\n";\r\r   # Directory Settings..\r my $tmpbase = $config{BASE_DIR};\r       dir_check("do you wish to install the InspIRCd base", "BASE_DIR");\r     if ($tmpbase ne $config{BASE_DIR}) {\r           $config{CONFIG_DIR}      = resolve_directory($config{BASE_DIR}."/conf");           # Configuration Dir\r         $config{MODULE_DIR}      = resolve_directory($config{BASE_DIR}."/modules");     # Modules Directory\r            $config{BINARY_DIR}      = resolve_directory($config{BASE_DIR}."/bin");     # Binary Directory\r         $config{LIBRARY_DIR}    = resolve_directory($config{BASE_DIR}."/lib");      # Library Directory\r        }\r\r     dir_check("are the configuration files", "CONFIG_DIR");\r        dir_check("are the modules to be compiled to", "MODULE_DIR");\r  dir_check("is the IRCd binary to be placed", "BINARY_DIR");\r    dir_check("are the IRCd libraries to be placed", "LIBRARY_DIR");\r\r      if ($has_kqueue) {\r             yesno(USE_KQUEUE,"You are running a BSD operating system, and kqueue\nwas detected. Would you like to enable kqueue support?\nThis is likely to increase performance.\nIf you are unsure, answer yes.\n\nEnable kqueue?");\r             print "\n";\r    }\r      if ($has_epoll) {\r              yesno(USE_EPOLL,"You are running a Linux 2.6+ operating system, and epoll\nwas detected. Would you like to enable epoll support?\nThis is likely to increase performance.\nIf you are unsure, answer yes.\n\nEnable epoll?");\r          print "\n";\r    }\r      if ($has_ports) {\r              yesno(USE_PORTS,"You are running Solaris 10.\nWould you like to enable I/O completion ports support?\nThis is likely to increase performance.\nIf you are unsure, answer yes.\n\nEnable support for I/O completion ports?");\r           print "\n";\r    }\r      $chose_hiperf = (($config{USE_EPOLL} eq "y") || ($config{USE_KQUEUE} eq "y") || ($config{USE_PORTS} eq "y"));\r  if (!$chose_hiperf) {\r          print "No high-performance socket engines are available, or you chose\n";\r              print "not to enable one. Defaulting to select() engine.\n\n";\r }\r\r     yesno(IPV6,"Would you like to build InspIRCd with IPv6 support?");\r     print "\n";\r\r   if ($config{IPV6} eq "y") {\r            print "You have chosen to build an \033[1;32mIPV6-enabled\033[0m server.\nTo accept IPV4 users, you can still use IPV4 addresses\nin your port bindings..\n\n";\r                $config{SUPPORT_IP6LINKS} = "y";\r       } else {\r               yesno(SUPPORT_IP6LINKS,"You have chosen to build an \033[1;32mIPV4-only\033[0m server.\nWould you like to enable support for linking to IPV6-enabled\nInspIRCd servers?\nIf you are using a recent operating\nsystem and are unsure, answer yes.\nIf you answer 'no' here, your InspIRCd server will be unable\nto parse IPV6 addresses (e.g. for CIDR bans)");\r                print "\n";\r    }\r\r     if (($config{HAS_GNUTLS} eq "y") && ($config{HAS_OPENSSL} eq "y")) {\r           print "I have detected both \033[1;32mGnuTLS\033[0m and \033[1;32mOpenSSL\033[0m on your system.\n";\r           print "I will default to GnuTLS. If you wish to use OpenSSL\n";\r                print "instead, you should enable the OpenSSL module yourself\n";\r              print "by copying it from src/modules/extra to src/modules.\n\n";\r              print "Detected GnuTLS version: \033[1;32m" . $gnutls_ver . "\033[0m\n";\r               print "Detected OpenSSL version: \033[1;32m" . $openssl_ver . "\033[0m\n\n";\r   }\r\r     if ($config{HAS_GNUTLS} eq "y") {\r              yesno(USE_GNUTLS, "Would you like to enable SSL Support?");\r            if ($config{USE_GNUTLS} eq "y") {\r                      print "\nUsing GnuTLS SSL module.\n";\r          }\r      } elsif ($config{HAS_OPENSSL} eq "y") {\r                        yesno(USE_OPENSSL, "Would you like to enable SSL Support?");\r   if ($config{USE_OPENSSL} eq "y") {\r                     print "\nUsing OpenSSL SSL module.\nYou will get better performance if you move to GnuTLS in the future.\n";\r           }\r      }\r      else {\r         print "\nCould not detect OpenSSL or GnuTLS. Make sure pkg-config is installed if\nyou intend to use OpenSSL, or that GnuTLS is in your path if you intend\nto use GnuTLS.\n\n";\r       }\r\r     print "\nThe following questions will ask you for various figures relating\n";\r print "To your IRCd install. Please note that these should usually be left\n";\r print "as defaults unless you have a real reason to change them. If they\n";\r   print "changed, then the values must be identical on all servers on your\n";\r   print "network, or malfunctions and/or crashes may occur, with the exception\n";\r       print "of the 'maximum number of clients' setting which may be different on\n";\r        print "different servers on the network.\n\n";\r\r        # File Descriptor Settings..\r   promptnumeric("number of clients at any one time", "MAX_CLIENT_T");\r    $config{MAX_CLIENT} = $config{MAX_CLIENT_T};\r   $config{MAX_DESCRIPTORS} = $config{MAX_CLIENT_T};\r\r     promptnumeric("length of nicknames", "NICK_LENGT");\r    promptnumeric("length of channel names", "CHAN_LENGT");\r        promptnumeric("number of mode changes in one line", "MAXI_MODES");\r     promptnumeric("length of an ident (username)", "MAX_IDENT");\r   promptnumeric("length of a quit message", "MAX_QUIT");\r promptnumeric("length of a channel topic", "MAX_TOPIC");\r       promptnumeric("length of a kick message", "MAX_KICK");\r promptnumeric("length of a GECOS (real name)", "MAX_GECOS");\r   promptnumeric("length of an away message", "MAX_AWAY");\r}\r\rdumphash();\r\rif (($config{USE_GNUTLS} eq "y") && ($config{HAS_GNUTLS} ne "y"))\r{\r    print "Sorry, but i couldn't detect gnutls. Make sure gnutls-config is in your path.\n";\r       exit(0);\r}\rif (($config{USE_OPENSSL} eq "y") && ($config{HAS_OPENSSL} ne "y"))\r{\r       print "Sorry, but i couldn't detect openssl. Make sure openssl is in your path.\n";\r    exit(0);\r}\r\rif ($config{USE_GNUTLS} eq "y") {\r  $failed = 0;\r   open(TMP, "<src/modules/m_ssl_gnutls.cpp") or $failed = 1;\r     close(TMP);\r    if ($failed) {\r         print "Symlinking src/modules/m_ssl_gnutls.cpp from extra/\n";\r         chdir("src/modules");\r          system("ln -s extra/m_ssl_gnutls.cpp");\r                chdir("../..");\r        }\r      getmodules();\r  if ($interactive)\r      {\r              $failed = 0;\r           open(TMP, "<$config{CONFIG_DIR}/key.pem") or $failed = 1;\r              close(TMP);\r            open(TMP, "<$config{CONFIG_DIR}/cert.pem") or $failed = 1;\r             close(TMP);\r            if ($failed) {\r                 print "SSL Certificates Not found, Generating.. \n\n\r*************************************************************\r* Generating the Private Key may take some time, go grab a  *\r* Coffee. Even better, to generate some more entropy if it  *\r* is taking a while, open another console and type du / a   *\r* few times and get that HD going :) Then answer the        *\r* Questions which follow. If you are unsure, just hit enter *\r*************************************************************\n\n";\r                   make_gnutls_cert() or $failed = 1;\r                     if (!$failed) {\r                                print "\nCertificate generation complete, copying to config directory... ";\r                            system("mv key.pem $config{CONFIG_DIR}/key.pem");\r                              system("mv cert.pem $config{CONFIG_DIR}/cert.pem");\r                            print "Done.\n\n";\r                     } else {\r                               print "\n\033[1;32mCertificate generation failed!\033[0m\n\n";\r                 }\r              }\r              else {\r                 print "SSL Certificates found, skipping.\n\n";\r         }\r      }\r      else\r   {\r              print "Skipping SSL certificate generation\nin non-interactive mode.\n\n";\r     }\r} elsif ($config{USE_OPENSSL} eq "y") {\r      $failed = 0;\r   open(TMP, "<src/modules/m_ssl_openssl.cpp") or $failed = 1;\r    close(TMP);\r    if ($failed) {\r         print "Symlinking src/modules/m_ssl_openssl.cpp from extra/\n";\r                chdir("src/modules");\r          system("ln -s extra/m_ssl_openssl.cpp");\r               chdir("../..");\r        }\r      getmodules();\r  $failed = 0;\r   if ($interactive)\r      {\r              open(TMP, "<$config{CONFIG_DIR}/key.pem") or $failed = 1;\r              close(TMP);\r            open(TMP, "<$config{CONFIG_DIR}/cert.pem") or $failed = 1;\r             close(TMP);\r            if ($failed) {\r                 print "SSL Certificates Not found, Generating.. \n\n\r*************************************************************\r* Generating the certificates may take some time, go grab a *\r* coffee, or something.                                     *\r*************************************************************\n\n";\r                     make_openssl_cert();\r                   print "\nCertificate generation complete, copying to config directory... ";\r                    system("mv key.pem $config{CONFIG_DIR}/key.pem");\r                      system("mv cert.pem $config{CONFIG_DIR}/cert.pem");\r                    system("mv dhparams.pem $config{CONFIG_DIR}/dhparams.pem");\r                    print "Done.\n\n";\r             } else {\r                       print "SSL Certificates found, skipping.\n\n"\r          }\r      }\r      else\r   {\r              print "Skipping SSL certificate generation\nin non-interactive mode.\n\n";\r     }\r}\rif (($config{USE_GNUTLS} eq "n") && ($config{USE_OPENSSL} eq "n")) {\r       print "Skipping SSL Certificate generation, SSL support is not available.\n\n";\r}\r\rgetosflags();\rwritefiles(1);\rmakecache();\r\rprint "\n\n";\rprint "To build your server with these settings, please type '\033[1;32m$config{MAKEPROG}\033[0m' now.\n";\rif (($config{USE_GNUTLS} eq "y") || ($config{USE_OPENSSL} eq "y")) {\r    print "Please remember that to enable \033[1;32mSSL support\033[0m you must\n";\r        print "load the required modules in your config. This configure process\n";\r    print "has just prepared these modules to be compiled for you, and has not\n";\r print "configured them to be compiled into the core of the ircd.\n";\r}\rprint "*** \033[1;32mRemember to edit your configuration files!!!\033[0m ***\n\n\n";\rif (($config{OSNAME} eq "OpenBSD") && ($config{CC} ne "eg++")) {\r   print "\033[1;32mWARNING!\033[0m You are running OpenBSD but you are using the base gcc package\nrather than eg++. This compile will most likely fail, but i'm letting you\ngo ahead with it anyway, just in case i'm wrong :-)\n";\r}\r\rif ($config{GCCVER} < "3") {\r    print <<FOO2;\r\033[1;32mWARNING!\033[0m You are attempting to compile InspIRCd on GCC 2.x!\rGCC 2.x series compilers only had partial (read as broken) C++ support, and\ryour compile will most likely fail horribly! If you have any problems, do NOT\rreport them to the bugtracker or forums without first upgrading your compiler\rto a newer 3.x or 4.x (or whatever is available currently) version.\rFOO2\r}\r\r################################################################################\r#                             HELPER FUNCTIONS                          #\r################################################################################\rsub getcache {\r      # Retrieves the .config.cache file, and loads values into the main config hash.\r        open(CACHE, ".config.cache") or return undef;\r  while (<CACHE>) {\r              chomp;\r         # Ignore Blank lines, and comments..\r           next if /^\s*$/;\r               next if /^\s*#/;\r               my ($key, $value) = split("=", $_, 2);\r         $value =~ /^\"(.*)\"$/;\r                # Do something with data here!\r         $config{$key} = $1;\r    }\r      close(CONFIG);\r return "true";\r}\r\rsub makecache {\r      # Dump the contents of %config\r print "Writing \033[1;32mcache file\033[0m for future ./configures ...\n";\r     open(FILEHANDLE, ">.config.cache");\r    foreach $key (keys %config) {\r          print FILEHANDLE "$key=\"$config{$key}\"\n";\r   }\r      close(FILEHANDLE);\r}\r\rsub dir_check {\r  my ($desc, $hash_key) = @_;\r    my $complete = 0;\r      while (!$complete) {\r           print "In what directory $desc?\n";\r            print "[\033[1;32m$config{$hash_key}\033[0m] -> ";\r             chomp($var = <STDIN>);\r         if ($var eq "") {\r                      $var = $config{$hash_key};\r             }\r              if ($var =~ /^\~\/(.+)$/) {\r                    # Convert it to a full path..\r                  $var = resolve_directory($ENV{HOME} . "/" . $1);\r               }\r              elsif ((($config{OSNAME} =~ /MINGW32/i) and ($var !~ /^[A-Z]{1}:\\.*/)) and (substr($var,0,1) ne "/"))\r         {\r                      # Assume relative Path was given.. fill in the rest.\r                   $var = $this . "/$var";\r                }\r              \r               $var = resolve_directory($var); \r               if (! -e $var) {\r                       print "$var does not exist. Create it?\n[\033[1;32my\033[0m] ";\r                        chomp($tmp = <STDIN>);\r                 if (($tmp eq "") || ($tmp =~ /^y/i)) {\r                         # Attempt to Create the Dir..\r                          \r                               system("mkdir -p \"$var\" >> /dev/null 2>&1");\r                         $chk = system("mkdir -p \"$var\" >> /dev/null 2>&1") / 256;\r                            if ($chk != 0) {\r                                       print "Unable to create directory. ($var)\n\n";\r                                        # Restart Loop..\r                                       next;\r                          }\r                      } else {\r                               # They said they don't want to create, and we can't install there.\r                             print "\n\n";\r                          next;\r                  }\r              } else {\r                       if (!is_dir($var)) {\r                           # Target exists, but is not a directory.\r                               print "File $var exists, but is not a directory.\n\n";\r                         next;\r                  }\r              }\r              # Either Dir Exists, or was created fine.\r              $config{$hash_key} = $var;\r             $complete = 1;\r         print "\n";\r    }\r}\r\rsub getosflags {\r\r $config{LDLIBS} = "-lstdc++";\r  $config{FLAGS}  = "-fno-strict-aliasing -fPIC -Wall -Woverloaded-virtual -Wno-deprecated $config{OPTIMISATI}";\r $config{DEVELOPER} = "-fno-strict-aliasing -fPIC -Wall -Woverloaded-virtual -Wno-deprecated -g";\r       $SHARED = "-Wl,--rpath -Wl,$config{LIBRARY_DIR} -shared";\r      $config{MAKEPROG} = "make";\r\r   if ($config{OSNAME} =~ /darwin/i) {\r            $config{FLAGS}  = "-DDARWIN -frtti -fPIC -Wall -Woverloaded-virtual -Wno-deprecated $config{OPTIMISATI}";\r              $SHARED = "-bundle -twolevel_namespace -undefined dynamic_lookup";\r             $config{LDLIBS} = "-ldl -lstdc++";\r     }\r\r     if ($config{OSNAME} =~ /OpenBSD/i) {\r           $config{MAKEPROG} = "gmake";\r           chomp($foo = `eg++ -dumpversion | cut -c 1`);\r          # theyre running the package version of gcc (eg++)... detect it and set up its version numbers.\r                # if theyre not running this, configure lets the build continue but they probably wont manage to\r               # compile as this standard version is 2.95.3!\r          if ($foo ne "") {\r                      $config{CC} = "eg++";\r                  chomp($config{GCCVER}       = `eg++ -dumpversion | cut -c 1`); # we must redo these if we change the compiler path\r             }\r              return "OpenBSD";\r      }\r\r     if ($config{OSNAME} =~ /Linux/i) {\r             $config{LDLIBS} = "-ldl -lstdc++";\r             $config{FLAGS}  = "-fno-strict-aliasing -fPIC -Wall -Woverloaded-virtual -Wno-deprecated $config{OPTIMISATI}";\r         $config{FLAGS}  .= " " . $ENV{CXXFLAGS} if exists($ENV{CXXFLAGS});\r             $config{LDLIBS} .= " " . $ENV{LDLIBS} if exists($ENV{LDLIBS});\r         $config{MAKEPROG} = "make";\r            if ($config{OSNAME} =~ /CYGWIN/) {\r                     $config{FLAGS}  = "-fno-strict-aliasing -Wall -Woverloaded-virtual -Wno-deprecated $config{OPTIMISATI}";\r                       $config{LDLIBS} = "";\r                  $config{MAKEPROG} = "/usr/bin/make";\r                   $config{MAKEORDER} = "ircd mods";\r                      return "Cygwin";\r               } elsif ($config{OSNAME} eq "CYG-STATIC") {\r                    $config{FLAGS} = "-fno-strict-aliasing -Wall -Woverloaded-virtual -Wno-deprecated $config{OPTIMISATI}";\r                        $config{LDLIBS} = "";\r                  $config{MAKEPROG} = "/usr/bin/make";\r                   $config{MAKEORDER} = "mods ircd";\r                      $config{STATICLIBS} = "modules/mods.a";\r                        $config{STATIC_LINK} = "yes";\r                  return "Cygwin-Static";\r                }\r      }\r\r     if ($config{OSNAME} =~ /FreeBSD/i) {\r           $config{FLAGS}  .= " " . $ENV{CXXFLAGS} if exists($ENV{CXXFLAGS});\r             $config{LDLIBS} .= " " . $ENV{LDLIBS} if exists($ENV{LDLIBS});\r }\r\r     if ($config{OSNAME} =~ /SunOS/i or $config{OSNAME} =~ /solaris/i)\r      {\r              # solaris/sunos needs these\r            # socket = bsd sockets api\r             # nsl = dns stuff\r              # rt = POSIX realtime extensions\r               # resolv = inet_aton only (why isnt this in nsl?!)\r             $config{MAKEPROG} = "gmake";\r           $config{LDLIBS} .= " -lsocket -lnsl -lrt -lresolv";\r            return "Solaris";\r      }\r      \r       if($config{OSNAME} =~ /MINGW32/i)\r      {\r              # All code is position-independent on windows\r          $config{FLAGS} =~ s/-fPIC //;\r          return "MinGW";\r        }\r\r     return $config{OSNAME};\r}\r\rsub writefiles {\r    my($writeheader) = @_;\r # First File.. inspircd_config.h\r       chomp(my $incos = `uname -n -s -r`);\r   chomp($version = `sh src/version.sh`);\r chomp(my $revision2 = getrevision());\r  if ($writeheader == 1)\r {\r              print "Writing \033[1;32minspircd_config.h\033[0m\n";\r          open(FILEHANDLE, ">include/inspircd_config.h");\r                my $NL = $config{NICK_LENGT}+1;\r                my $CL = $config{CHAN_LENGT}+1;\r                print FILEHANDLE <<EOF;\r/* Auto generated by configure, do not modify! */\r#ifndef __CONFIGURATION_AUTO__\r#define __CONFIGURATION_AUTO__\r\r/* this is for windows support. */\r#define CoreExport /**/\r#define DllExport /**/\r\r#define CONFIG_FILE "$config{CONFIG_DIR}/inspircd.conf"\r#define MOD_PATH "$config{MODULE_DIR}"\r#define VERSION "$version"\r#define REVISION "$revision2"\r#define MAXCLIENTS $config{MAX_CLIENT}\r#define MAXCLIENTS_S "$config{MAX_CLIENT}"\r#define SOMAXCONN_S "$config{_SOMAXCONN}"\r#define MAX_DESCRIPTORS $config{MAX_DESCRIPTORS}\r#define NICKMAX $NL\r#define CHANMAX $CL\r#define MAXMODES $config{MAXI_MODES}\r#define IDENTMAX $config{MAX_IDENT}\r#define MAXQUIT $config{MAX_QUIT}\r#define MAXTOPIC $config{MAX_TOPIC}\r#define MAXKICK $config{MAX_KICK}\r#define MAXGECOS $config{MAX_GECOS}\r#define MAXAWAY $config{MAX_AWAY}\r#define OPTIMISATION $config{OPTIMITEMP}\r#define LIBRARYDIR "$config{LIBRARY_DIR}"\r#define SYSTEM "$incos"\rEOF\rprint FILEHANDLE "#define MAXBUF " . ($config{MAXBUF}+2) . "\n";\r\r               if ($config{OSNAME} =~ /SunOS/i) {\r                     print FILEHANDLE "#define IS_SOLARIS\n";\r               }\r              if ($config{OSNAME} =~ /CYGWIN/i) {\r                    print FILEHANDLE "#define IS_CYGWIN\n";\r                        print FILEHANDLE "#ifndef FD_SETSIZE\n#define FD_SETSIZE        1024\n#endif\n";\r               }\r              if ($config{OSNAME} =~ /MINGW32/i) {\r                   print FILEHANDLE "#define IS_MINGW\n";\r         }\r              if ($config{OSNAME} =~ /CYG-STATIC/i) {\r                        print FILEHANDLE "#ifndef FD_SETSIZE\n#define FD_SETSIZE    1024\n#endif\n";\r           }\r              if ($config{STATIC_LINK} eq "yes") {\r                   print FILEHANDLE "#define STATIC_LINK\n";\r              }\r              if ($config{GCCVER} >= 3) {\r                    print FILEHANDLE "#define GCC3\n";\r             }\r              if ($config{HAS_STRLCPY} eq "true") {\r                  print FILEHANDLE "#define HAS_STRLCPY\n";\r              }\r              if ($config{HAS_STDINT} eq "true") {\r                   print FILEHANDLE "#define HAS_STDINT\n";\r               }\r              if ($config{IPV6} =~ /y/i) {\r                   print FILEHANDLE "#define IPV6\n";\r             }\r              if ($config{SUPPORT_IP6LINKS} =~ /y/i) {\r                       print FILEHANDLE "#define SUPPORT_IP6LINKS\n";\r         }\r              my $use_hiperf = 0;\r            if (($has_kqueue) && ($config{USE_KQUEUE} eq "y")) {\r                   print FILEHANDLE "#define USE_KQUEUE\n";\r                       $se = "socketengine_kqueue";\r                   $use_hiperf = 1;\r               }\r              if (($has_epoll) && ($config{USE_EPOLL} eq "y")) {\r                     print FILEHANDLE "#define USE_EPOLL\n";\r                        $se = "socketengine_epoll";\r                    $use_hiperf = 1;\r               }\r              if (($has_ports) && ($config{USE_PORTS} eq "y")) {\r                     print FILEHANDLE "#define USE_PORTS\n";\r                        $se = "socketengine_ports";\r                    $use_hiperf = 1;\r               }\r              # user didn't choose either epoll or select for their OS.\r              # default them to USE_SELECT (ewwy puke puke)\r          if (!$use_hiperf) {\r                    print FILEHANDLE "#define USE_SELECT\n";\r                       $se = "socketengine_select";\r           }\r              print FILEHANDLE "\n#endif\n";\r         close(FILEHANDLE);\r     }\r\r     if ($writeheader)\r      {\r              open(FILEHANDLE, ">include/inspircd_se_config.h");\r             print FILEHANDLE <<EOF;\r/* Auto generated by configure, do not modify or commit to svn! */\r#ifndef __CONFIGURATION_SOCKETENGINE__\r#define __CONFIGURATION_SOCKETENGINE__\r\r#include "$se.h"\r\r#endif\rEOF\r         close(FILEHANDLE);\r     }\r\r\r    # Create a Modules List..\r      my $modules = "";\r      foreach $i (@modlist)\r  {\r              if ($config{STATIC_LINK} eq "yes") {\r                   $modules .= "m_".$i.".o ";\r             }\r              else {\r                 $modules .= "m_".$i.".so ";\r            }\r      }\r      chomp($modules);   # Remove Redundant whitespace..\r\r    opendir(DIRHANDLE, "src/modules");\r     foreach $name (sort readdir(DIRHANDLE)) {\r              if ($name =~ /^m_(.+?)$/) {\r                    if (opendir(MDIRHANDLE, "src/modules/$name") != 0) {\r                           closedir(MDIRHANDLE);\r                          $modules .= "$name.so ";\r                       }\r              }\r      }\r      closedir(DIRHANDLE);\r\r\r # Write all .in files.\r my $tmp = "";\r  my $file = "";\r my $exe = "inspircd";\r\r if ($config{OSNAME} =~ /CYGWIN/i) {\r            $exe = "inspircd.exe";\r }\r\r     opendir(DIRHANDLE, $this);\r\r    # Do this once here, and cache it in the .*.inc files,\r # rather than attempting to read src/version.sh from\r   # compiled code -- we might not have the source to hand.\r       # Fix for bug#177 by Brain.\r\r   chomp(my $version = `sh ./src/version.sh`);\r    chomp(my $revision = getrevision());\r   $version = "$version(r$revision)";\r\r    my $LIBEXT = "so";\r     if ($config{IS_DARWIN} eq "YES")\r       {\r              $LIBEXT = "dylib";\r     }\r      # We can actually parse any file starting with . and ending with .inc,\r # but right now we only parse .inspircd.inc to form './inspircd'\r\r      foreach $name (sort readdir(DIRHANDLE)) {\r              if ($name =~ /^\.(.+)\.inc$/) {\r                        $file = $1;\r                    # All .name.inc files need parsing!\r                    $tmp = "";\r                     open(FILEHANDLE, ".$file.inc");\r                        while (<FILEHANDLE>) {\r                         $tmp .= $_;\r                    }\r                      close(FILEHANDLE);\r\r                    $tmp =~ s/\@CC\@/$config{CC}/;\r                 $tmp =~ s/\@MAKEPROG\@/$config{MAKEPROG}/;\r                     $tmp =~ s/\@FLAGS\@/$config{FLAGS}/;\r                   $tmp =~ s/\@DEVELOPER\@/$config{DEVELOPER}/;\r                   $tmp =~ s/\@LDLIBS\@/$config{LDLIBS}/;\r                 $tmp =~ s/\@BASE_DIR\@/$config{BASE_DIR}/;\r                     $tmp =~ s/\@CONFIG_DIR\@/$config{CONFIG_DIR}/;\r                 $tmp =~ s/\@MODULE_DIR\@/$config{MODULE_DIR}/;\r                 $tmp =~ s/\@BINARY_DIR\@/$config{BINARY_DIR}/;\r                 $tmp =~ s/\@LIBRARY_DIR\@/$config{LIBRARY_DIR}/;\r                       $tmp =~ s/\@LIBRARY_EXT\@/$LIBEXT/;\r                    $tmp =~ s/\@MODULES\@/$modules/;\r                       $tmp =~ s/\@STARTSCRIPT\@/$config{STARTSCRIPT}/;\r                       $tmp =~ s/\@DESTINATION\@/$config{DESTINATION}/;\r                       $tmp =~ s/\@EXTRA_DIR\@/$config{EXTRA_DIR}/;\r                   $tmp =~ s/\@EXECUTABLE\@/$exe/;\r                        $tmp =~ s/\@MAKEORDER\@/$config{MAKEORDER}/;\r                   $tmp =~ s/\@STATICLIBS\@/$config{STATICLIBS}/;\r                 $tmp =~ s/\@VERSION\@/$version/;\r\r                      print "Writing \033[1;32m$file\033[0m\n";\r                      open(FILEHANDLE, ">$file");\r                    print FILEHANDLE $tmp;\r         }\r      }\r      closedir(DIRHANDLE);\r\r  # Make inspircd executable!\r    chmod 0744, 'inspircd';\r\r       if ($config{STATIC_LINK} eq "yes") {\r           print "Writing static-build \033[1;32msrc/Makefile\033[0m\n";\r          write_static_makefile();\r               write_static_modules_makefile();\r       } elsif ($config{OSNAME} =~ /CYGWIN/i) {\r               print "Writing cygwin-build \033[1;32msrc/Makefile\033[0m\n";\r          write_static_makefile();\r               write_dynamic_modules_makefile();\r      } else {\r               print "Writing dynamic-build \033[1;32msrc/Makefile\033[0m\n";\r         write_dynamic_makefile();\r              write_dynamic_modules_makefile();\r      }\r}\r\rsub write_static_modules_makefile {\r       # Modules Makefile..\r   print "Writing \033[1;32msrc/modules/Makefile\033[0m\n";\r       open(FILEHANDLE, ">src/modules/Makefile");\r\r    ###\r    # Module Makefile Header\r       ###\r    print FILEHANDLE <<EOF;\r# (C) ChatSpike development team\r# Makefile by <Craig\@ChatSpike.net>\r# Many Thanks to Andrew Church <achurch\@achurch.org>\r#    for assisting with making this work right.\r#\r# Automatically Generated by ./configure to add a modules\r# please run ./configure --update\r\rall: \$(MODULES)\r\rEOF\r       ###\r    # End Module Makefile Header\r   ###\r\r   # Create a Modules List..\r      my $modules = "";\r      my $cmflags = "";\r      my $liflags = "";\r\r     open(MODLIST,">include/modlist.h");\r\r   ###\r    # Include File Header\r  ###\r    print MODLIST <<HEADER;\r// Generated automatically by configure. DO NOT EDIT!\r\r#ifndef __SYMBOLS__H_CONFIGURED__\r#define __SYMBOLS__H_CONFIGURED__\r\rHEADER\r     ###\r    # End Include File Header\r      ###\r\r   # Place Module List into Include\r       foreach $i (@modlist) {\r                if ($i !~ /_static$/) {\r                        print MODLIST "extern \"C\" void * $i\_init (void);\n";\r                }\r      }\r      print MODLIST "\nstruct {const char *name; initfunc *value; } modsyms[] = {\n";\r\r       ###\r    # Build Module Crap\r    ###\r    foreach $i (@modlist)\r  {\r              if ($i !~ /_static$/) {\r                        $cmflags = getcompilerflags("src/modules/m_".$i.".cpp");\r                       $liflags = getlinkerflags("src/modules/m_".$i.".cpp");\r                 $deps = getdependencies("src/modules/m_".$i.".cpp");\r\r                  #print "file: $i: cmflags=$cmflags; liflags=$liflags; deps=$deps\n";\r\r                  ###\r                    # Write Entry to the Makefile\r                  ###\r                    print FILEHANDLE <<EOCHEESE;\rm_$i.o: .m_$i\_static.cpp ../../include/modules.h ../../include/users.h ../../include/channels.h ../../include/base.h $deps\r       \$(CC) -pipe -I../../include \$(FLAGS) $flags -export-dynamic -c .m_$i\_static.cpp\r     mv .m_$i\_static.o ../m_$i.o\r\rEOCHEESE\r                 ###\r                    # End Write Entry to the MakeFile\r                      ###\r                    print "Configuring module [\033[1;32mm_$i.so\033[0m] for static linking... ";\r                  open(MODULE,"<src/modules/m_".$i.".cpp") or die("Could not open m_".$i.".cpp");\r                        open(MUNGED,">src/modules/.m_".$i."_static.cpp") or die("Could not create .m_".$i."_static.cpp");\r                      while (chomp($a = <MODULE>)) { \r                                $a =~ s/init_module/$i\_init/g;\r                                print MUNGED "$a\n";\r                   }\r                      close(MODULE);\r                 close(MUNGED);\r                 print MODLIST <<EOENT;\r{"m_$i.so",\&$i\_init},\rEOENT\r                   print "done\n";\r                }\r      }\r\r     print MODLIST "{0}};\n\n#endif\n";\r     close(MODLIST);\r}\r\rsub write_dynamic_modules_makefile {\r        # Modules Makefile..\r   print "Writing \033[1;32msrc/modules/Makefile\033[0m\n";\r       open(FILEHANDLE, ">src/modules/Makefile");\r     my $extra = "";\r\r       if ($config{OSNAME} =~ /CYGWIN/i) {\r            $extra = "../inspircd.dll.a";\r  }\r\r###\r# Module Makefile Header\r###\r    print FILEHANDLE <<EOF;\r# (C) ChatSpike development team\r# Makefile by <Craig\@ChatSpike.net>\r# Many Thanks to Andrew Church <achurch\@achurch.org>\r#    for assisting with making this work right.\r#\r# Automatically Generated by ./configure to add a modules\r# please run ./configure -update or ./configure -modupdate\r\rall: \$(MODULES)\r\rEOF\r      ###\r    # End Module Makefile Header\r   ###\r\r   # Create a Modules List..\r      my $modules = "";\r      my $cmflags = "";\r      my $liflags = "";\r      my $crud = "";\r\r        foreach $i (@modlist) {\r                ###\r            # Write Entry to the MakeFile\r          ###\r            $cmflags = getcompilerflags("src/modules/m_".$i.".cpp");\r               $liflags = getlinkerflags("src/modules/m_".$i.".cpp");\r         $deps = getdependencies("src/modules/m_".$i.".cpp");\r   \r               #print "file: $i: cmflags=$cmflags; liflags=$liflags; deps=$deps\n";\r   \r               print FILEHANDLE <<EOCHEESE;\rm_$i.so: m_$i.cpp ../../include/modules.h ../../include/users.h ../../include/channels.h ../../include/base.h ../../include/inspircd_config.h ../../include/inspircd.h ../../include/configreader.h $deps\r \$(CC) -pipe -I../../include \$(FLAGS) $cmflags -export-dynamic -c m_$i.cpp\rEOCHEESE\r\rif ($config{OSNAME} =~ /darwin/) {\r               print FILEHANDLE <<EOCHEESE;\r   \$(CC) -pipe -twolevel_namespace -undefined dynamic_lookup \$(FLAGS) -bundle $liflags -o m_$i.so m_$i.o $extra\r\rEOCHEESE\r} else {\r              print FILEHANDLE <<EOCHEESE;\r   \$(CC) -pipe \$(FLAGS) -shared $liflags -o m_$i.so m_$i.o $extra\r\rEOCHEESE\r}\r           $crud = $crud . "       install -m \$(INSTMODE) m_$i.so \$(MODPATH)\n";\r###\r            # End Write Entry to the MakeFile\r              ###\r    }\r\r     opendir(DIRHANDLE, "src/modules");\r     foreach $name (sort readdir(DIRHANDLE)) {\r              if ($name =~ /^m_(.+?)$/) {\r                    $crapola = "";\r                 $crap3 = "";\r                   # A module made of multiple files, in a dir, e.g. src/modules/m_spanningtree/\r                  if (opendir(MDIRHANDLE, "src/modules/$name") != 0) {\r                           my $i = 0;\r                             print FILEHANDLE "$name.so: ../../include/modules.h ../../include/users.h ../../include/channels.h ../../include/base.h ../../include/inspircd_config.h ../../include/inspircd.h ../../include/configreader.h"; \r                               foreach $fname (sort readdir(MDIRHANDLE)) {\r                                    if ($fname =~ /\.cpp$/) {\r                                              $cmflags = getcompilerflags("src/modules/$name/$fname");\r                                               $liflags = getlinkerflags("src/modules/$name/$fname");\r                                         $deps = getdependencies("src/modules/$name/$fname");\r                                           $oname = $fname;\r                                               $oname =~ s/\.cpp$/.o/g;\r                                               print FILEHANDLE " $name/$oname";\r                                              $crapola = $crapola .  "$name/$oname: $name/$fname ../../include/modules.h ../../include/users.h ../../include/channels.h ../../include/base.h ../../include/inspircd_config.h ../../include/inspircd.h ../../include/configreader.h $deps\n";\r                                         $crapola = $crapola .  "        \$(CC) -pipe -I../../include -I. \$(FLAGS) $cmflags -export-dynamic -o $name/$oname -c $name/$fname\n\n";\r                                              $crap3 = $crap3 . " $name/$oname";\r                                             $i++;\r                                  }\r                              }\r                              print "Composing Makefile rules for directory \033[1;32m$name\033[0m... (\033[1;32m$i files found\033[0m)\n";\r                          if ($config{IS_DARWIN} eq "YES") {\r                                     print FILEHANDLE "\n    \$(CC) -pipe -twolevel_namespace -undefined dynamic_lookup \$(FLAGS) -bundle -o $name.so $crap3\n"; \r                           } else {\r                                       print FILEHANDLE "\n    \$(CC) -pipe \$(FLAGS) -shared $liflags -o $name.so $crap3\n";\r                         }\r                              print FILEHANDLE "\n$crapola\n";\r                               closedir(MDIRHANDLE);\r                          $crud = $crud . "       install -m \$(INSTMODE) $name.so \$(MODPATH)\n";\r                       }\r              }\r      }\r      closedir(DIRHANDLE);\r\r  print FILEHANDLE "modinst:\n    \@echo \"Installing modules...\"\n" . $crud;\r}\r\r\rsub write_static_makefile {\r   open(FH,">src/Makefile") or die("Could not write src/Makefile!");\r      my $i = 0;\r     my @cmdlist = ();\r      opendir(DIRHANDLE, "src");\r     foreach $name (sort readdir(DIRHANDLE)) {\r              if ($name =~ /^cmd_(.+)\.cpp$/) {\r                      $cmdlist[$i++] = $1;\r           }\r      }\r      closedir(DIRHANDLE);\r   my $cmdobjs = "";\r      my $srcobjs = "";\r      foreach my $cmd (@cmdlist) {\r           $cmdobjs = $cmdobjs . "cmd_$cmd.o ";\r           $srcobjs = $srcobjs . "cmd_$cmd.cpp ";\r }\r      print FH <<EOM;\r# Insp Makefile :p\r#\r# (C) ChatSpike development team\r# Makefile by <Craig\@ChatSpike.net>\r# Makefile version 2 (statically linked core) by <brain\@inspircd.org>\r#\r\rCC = im a cheezeball\r\rCXXFLAGS = -I../include \${FLAGS}\rCPPFILES = \$(shell /bin/ls -l modes/ | grep '\\.cpp' | sed 's/^.* //' | grep -v svn)\rRELCPPFILES = \$(shell /bin/ls -l modes/ | grep '\\.cpp' | sed 's/^.* /modes\\//' | grep -v svn)\r\rEOM\r\r$se = "socketengine_select";\rif (($has_kqueue) && ($config{USE_KQUEUE} eq "y")) {\r    $se = "socketengine_kqueue";\r}       \relsif (($has_epoll) && ($config{USE_EPOLL} eq "y")) {\r    $se = "socketengine_epoll";\r}\relsif (($has_ports) && ($config{USE_PORTS} eq "y")) {\r    $se = "socketengine_ports";\r}\r\r ###\r    # This next section is for cygwin dynamic module builds.\r       # Basically, what we do, is build the inspircd core as a library\r       # then the main executable uses that. the library is capable of\r        # loading / unloading the modules dynamically :)\r       # Massive thanks to the guys on #cygwin @ irc.freenode.net for helping\r # make this work :)\r    ###\r\r   if ($config{OSNAME} =~ /CYGWIN/i) {\r            print FH <<EOM;\rall: timer.o command_parse.o cull_list.o userprocess.o socketengine.o socket.o hashcomp.o channels.o mode.o xline.o inspstring.o dns.o base.o configreader.o inspsocket.o $cmdobjs commands.o dynamic.o users.o modules.o wildcard.o helperfuncs.o snomasks.o inspircd.exe\r\rinspircd.exe: inspircd.dll.a\r       \$(CC) -o \$@ \$^\r\rinspircd.dll inspircd.dll.a: inspircd.o channels.o mode.o xline.o inspstring.o dns.o base.o configreader.o inspsocket.o $cmdobjs  commands.o dynamic.o users.o modules.o wildcard.o helperfuncs.o hashcomp.o socket.o socketengine.o userprocess.o cull_list.o command_parse.o timer.o snomasks.o\r   \$(CC) -shared -Wl,--out-implib=inspircd.dll.a -o inspircd.dll \$^\rEOM\r } else {\r               print FH <<EOM;\rall: timer.o command_parse.o cull_list.o userprocess.o socketengine.o socket.o hashcomp.o channels.o mode.o xline.o inspstring.o dns.o base.o configreader.o inspsocket.o $cmdobjs commands.o dynamic.o users.o modules.o wildcard.o helperfuncs.o snomasks.o \$(MODULES) inspircd.exe\r\rinspircd.exe: inspircd.cpp ../include/base.h ../include/channels.h ../include/inspircd.h ../include/channels.h ../include/globals.h ../include/inspircd_config.h ../include/base.h\r     \$(CC) -I../include \$(FLAGS) inspircd.cpp -o inspircd.exe \$(LDLIBS) channels.o mode.o xline.o inspstring.o dns.o base.o inspsocket.o configreader.o $cmdobjs commands.o dynamic.o users.o modules.o wildcard.o helperfuncs.o hashcomp.o socket.o socketengine.o userprocess.o cull_list.o command_parse.o timer.o snomasks.o modes/modeclasses.a \$(MODULES)\rEOM\r     }\r\r     print FH <<EOM;\r\rcull_list.o: cull_list.cpp ../include/base.h ../include/hashcomp.h ../include/globals.h ../include/inspircd_config.h ../include/users.h ../include/channels.h\r \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c cull_list.cpp\r\rsnomasks.o: snomasks.cpp ../include/base.h ../include/hashcomp.h ../include/inspircd.h ../include/users.h ../include/globals.h ../include/inspircd_config.h ../include/channels.h\r        \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c snomasks.cpp\r\rcommand_parse.o: command_parse.cpp ../include/base.h ../include/hashcomp.h ../include/inspircd.h ../include/users.h ../include/globals.h ../include/inspircd_config.h\r     \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c command_parse.cpp\r\ruserprocess.o: userprocess.cpp ../include/base.h ../include/hashcomp.h ../include/globals.h ../include/inspircd_config.h\r     \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c userprocess.cpp\r\rsocketengine.o: $se.cpp socketengine.cpp ../include/base.h ../include/hashcomp.h ../include/globals.h ../include/inspircd_config.h ../include/$se.h\r    \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c socketengine.cpp $se.cpp\r\rhashcomp.o: hashcomp.cpp ../include/base.h ../include/hashcomp.h ../include/inspircd.h ../include/users.h ../include/globals.h ../include/inspircd_config.h\r   \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c hashcomp.cpp\r\rhelperfuncs.o: helperfuncs.cpp ../include/base.h ../include/inspircd.h ../include/users.h ../include/globals.h ../include/inspircd_config.h\r       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c helperfuncs.cpp\r\rchannels.o: channels.cpp ../include/base.h ../include/channels.h ../include/inspircd.h ../include/users.h ../include/globals.h ../include/inspircd_config.h\r    \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c channels.cpp\r\rmode.o: mode.cpp ../include/base.h ../include/mode.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h \$(RELCPPFILES) modes/modeclasses.a\r \${MAKE} -C "modes" DIRNAME="src/modes" CC="\$(CC)" \$(MAKEARGS)\r       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c mode.cpp\r\rxline.o: xline.cpp ../include/base.h ../include/xline.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h\r      \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c xline.cpp\r\rinspstring.o: inspstring.cpp ../include/base.h ../include/inspstring.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h\r      \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c inspstring.cpp\r\rdns.o: dns.cpp ../include/base.h ../include/dns.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h ../include/timer.h\r   \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c dns.cpp\r\rbase.o: base.cpp ../include/base.h ../include/globals.h ../include/inspircd_config.h\r   \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c base.cpp\r\rconfigreader.o: configreader.cpp ../include/base.h ../include/configreader.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h\r \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c configreader.cpp\r\rcommands.o: commands.cpp ../include/base.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h ../include/timer.h $srcobjs\r       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c commands.cpp $cmdobjs\r\rdynamic.o: dynamic.cpp ../include/base.h ../include/dynamic.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h\r   \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c dynamic.cpp\r\rusers.o: users.cpp ../include/base.h ../include/users.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h ../include/timer.h\r        \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c users.cpp\r\rmodules.o: modules.cpp ../include/base.h ../include/modules.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h ../include/timer.h\r    \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c modules.cpp\r\rwildcard.o: wildcard.cpp ../include/base.h ../include/wildcard.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h\r  \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c wildcard.cpp\r\rsocket.o: socket.cpp ../include/base.h ../include/inspircd.h ../include/globals.h ../include/inspircd_config.h\r    \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c socket.cpp\r      \rinspsocket.o: inspsocket.cpp ../include/base.h ../include/inspircd.h ../include/globals.h ../include/inspircd_config.h ../include/timer.h\r     \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c inspsocket.cpp\r\rtimer.o: timer.cpp ../include/base.h ../include/inspircd.h ../include/globals.h ../include/inspircd_config.h ../include/timer.h\r \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c timer.cpp\r\rEOM\r  foreach my $cmd (@cmdlist) {\r           print FH <<ITEM;\rcmd_$cmd.o: cmd_$cmd.cpp ../include/base.h ../include/modules.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h ../include/commands/cmd_$cmd.h\r       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c cmd_$cmd.cpp\rITEM\r       }\r      close(FH);\r}\r\rsub write_dynamic_makefile {\r\r    my $i = 0;\r     my @cmdlist = ();\r      opendir(DIRHANDLE, "src");\r     foreach $name (sort readdir(DIRHANDLE)) {\r              if ($name =~ /^cmd_(.+)\.cpp$/) {\r                      $cmdlist[$i++] = $1;\r           }\r      }\r      closedir(DIRHANDLE);\r\r  my $cmdobjs = "";\r      my $srcobjs = "";\r      foreach my $cmd (@cmdlist) {\r           $cmdobjs = $cmdobjs . "cmd_$cmd.so ";\r          $srcobjs = $srcobjs . "cmd_$cmd.cpp ";\r }\r\r     $se = "socketengine_select";\r   if (($has_kqueue) && ($config{USE_KQUEUE} eq "y")) {\r           $se = "socketengine_kqueue";\r   }\r      elsif (($has_epoll) && ($config{USE_EPOLL} eq "y")) {\r          $se = "socketengine_epoll";\r    }\r      elsif (($has_ports) && ($config{USE_PORTS} eq "y")) {\r          $se = "socketengine_ports";\r    }\r\r     open(FH,">src/Makefile") or die("Could not write src/Makefile");\r       print FH <<EOM;\r# Insp Makefile :p\r#\r# (C) ChatSpike development team\r# Makefile by <Craig\@ChatSpike.net>\r# Makefile version 2 (dynamically linked core) by <brain\@inspircd.org>\r#\r\rCC = im a cheezeball\r\rCXXFLAGS = -I../include \${FLAGS}\rCPPFILES = \$(shell /bin/ls -l modes/ | grep '\\.cpp' | sed 's/^.* //' | grep -v svn)\rRELCPPFILES = \$(shell /bin/ls -l modes/ | grep '\\.cpp' | sed 's/^.* /modes\\//' | grep -v svn)\r\rEOM\r\rif ($config{IS_DARWIN} eq "YES") {\r  print FH <<EOM;\rall: libIRCDtimer.dylib libIRCDcull_list.dylib libIRCDuserprocess.dylib libIRCDsocketengine.dylib libIRCDsocket.dylib libIRCDhash.dylib libIRCDchannels.dylib libIRCDmode.dylib libIRCDxline.dylib libIRCDstring.dylib libIRCDasyncdns.dylib libIRCDbase.dylib libIRCDconfigreader.dylib libIRCDinspsocket.dylib libIRCDcommands.dylib libIRCDdynamic.dylib libIRCDusers.dylib libIRCDmodules.dylib libIRCDwildcard.dylib libIRCDhelper.dylib libIRCDcommand_parse.dylib libIRCDsnomasks.dylib inspircd\r\rinspircd: inspircd.cpp ../include/base.h ../include/channels.h ../include/inspircd.h ../include/channels.h ../include/globals.h ../include/inspircd_config.h ../include/socket.h $cmdobjs libIRCDtimer.dylib libIRCDcull_list.dylib libIRCDuserprocess.dylib libIRCDsocketengine.dylib libIRCDsocket.dylib libIRCDhash.dylib libIRCDchannels.dylib libIRCDmode.dylib libIRCDxline.dylib libIRCDstring.dylib libIRCDasyncdns.dylib libIRCDbase.dylib libIRCDconfigreader.dylib libIRCDinspsocket.dylib libIRCDsnomasks.dylib libIRCDcommands.dylib libIRCDdynamic.dylib libIRCDusers.dylib libIRCDmodules.dylib libIRCDwildcard.dylib libIRCDhelper.dylib libIRCDcommand_parse.dylib\r   \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c inspircd.cpp\r    \$(CC) -pipe -dynamic -bind_at_load -L. -o inspircd \$(LDLIBS) inspircd.o libIRCDchannels.dylib libIRCDmode.dylib libIRCDxline.dylib libIRCDstring.dylib libIRCDasyncdns.dylib libIRCDbase.dylib libIRCDconfigreader.dylib libIRCDinspsocket.dylib libIRCDcommands.dylib libIRCDdynamic.dylib libIRCDusers.dylib libIRCDmodules.dylib libIRCDwildcard.dylib libIRCDhelper.dylib libIRCDhash.dylib libIRCDsocket.dylib libIRCDsocketengine.dylib libIRCDuserprocess.dylib libIRCDcull_list.dylib libIRCDcommand_parse.dylib libIRCDtimer.dylib libIRCDsnomasks.dylib\r\rlibIRCDsocketengine.dylib: $se.cpp socketengine.cpp ../include/base.h ../include/hashcomp.h ../include/globals.h ../include/inspircd_config.h ../include/$se.h\r    \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c socketengine.cpp\r        \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c $se.cpp\r \$(CC) -pipe -install_name $config{LIBRARY_DIR}/libIRCDsocketengine.dylib -dynamiclib -twolevel_namespace -undefined dynamic_lookup -o libIRCDsocketengine.dylib socketengine.o $se.o\r\rlibIRCDsnomasks.dylib: snomasks.cpp ../include/base.h ../include/hashcomp.h ../include/inspircd.h ../include/users.h ../include/globals.h ../include/inspircd_config.h ../include/channels.h\r    \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c snomasks.cpp\r    \$(CC) -pipe -install_name $config{LIBRARY_DIR}/libIRCDsnomasks.dylib -dynamiclib -twolevel_namespace -undefined dynamic_lookup -o libIRCDsnomasks.dylib snomasks.o\r\rlibIRCDcommand_parse.dylib: command_parse.cpp ../include/base.h ../include/hashcomp.h ../include/inspircd.h ../include/users.h ../include/globals.h ../include/inspircd_config.h\r  \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c command_parse.cpp\r       \$(CC) -pipe -install_name $config{LIBRARY_DIR}/libIRCDcommand_parse.dylib -dynamiclib -twolevel_namespace -undefined dynamic_lookup -o libIRCDcommand_parse.dylib command_parse.o\r\rlibIRCDcull_list.dylib: cull_list.cpp ../include/base.h ../include/hashcomp.h ../include/globals.h ../include/inspircd_config.h ../include/users.h ../include/channels.h\r   \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c cull_list.cpp\r   \$(CC) -pipe -install_name $config{LIBRARY_DIR}/libIRCDcull_list.dylib -dynamiclib -twolevel_namespace -undefined dynamic_lookup -o libIRCDcull_list.dylib cull_list.o\r\rlibIRCDuserprocess.dylib: userprocess.cpp ../include/base.h ../include/hashcomp.h ../include/globals.h ../include/inspircd_config.h\r    \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c userprocess.cpp\r \$(CC) -pipe -install_name $config{LIBRARY_DIR}/libIRCDuserprocess.dylib -dynamiclib -twolevel_namespace -undefined dynamic_lookup -o libIRCDuserprocess.dylib userprocess.o\r\rlibIRCDhash.dylib: hashcomp.cpp ../include/base.h ../include/hashcomp.h ../include/inspircd.h ../include/users.h ../include/globals.h ../include/inspircd_config.h\r       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c hashcomp.cpp\r    \$(CC) -pipe -install_name $config{LIBRARY_DIR}/libIRCDhash.dylib -dynamiclib -twolevel_namespace -undefined dynamic_lookup -o libIRCDhash.dylib hashcomp.o\r\rlibIRCDhelper.dylib: helperfuncs.cpp ../include/base.h ../include/inspircd.h ../include/users.h ../include/globals.h ../include/inspircd_config.h\r \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c helperfuncs.cpp\r \$(CC) -pipe -install_name $config{LIBRARY_DIR}/libIRCDhelper.dylib -dynamiclib -twolevel_namespace -undefined dynamic_lookup -o libIRCDhelper.dylib helperfuncs.o\r\rlibIRCDchannels.dylib: channels.cpp ../include/base.h ../include/channels.h ../include/inspircd.h ../include/users.h ../include/globals.h ../include/inspircd_config.h\r     \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c channels.cpp\r    \$(CC) -pipe -install_name $config{LIBRARY_DIR}/libIRCDchannels.dylib -dynamiclib -twolevel_namespace -undefined dynamic_lookup -o libIRCDchannels.dylib channels.o\r\rlibIRCDmode.dylib: mode.cpp ../include/base.h ../include/mode.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h \$(RELCPPFILES)\r  \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c mode.cpp\r        \${MAKE} -C "modes" DIRNAME="src/modes" CC="\$(CC)" \$(MAKEARGS) CPPFILES="\$(CPPFILES)"\r       \$(CC) -pipe -install_name $config{LIBRARY_DIR}/libIRCDmode.dylib -dynamiclib -twolevel_namespace -undefined dynamic_lookup -o libIRCDmode.dylib mode.o modes/modeclasses.a\r\rlibIRCDxline.dylib: xline.cpp ../include/base.h ../include/xline.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h ../include/timer.h\r    \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c xline.cpp\r       \$(CC) -pipe -install_name $config{LIBRARY_DIR}/libIRCDxline.dylib -dynamiclib -twolevel_namespace -undefined dynamic_lookup -o libIRCDxline.dylib xline.o\r\rlibIRCDstring.dylib: inspstring.cpp ../include/base.h ../include/inspstring.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h\r     \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c inspstring.cpp\r  \$(CC) -pipe -install_name $config{LIBRARY_DIR}/libIRCDstring.dylib -dynamiclib -twolevel_namespace -undefined dynamic_lookup -o libIRCDstring.dylib inspstring.o\r\rlibIRCDasyncdns.dylib: dns.cpp ../include/base.h ../include/dns.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h ../include/timer.h\r       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c dns.cpp\r \$(CC) -pipe -install_name $config{LIBRARY_DIR}/libIRCDasyncdns.dylib -dynamiclib -twolevel_namespace -undefined dynamic_lookup -o libIRCDasyncdns.dylib dns.o\r\rlibIRCDbase.dylib: base.cpp ../include/base.h ../include/globals.h ../include/inspircd_config.h\r        \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c base.cpp\r        \$(CC) -pipe -install_name $config{LIBRARY_DIR}/libIRCDbase.dylib -dynamiclib -twolevel_namespace -undefined dynamic_lookup -o libIRCDbase.dylib base.o\r\rlibIRCDconfigreader.dylib: configreader.cpp ../include/base.h ../include/configreader.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h\r      \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c configreader.cpp\r        \$(CC) -pipe -install_name $config{LIBRARY_DIR}/libIRCDconfigreader.dylib -dynamiclib -twolevel_namespace -undefined dynamic_lookup -o libIRCDconfigreader.dylib configreader.o\r\rlibIRCDcommands.dylib: commands.cpp ../include/base.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h ../include/timer.h\r     \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c commands.cpp\r    \$(CC) -pipe -install_name $config{LIBRARY_DIR}/libIRCDcommands.dylib -dynamiclib -twolevel_namespace -undefined dynamic_lookup -o libIRCDcommands.dylib commands.o\r\rlibIRCDdynamic.dylib: dynamic.cpp ../include/base.h ../include/dynamic.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h\r \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c dynamic.cpp\r     \$(CC) -pipe -install_name $config{LIBRARY_DIR}/libIRCDdynamic.dylib -dynamiclib -twolevel_namespace -undefined dynamic_lookup -o libIRCDdynamic.dylib dynamic.o\r\rlibIRCDusers.dylib: users.cpp ../include/base.h ../include/users.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h ../include/timer.h\r       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c users.cpp\r       \$(CC) -pipe -install_name $config{LIBRARY_DIR}/libIRCDusers.dylib -dynamiclib -twolevel_namespace -undefined dynamic_lookup -o libIRCDusers.dylib users.o\r\rlibIRCDmodules.dylib: modules.cpp ../include/base.h ../include/modules.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h ../include/timer.h\r       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c modules.cpp\r     \$(CC) -pipe -install_name $config{LIBRARY_DIR}/libIRCDmodules.dylib -dynamiclib -twolevel_namespace -undefined dynamic_lookup -o libIRCDmodules.dylib modules.o\r\rlibIRCDwildcard.dylib: wildcard.cpp ../include/base.h ../include/wildcard.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h\r \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c wildcard.cpp\r    \$(CC) -pipe -install_name $config{LIBRARY_DIR}/libIRCDwildcard.dylib -dynamiclib -twolevel_namespace -undefined dynamic_lookup -o libIRCDwildcard.dylib wildcard.o\r\rlibIRCDsocket.dylib: socket.cpp ../include/base.h ../include/inspircd.h ../include/globals.h ../include/inspircd_config.h\r \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c socket.cpp\r      \$(CC) -pipe -install_name $config{LIBRARY_DIR}/libIRCDsocket.dylib -dynamiclib -twolevel_namespace -undefined dynamic_lookup -o libIRCDsocket.dylib socket.o\r\rlibIRCDinspsocket.dylib: inspsocket.cpp ../include/base.h ../include/inspircd.h ../include/globals.h ../include/inspircd_config.h ../include/timer.h\r    \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c inspsocket.cpp\r  \$(CC) -pipe -install_name $config{LIBRARY_DIR}/libIRCDinspsocket.dylib -dynamiclib -twolevel_namespace -undefined dynamic_lookup -o libIRCDinspsocket.dylib inspsocket.o\r\rlibIRCDtimer.dylib: timer.cpp ../include/base.h ../include/inspircd.h ../include/globals.h ../include/inspircd_config.h ../include/timer.h\r  \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c timer.cpp\r       \$(CC) -pipe -install_name $config{LIBRARY_DIR}/libIRCDtimer.dylib -dynamiclib -twolevel_namespace -undefined dynamic_lookup -o libIRCDtimer.dylib timer.o\r\rEOM\r\r} else {\r\r     print FH <<EOM;\rall: libIRCDtimer.so libIRCDcull_list.so libIRCDuserprocess.so libIRCDsocketengine.so libIRCDsocket.so libIRCDhash.so libIRCDchannels.so libIRCDmode.so libIRCDxline.so libIRCDstring.so libIRCDasyncdns.so libIRCDbase.so libIRCDconfigreader.so libIRCDinspsocket.so $cmdobjs libIRCDcommands.so libIRCDdynamic.so libIRCDusers.so libIRCDmodules.so libIRCDwildcard.so libIRCDhelper.so libIRCDcommand_parse.so libIRCDsnomasks.so inspircd\r\rinspircd: inspircd.cpp ../include/base.h ../include/channels.h ../include/inspircd.h ../include/channels.h ../include/globals.h ../include/inspircd_config.h ../include/socket.h libIRCDtimer.so libIRCDcull_list.so libIRCDuserprocess.so libIRCDsocketengine.so libIRCDsocket.so libIRCDhash.so libIRCDchannels.so libIRCDmode.so libIRCDxline.so libIRCDstring.so libIRCDasyncdns.so libIRCDbase.so libIRCDconfigreader.so libIRCDinspsocket.so $cmdobjs libIRCDsnomasks.so libIRCDcommands.so libIRCDdynamic.so libIRCDusers.so libIRCDmodules.so libIRCDwildcard.so libIRCDhelper.so libIRCDcommand_parse.so\r      \$(CC) -pipe -I../include $extra -Wl,--rpath -Wl,$config{LIBRARY_DIR} \$(FLAGS) -rdynamic -L. inspircd.cpp -o inspircd \$(LDLIBS) libIRCDchannels.so libIRCDmode.so libIRCDxline.so libIRCDstring.so libIRCDasyncdns.so libIRCDbase.so libIRCDconfigreader.so libIRCDinspsocket.so libIRCDcommands.so libIRCDdynamic.so libIRCDusers.so libIRCDmodules.so libIRCDwildcard.so libIRCDhelper.so libIRCDhash.so libIRCDsocket.so libIRCDsocketengine.so libIRCDuserprocess.so libIRCDcull_list.so libIRCDcommand_parse.so libIRCDtimer.so libIRCDsnomasks.so\r\rlibIRCDsocketengine.so: $se.cpp socketengine.cpp ../include/base.h ../include/hashcomp.h ../include/globals.h ../include/inspircd_config.h ../include/$se.h\r \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c socketengine.cpp $se.cpp\r        \$(CC) -pipe -Wl,--rpath -Wl,$config{LIBRARY_DIR} -shared -o libIRCDsocketengine.so socketengine.o $se.o\r\rlibIRCDsnomasks.so: snomasks.cpp ../include/base.h ../include/hashcomp.h ../include/inspircd.h ../include/users.h ../include/globals.h ../include/inspircd_config.h ../include/channels.h\r    \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c snomasks.cpp\r    \$(CC) -pipe -Wl,--rpath -Wl,$config{LIBRARY_DIR} -shared -o libIRCDsnomasks.so snomasks.o\r\rlibIRCDcommand_parse.so: command_parse.cpp ../include/base.h ../include/hashcomp.h ../include/inspircd.h ../include/users.h ../include/globals.h ../include/inspircd_config.h\r      \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c command_parse.cpp\r       \$(CC) -pipe -Wl,--rpath -Wl,$config{LIBRARY_DIR} -shared -o libIRCDcommand_parse.so command_parse.o\r\rlibIRCDcull_list.so: cull_list.cpp ../include/base.h ../include/hashcomp.h ../include/globals.h ../include/inspircd_config.h ../include/users.h ../include/channels.h\r    \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c cull_list.cpp\r   \$(CC) -pipe -Wl,--rpath -Wl,$config{LIBRARY_DIR} -shared -o libIRCDcull_list.so cull_list.o\r\rlibIRCDuserprocess.so: userprocess.cpp ../include/base.h ../include/hashcomp.h ../include/globals.h ../include/inspircd_config.h\r \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c userprocess.cpp\r \$(CC) -pipe -Wl,--rpath -Wl,$config{LIBRARY_DIR} -shared -o libIRCDuserprocess.so userprocess.o\r\rlibIRCDhash.so: hashcomp.cpp ../include/base.h ../include/hashcomp.h ../include/inspircd.h ../include/users.h ../include/globals.h ../include/inspircd_config.h\r      \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c hashcomp.cpp\r    \$(CC) -pipe -Wl,--rpath -Wl,$config{LIBRARY_DIR} -shared -o libIRCDhash.so hashcomp.o\r\rlibIRCDhelper.so: helperfuncs.cpp ../include/base.h ../include/inspircd.h ../include/users.h ../include/globals.h ../include/inspircd_config.h\r \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c helperfuncs.cpp\r \$(CC) -pipe -Wl,--rpath -Wl,$config{LIBRARY_DIR} -shared -o libIRCDhelper.so helperfuncs.o\r\rlibIRCDchannels.so: channels.cpp ../include/base.h ../include/channels.h ../include/inspircd.h ../include/users.h ../include/globals.h ../include/inspircd_config.h\r       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c channels.cpp\r    \$(CC) -pipe -Wl,--rpath -Wl,$config{LIBRARY_DIR} -shared -o libIRCDchannels.so channels.o\r\rlibIRCDmode.so: mode.cpp ../include/base.h ../include/mode.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h \$(RELCPPFILES)\r      \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c mode.cpp\r        \${MAKE} -C "modes" DIRNAME="src/modes" CC="\$(CC)" \$(MAKEARGS) CPPFILES="\$(CPPFILES)"\r       \$(CC) -pipe -Wl,--rpath -Wl,$config{LIBRARY_DIR} -shared -o libIRCDmode.so mode.o modes/modeclasses.a\r\rlibIRCDxline.so: xline.cpp ../include/base.h ../include/xline.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h ../include/timer.h\r    \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c xline.cpp\r       \$(CC) -pipe -Wl,--rpath -Wl,$config{LIBRARY_DIR} -shared -o libIRCDxline.so xline.o\r\rlibIRCDstring.so: inspstring.cpp ../include/base.h ../include/inspstring.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h\r      \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c inspstring.cpp\r  \$(CC) -pipe -Wl,--rpath -Wl,$config{LIBRARY_DIR} -shared -o libIRCDstring.so inspstring.o\r\rlibIRCDasyncdns.so: dns.cpp ../include/base.h ../include/dns.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h ../include/timer.h\r \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c dns.cpp\r \$(CC) -pipe -Wl,--rpath -Wl,$config{LIBRARY_DIR} -shared -o libIRCDasyncdns.so dns.o\r\rlibIRCDbase.so: base.cpp ../include/base.h ../include/globals.h ../include/inspircd_config.h\r    \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c base.cpp\r        \$(CC) -pipe -Wl,--rpath -Wl,$config{LIBRARY_DIR} -shared -o libIRCDbase.so base.o\r\rlibIRCDconfigreader.so: configreader.cpp ../include/base.h ../include/configreader.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h\r      \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c configreader.cpp\r        \$(CC) -pipe -Wl,--rpath -Wl,$config{LIBRARY_DIR} -shared -o libIRCDconfigreader.so configreader.o\r\rlibIRCDcommands.so: commands.cpp ../include/base.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h ../include/timer.h\r     \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c commands.cpp\r    \$(CC) -pipe -Wl,--rpath -Wl,$config{LIBRARY_DIR} -shared -o libIRCDcommands.so commands.o\r\rlibIRCDdynamic.so: dynamic.cpp ../include/base.h ../include/dynamic.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h\r     \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c dynamic.cpp\r     \$(CC) -pipe -Wl,--rpath -Wl,$config{LIBRARY_DIR} -shared -o libIRCDdynamic.so dynamic.o\r\rlibIRCDusers.so: users.cpp ../include/base.h ../include/users.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h ../include/timer.h\r  \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c users.cpp\r       \$(CC) -pipe -Wl,--rpath -Wl,$config{LIBRARY_DIR} -shared -o libIRCDusers.so users.o\r\rlibIRCDmodules.so: modules.cpp ../include/base.h ../include/modules.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h ../include/timer.h\r        \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c modules.cpp\r     \$(CC) -pipe -Wl,--rpath -Wl,$config{LIBRARY_DIR} -shared -o libIRCDmodules.so modules.o\r\rlibIRCDwildcard.so: wildcard.cpp ../include/base.h ../include/wildcard.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h\r    \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c wildcard.cpp\r    \$(CC) -pipe -Wl,--rpath -Wl,$config{LIBRARY_DIR} -shared -o libIRCDwildcard.so wildcard.o\r\rlibIRCDsocket.so: socket.cpp ../include/base.h ../include/inspircd.h ../include/globals.h ../include/inspircd_config.h\r     \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c socket.cpp\r      \$(CC) -pipe -Wl,--rpath -Wl,$config{LIBRARY_DIR} -shared -o libIRCDsocket.so socket.o\r\rlibIRCDinspsocket.so: inspsocket.cpp ../include/base.h ../include/inspircd.h ../include/globals.h ../include/inspircd_config.h ../include/timer.h\r      \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c inspsocket.cpp\r  \$(CC) -pipe -Wl,--rpath -Wl,$config{LIBRARY_DIR} -shared -o libIRCDinspsocket.so inspsocket.o\r\rlibIRCDtimer.so: timer.cpp ../include/base.h ../include/inspircd.h ../include/globals.h ../include/inspircd_config.h ../include/timer.h\r        \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c timer.cpp\r       \$(CC) -pipe -Wl,--rpath -Wl,$config{LIBRARY_DIR} -shared -o libIRCDtimer.so timer.o\r\rEOM\r}\r    foreach my $cmd (@cmdlist) {\r           print FH <<ITEM;\rcmd_$cmd.so: cmd_$cmd.cpp ../include/base.h ../include/modules.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h ../include/commands/cmd_$cmd.h\r      \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c cmd_$cmd.cpp\r    \$(CC) -pipe $SHARED -o cmd_$cmd.so cmd_$cmd.o\r\rITEM\r   }\r      close(FH);\r}\r\r
\ No newline at end of file
+#!/usr/bin/perl
+###################################################
+# InspIRCd Configuration Script
+#
+# Copyright 2002-2007 The InspIRCd Development Team
+#  http://www.inspircd.org/wiki/index.php/Credits
+#
+# Licensed under GPL, please see the COPYING file
+# for more information
+#
+# $Id$
+#
+###################################################
+
+require 5.6.0;
+use Socket;
+use Cwd;
+use Getopt::Long;
+
+# Utility functions for our buildsystem
+use make::utilities;
+use make::configure;
+use make::gnutlscert;
+use make::opensslcert;
+
+GetOptions (
+       'enable-gnutls' => \$opt_use_gnutls,
+       'rebuild' => \$opt_rebuild,
+       'enable-openssl' => \$opt_use_openssl,
+       'disable-interactive' => \$opt_nointeractive,
+       'with-nick-length=i' => \$opt_nick_length,
+       'with-channel-length=i' => \$opt_chan_length,
+       'with-max-clients=i' => \$opt_maxclients,
+       'enable-ports' => \$opt_ports,
+       'enable-epoll' => \$opt_epoll,
+       'enable-kqueue' => \$opt_kqueue,
+       'disable-ports' => \$opt_noports,
+       'disable-epoll' => \$opt_noepoll,
+       'disable-kqueue' => \$opt_nokqueue,
+       'enable-ipv6' => \$opt_ipv6,
+       'enable-remote-ipv6' => \$opt_ipv6links,
+       'disable-remote-ipv6' => \$opt_noipv6links,
+       'with-cc=s' => \$opt_cc,
+       'with-ident-length=i' => \$opt_ident,
+       'with-quit-length=i' => \$opt_quit,
+       'with-topic-length=i' => \$opt_topic,
+       'with-maxbuf=i' => \$opt_maxbuf,
+       'with-kick-length=i' => \$opt_kick,
+       'with-gecos-length=i' => \$opt_gecos,
+       'with-away-length=i' => \$opt_away,
+       'with-max-modes=i' => \$opt_modes,
+       'prefix=s' => \$opt_base_dir,
+       'config-dir=s' => \$opt_config_dir,
+       'module-dir=s' => \$opt_module_dir,
+       'binary-dir=s' => \$opt_binary_dir,
+       'library-dir=s' => \$opt_library_dir,
+       'disable-debuginfo' => sub { $opt_disable_debug = 1 },
+       'help'  => sub { showhelp(); },
+       'modupdate' => sub { modupdate(); },
+       'update' => sub { update(); },
+       'svnupdate' => sub { svnupdate(); },
+       'clean' => sub { clean(); },
+);
+
+my $non_interactive = (
+       (defined $opt_library_dir) ||
+       (defined $opt_base_dir) ||
+       (defined $opt_config_dir) ||
+       (defined $opt_module_dir) ||
+       (defined $opt_base_dir) ||
+       (defined $opt_binary_dir) ||
+       (defined $opt_nointeractive) ||
+       (defined $opt_away) ||
+       (defined $opt_gecos) ||
+       (defined $opt_kick) ||
+       (defined $opt_maxclients) ||
+       (defined $opt_modes) ||
+       (defined $opt_topic) ||
+       (defined $opt_quit) ||
+       (defined $opt_ident) ||
+       (defined $opt_cc) ||
+       (defined $opt_ipv6) ||
+       (defined $opt_ipv6links) ||
+       (defined $opt_noipv6links) ||
+       (defined $opt_kqueue) ||
+       (defined $opt_epoll) ||
+       (defined $opt_ports) ||
+       (defined $opt_maxchans) ||
+       (defined $opt_opermaxchans) ||
+       (defined $opt_chan_length) ||
+       (defined $opt_nick_length) ||
+       (defined $opt_use_openssl) ||
+       (defined $opt_nokqueue) ||
+       (defined $opt_noepoll) ||
+       (defined $opt_noports) ||
+       (defined $opt_maxbuf) ||
+       (defined $opt_use_gnutls)
+);
+my $interactive = !$non_interactive;
+
+
+chomp($topdir = getcwd());
+$this = resolve_directory($topdir);                                            # PWD, Regardless.
+@modlist = ();                                                                 # Declare for Module List..
+%config = ();                                                                  # Initiate Configuration Hash..
+$config{ME}             = resolve_directory($topdir);                          # Present Working Directory
+
+$config{BASE_DIR}         = $config{ME};
+
+if (defined $opt_base_dir)
+{
+       $config{BASE_DIR} = $opt_base_dir;
+}
+
+$config{CONFIG_DIR}     = resolve_directory($config{BASE_DIR}."/conf");        # Configuration Directory
+$config{MODULE_DIR}     = resolve_directory($config{BASE_DIR}."/modules");     # Modules Directory
+$config{BINARY_DIR}     = resolve_directory($config{BASE_DIR}."/bin");         # Binary Directory
+$config{LIBRARY_DIR}   = resolve_directory($config{BASE_DIR}."/lib");          # Library Directory
+
+if (defined $opt_config_dir)
+{
+       $config{CONFIG_DIR} = $opt_config_dir;
+}
+if (defined $opt_module_dir)
+{
+       $config{MODULE_DIR} = $opt_module_dir;
+}
+if (defined $opt_binary_dir)
+{
+       $config{BINARY_DIR} = $opt_binary_dir;
+}
+if (defined $opt_library_dir)
+{
+       $config{LIBRARY_DIR} = $opt_library_dir;
+}
+chomp($config{HAS_GNUTLS}   = `libgnutls-config --version 2>/dev/null | cut -c 1,2,3`); # GNUTLS Version.
+chomp($config{HAS_OPENSSL}  = `pkg-config --modversion openssl 2>/dev/null`);          # Openssl version
+chomp($gnutls_ver = $config{HAS_GNUTLS});
+chomp($openssl_ver = $config{HAS_OPENSSL});
+$config{USE_GNUTLS}        = "n";
+if (defined $opt_use_gnutls)
+{
+       $config{USE_GNUTLS} = "y";                                      # Use gnutls.
+}
+$config{USE_OPENSSL}   = "n";                                          # Use openssl.
+if (defined $opt_use_openssl)
+{
+       $config{USE_OPENSSL} = "y";
+}
+
+# no, let's not change these.
+$config{OPTIMITEMP}     = "0";                                         # Default Optimisation Value
+if (!defined $opt_disable_debug)
+{
+       $config{OPTIMISATI}      = "-g1";                               # Optimisation Flag
+}
+else
+{
+       $config{OPTIMISATI}      = "-O2";                               # DEBUGGING OFF!
+}
+
+$config{NICK_LENGT}     = "31";                                        # Default Nick Length
+if (defined $opt_nick_length)
+{
+       $config{NICK_LENGT} = $opt_nick_length;
+}
+$config{CHAN_LENGT}     = "64";                                        # Default Channel Name Length
+if (defined $opt_chan_length)
+{
+       $config{CHAN_LENGT} = $opt_chan_length;
+}
+$config{MAXI_MODES}     = "20";                                        # Default Max. Number of Modes set at once.
+if (defined $opt_modes)
+{
+       $config{MAXI_MODES} = $opt_modes;
+}
+$config{HAS_STRLCPY}   = "false";                                      # strlcpy Check.
+$config{HAS_STDINT}     = "false";                                     # stdint.h check
+$config{USE_KQUEUE}     = "y";                                         # kqueue enabled
+if (defined $opt_kqueue)
+{
+       $config{USE_KQUEUE} = "y";
+}
+if (defined $opt_nokqueue)
+{
+       $config{USE_KQUEUE} = "n";
+}
+$config{USE_EPOLL}       = "y";                                        # epoll enabled
+if (defined $opt_epoll)
+{
+       $config{USE_EPOLL} = "y";
+}
+if (defined $opt_noepoll)
+{
+       $config{USE_EPOLL} = "n";
+}
+$config{USE_PORTS}       = "y";                                        # epoll enabled
+if (defined $opt_ports)
+{
+       $config{USE_PORTS} = "y";
+}
+if (defined $opt_noports)
+{
+       $config{USE_PORTS} = "n";
+}
+$config{IPV6}         = "n";                                           # IPv6 support (experimental)
+if (defined $opt_ipv6)
+{
+       $config{IPV6} = "y";
+}
+$config{SUPPORT_IP6LINKS}   = "y";                                     # IPv4 supporting IPv6 links (experimental)
+if (defined $opt_ipv6links)
+{
+       $config{SUPPORT_IP6LINKS} = "y";
+}
+if (defined $opt_noipv6links)
+{
+       $config{SUPPORT_IP6LINKS} = "n";
+}
+$config{STATIC_LINK}       = "no";                                     # are doing static modules?
+chomp($config{MAX_CLIENT_T} = `sh -c \"ulimit -n\"`);                  # FD Limit
+chomp($config{MAX_DESCRIPTORS} = `sh -c \"ulimit -n\"`);               # Hard FD Limit
+chomp($config{GCCVER}       = `g++ -dumpversion | cut -c 1`);          # Major GCC Version
+$config{_SOMAXCONN} = SOMAXCONN;                                       # Max connections in accept queue
+$config{OSNAME}            = $^O;                                      # Operating System Name
+$config{IS_DARWIN}          = "NO";                                    # Is OSX?
+$config{STARTSCRIPT}          = "inspircd";                    # start script?
+$config{DESTINATION}          = "BASE";                                # Is target path.
+$config{EXTRA_DIR}          = "";                                              # Is empty.
+if ($config{OSNAME} =~ /darwin/i)
+{
+       $config{IS_DARWIN} = "YES";
+       $config{STARTSCRIPT}          = "org.inspircd.plist";           # start script for OSX.
+       $config{DESTINATION}          = "LAUNCHDPATH";                          # Is OSX target.
+       $config{EXTRA_DIR}            = " launchd_dir";                         # Is OSX specific path.
+}
+$config{CC}                = "g++";                                            # C++ compiler
+if (defined $opt_cc)
+{
+       $config{CC} = $opt_cc;
+}
+$exec = $config{CC} . " -dumpversion | cut -c 1";
+chomp($config{GCCVER}          = `$exec`);                             # Major GCC Version
+$config{MAKEORDER}             = "ircd mods";                          # build order
+$config{STATICLIBS}            = "";                                   # library archive path
+$config{MAX_IDENT}             = "12";                                 # max ident size
+$config{MAX_QUIT}              = "255";                                # max quit message size
+$config{MAX_TOPIC}             = "307";                                # max topic size
+$config{MAX_KICK}              = "255";                                # max kick message size
+$config{MAX_GECOS}             = "128";                                # max GECOS size
+$config{MAX_AWAY}              = "200";                                # max AWAY size
+$config{MAXBUF}                        = "512";                                # Max buffer size
+if (defined $opt_ident)
+{
+       $config{MAX_IDENT} = $opt_ident;
+}
+if (defined $opt_quit)
+{
+       $config{MAX_QUIT} = $opt_quit;
+}
+if (defined $opt_topic)
+{
+       $config{MAX_TOPIC} = $opt_topic;
+}
+if (defined $opt_kick)
+{
+       $config{MAX_KICK} = $opt_kick;
+}
+if (defined $opt_gecos)
+{
+       $config{MAX_GECOS} = $opt_gecos;
+}
+if (defined $opt_away)
+{
+       $config{MAX_AWAY} = $opt_away;
+}
+
+$config{HAS_OPENSSL} =~ /^([-[:digit:].]+)([a-z])?(\-[a-z][0-9])?$/;
+$config{HAS_OPENSSL} = $1;
+
+if ($config{GCCVER} eq "") {
+       print $config{CC} . " was not found! You require g++ (the GNU C++ compiler, part of GCC) to build InspIRCd!\n";
+       exit;
+}
+
+# Minihack! Convert Cygwin to 'Cyg-Static' so i can
+# Keep my dynamic module experiments here for later
+# consideration!
+
+if ($config{OSNAME} =~ /CYGWIN/i)
+{
+       $config{OSNAME} = "CYG-STATIC";
+}
+
+if (!$config{MAX_CLIENT_T}) { 
+       $config{MAX_CLIENT_T} = 1024;                            # Set a reasonable 'Default'
+       $fd_scan_fail = "true";                                # Used Later
+}
+
+# Get and Set some important vars..
+getmodules();
+
+sub clean
+{
+       system("rm -rf .config.cache");
+}
+
+sub update
+{
+       eval {
+               chomp($topdir = getcwd());
+               $this = resolve_directory($topdir);                                          # PWD, Regardless.
+               getmodules();
+               # Does the cache file exist?
+               if (!getcache()) {
+                       # No, No it doesn't.. *BASH*
+                       print "You have not run ./configure before. Please do this before trying to run the update script.\n";
+                       exit 0;
+               } else {
+                       # We've Loaded the cache file and all our variables..
+                       print "Updating Files..\n";
+                       getosflags();
+                       if ($opt_disable_debug == 1)
+                       {
+                               print "Disabling debug information (-g).\n";
+                               $config{OPTIMISATI} = "";
+                               getosflags();
+                       }
+                       $has_epoll = $config{HAS_EPOLL};
+                       $has_ports = $config{HAS_PORTS};
+                       $has_kqueue = $config{HAS_KQUEUE};
+                       writefiles(1);
+                       makecache();
+                       print "Complete.\n";
+                       exit;
+               }
+       };
+       if ($@)
+       {
+               print "Configure update failed: $@\n";
+       }
+       exit;
+}
+
+sub modupdate
+{
+       eval {
+               chomp($topdir = getcwd());
+               $this = resolve_directory($topdir);                                          # PWD, Regardless.
+               getmodules();
+               # Does the cache file exist?
+               if (!getcache()) {
+                       # No, No it doesn't.. *BASH*
+                       print "You have not run ./configure before. Please do this before trying to run the update script.\n";
+                       exit 0;
+               } else {
+                       # We've Loaded the cache file and all our variables..
+                       print "Updating Files..\n";
+                       getosflags();
+                       $has_epoll = $config{HAS_EPOLL};
+                       $has_ports = $config{HAS_PORTS};
+                       $has_kqueue = $config{HAS_KQUEUE};
+                       writefiles(0);
+                       makecache();
+                       print "Complete.\n";
+                       exit;
+               }
+       };
+       if ($@)
+       {
+               print "Module update failed: $@\n";
+       }
+       exit;
+}
+
+
+
+sub svnupdate
+{
+       my $fail = 0;
+       open(FH,"<.svn/entries") or $fail = 1;
+       if ($fail) {
+               print "This is not an SVN copy of InspIRCd.\n";
+               exit;
+       }
+       else
+       {
+               close(FH);
+       }
+       system("svn update");
+       system("perl configure -update");
+       if (defined $opt_rebuild) {
+               system("make install");
+       }
+       exit;
+}
+
+print "Running non-interactive configure...\n" unless $interactive;
+print "Checking for cache from previous configure... ";
+print ((getcache() eq "true") ? "found\n" : "not found\n");
+print "Checking operating system version... ";
+print getosflags() . "\n";
+
+if (defined $opt_maxclients)
+{
+       $config{MAX_CLIENT} = $opt_maxclients;
+}
+
+if (!$config{MAX_CLIENT}) { 
+       # If the cache hasn't set the max clients, copy the variable of MAX_CLIENT_T, this
+       # allows us to keep _T for testing purposes. (ie. "Are you sure you want to go
+       # higher than the found value" :))
+       $config{MAX_CLIENT} = $config{MAX_CLIENT_T};
+}
+
+printf "Checking if stdint.h exists... ";
+$config{HAS_STDINT} = "true";
+my $fail = 0;
+open(STDINT, "</usr/include/stdint.h") or $config{HAS_STDINT} = "false";
+if ($config{HAS_STDINT} eq "true") {
+       close(STDINT);
+}
+print "yes\n" if $config{HAS_STDINT} eq "true";
+print "no\n" if $config{HAS_STDINT} eq "false";
+
+
+printf "Checking if strlcpy exists... ";
+# Perform the strlcpy() test..
+$config{HAS_STRLCPY} = "false";
+my $fail = 0;
+open(STRLCPY, "</usr/include/string.h") or $fail = 1;
+if (!$fail) {
+       while (chomp($line = <STRLCPY>)) {
+               # try and find the delcaration of:
+               # size_t strlcpy(...)
+               if ($line =~ /size_t(\0x9|\s)+strlcpy/) {
+                       $config{HAS_STRLCPY} = "true";
+               }
+       }
+       close(STRLCPY);
+}
+print "yes\n" if $config{HAS_STRLCPY} eq "true";
+print "no\n" if $config{HAS_STRLCPY} eq "false";
+
+
+printf "Checking if kqueue exists... ";
+$has_kqueue = 0;
+$fail = 0;
+open(KQUEUE, "</usr/include/sys/event.h") or $fail = 1;
+if (!$fail) {
+       while (chomp($line = <KQUEUE>)) {
+               # try and find the delcaration of:
+               # int kqueue(void);
+               if ($line =~ /int(\0x9|\s)+kqueue/) {
+                       $has_kqueue = 1;
+               }
+       }
+       close(KQUEUE);
+}
+print "yes\n" if $has_kqueue == 1;
+print "no\n" if $has_kqueue == 0;
+
+printf "Checking if epoll exists... ";
+$has_epoll = 0;
+$fail = 0;
+open(EPOLL, "</usr/include/sys/epoll.h") or $fail = 1;
+if (!$fail) {
+       $has_epoll = 1;
+       close(EPOLL);
+}
+if ($has_epoll) {
+       my $kernel = `uname -r`;
+       chomp($kernel);
+       if (($kernel =~ /^2\.0\./) || ($kernel =~ /^2\.2\./) || ($kernel =~ /^2\.4\./)) {
+               $has_epoll = 0;
+       }
+}
+print "yes\n" if $has_epoll == 1;
+print "no\n" if $has_epoll == 0;
+
+printf "Checking if Solaris I/O completion ports are available... ";
+$has_ports = 0;
+my $system = `uname -s`;
+chomp ($system);
+$has_ports = 1 if ($system eq "SunOS");
+
+if ($has_ports) {
+       my $kernel = `uname -r`;
+       chomp($kernel);
+       if (($kernel !~ /^5\.1./)) {
+               $has_ports = 0;
+       }
+}
+print "yes\n" if $has_ports == 1;
+print "no\n" if $has_ports == 0;
+
+if (($config{OSNAME} =~ /CYGWIN/) || ($config{OSNAME} eq "CYG-STATIC")) {
+       $config{HAS_STRLCPY} = "true";
+}
+
+$config{HAS_EPOLL} = $has_epoll;
+$config{HAS_KQUEUE} = $has_kqueue; 
+
+printf "Checking for libgnutls... ";
+if (($config{HAS_GNUTLS}) && (($config{HAS_GNUTLS} >= 1.2) || ($config{HAS_GNUTLS} eq "y"))) {
+       print "yes\n";
+       $config{HAS_GNUTLS} = "y";
+} else {
+       print "no\n";
+       $config{HAS_GNUTLS} = "n";
+}
+
+printf "Checking for openssl... ";
+if (($config{HAS_OPENSSL}) && (($config{HAS_OPENSSL} >= 0.8) || ($config{HAS_OPENSSL} eq "y"))) {
+       print "yes\n";
+       $config{HAS_OPENSSL} = "y";
+} else {
+       print "no\n";
+       $config{HAS_OPENSSL} = "n";
+}
+
+################################################################################
+#                        BEGIN INTERACTIVE PART                              #
+################################################################################
+
+# Clear the Screen..
+if ($interactive)
+{
+       system("clear");
+       $wholeos = $^O;
+
+       my $rev = getrevision();
+       # Display Introduction Message..
+       print "
+Welcome to the \033[1mInspIRCd\033[0m Configuration program! (\033[1minteractive mode\033[0m)
+\033[1mPackage maintainers: Type ./configure --help for non-interactive help\033[0m
+
+*** If you are unsure of any of these values, leave it blank for    ***
+*** standard settings that will work, and your server will run      ***
+*** using them. Please consult your IRC network admin if in doubt.  ***
+
+Press \033[1m<RETURN>\033[0m to accept the default for any option, or enter
+a new value. Please note: You will \033[1mHAVE\033[0m to read the docs
+dir, otherwise you won't have a config file!
+
+Your operating system is: \033[1;32m$config{OSNAME}\033[0m ($wholeos)
+Maximum file descriptors: \033[1;32m$config{MAX_CLIENT_T}\033[0m
+Your InspIRCd revision ID is \033[1;32mr$rev\033[0m";
+       if ($rev eq "r0") {
+               print " (Non-SVN build)";
+       }
+       print ".\n\n";
+
+       $config{CHANGE_COMPILER} = "n";
+       print "I have detected the following compiler: \033[1;32m$config{CC}\033[0m (version \033[1;32m$config{GCCVER}.x\033[0m)\n";
+
+       while (($config{GCCVER} < 3) || ($config{GCCVER} eq "")) {
+               print "\033[1;32mIMPORTANT!\033[0m A GCC 2.x compiler has been detected, and
+should NOT be used. You should probably specify a newer compiler.\n\n";
+               yesno(CHANGE_COMPILER,"Do you want to change the compiler?");
+               if ($config{CHANGE_COMPILER} =~ /y/i) {
+                       print "What command do you want to use to invoke your compiler?\n";
+                       print "[\033[1;32m$config{CC}\033[0m] -> ";
+                       chomp($config{CC} = <STDIN>);
+                       if ($config{CC} eq "") {
+                               $config{CC} = "g++";
+                       }
+                       chomp($foo = `$config{CC} -dumpversion | cut -c 1`);
+                       if ($foo ne "") {
+                               chomp($config{GCCVER}       = `$config{CC} -dumpversion | cut -c 1`); # we must redo these if we change compilers
+                               print "Queried compiler: \033[1;32m$config{CC}\033[0m (version \033[1;32m$config{GCCVER}.x\033[0m)\n";
+                               if ($config{GCCVER} < 3) {
+                                       print "\033[1;32mGCC 2.x WILL NOT WORK!\033[0m. Let's try that again, shall we?\n";
+                               }
+                       }
+                       else {
+                               print "\033[1;32mWARNING!\033[0m Could not execute the compiler you specified. You may want to try again.\n";
+                       }
+               }
+       }
+
+       print "\n";
+
+       # Directory Settings..
+       my $tmpbase = $config{BASE_DIR};
+       dir_check("do you wish to install the InspIRCd base", "BASE_DIR");
+       if ($tmpbase ne $config{BASE_DIR}) {
+               $config{CONFIG_DIR}      = resolve_directory($config{BASE_DIR}."/conf");           # Configuration Dir
+               $config{MODULE_DIR}      = resolve_directory($config{BASE_DIR}."/modules");     # Modules Directory
+               $config{BINARY_DIR}      = resolve_directory($config{BASE_DIR}."/bin");     # Binary Directory
+               $config{LIBRARY_DIR}    = resolve_directory($config{BASE_DIR}."/lib");      # Library Directory
+       }
+
+       dir_check("are the configuration files", "CONFIG_DIR");
+       dir_check("are the modules to be compiled to", "MODULE_DIR");
+       dir_check("is the IRCd binary to be placed", "BINARY_DIR");
+       dir_check("are the IRCd libraries to be placed", "LIBRARY_DIR");
+
+       if ($has_kqueue) {
+               yesno(USE_KQUEUE,"You are running a BSD operating system, and kqueue\nwas detected. Would you like to enable kqueue support?\nThis is likely to increase performance.\nIf you are unsure, answer yes.\n\nEnable kqueue?");
+               print "\n";
+       }
+       if ($has_epoll) {
+               yesno(USE_EPOLL,"You are running a Linux 2.6+ operating system, and epoll\nwas detected. Would you like to enable epoll support?\nThis is likely to increase performance.\nIf you are unsure, answer yes.\n\nEnable epoll?");
+               print "\n";
+       }
+       if ($has_ports) {
+               yesno(USE_PORTS,"You are running Solaris 10.\nWould you like to enable I/O completion ports support?\nThis is likely to increase performance.\nIf you are unsure, answer yes.\n\nEnable support for I/O completion ports?");
+               print "\n";
+       }
+       $chose_hiperf = (($config{USE_EPOLL} eq "y") || ($config{USE_KQUEUE} eq "y") || ($config{USE_PORTS} eq "y"));
+       if (!$chose_hiperf) {
+               print "No high-performance socket engines are available, or you chose\n";
+               print "not to enable one. Defaulting to select() engine.\n\n";
+       }
+
+       yesno(IPV6,"Would you like to build InspIRCd with IPv6 support?");
+       print "\n";
+
+       if ($config{IPV6} eq "y") {
+               print "You have chosen to build an \033[1;32mIPV6-enabled\033[0m server.\nTo accept IPV4 users, you can still use IPV4 addresses\nin your port bindings..\n\n";
+               $config{SUPPORT_IP6LINKS} = "y";
+       } else {
+               yesno(SUPPORT_IP6LINKS,"You have chosen to build an \033[1;32mIPV4-only\033[0m server.\nWould you like to enable support for linking to IPV6-enabled\nInspIRCd servers?\nIf you are using a recent operating\nsystem and are unsure, answer yes.\nIf you answer 'no' here, your InspIRCd server will be unable\nto parse IPV6 addresses (e.g. for CIDR bans)");
+               print "\n";
+       }
+
+       if (($config{HAS_GNUTLS} eq "y") && ($config{HAS_OPENSSL} eq "y")) {
+               print "I have detected both \033[1;32mGnuTLS\033[0m and \033[1;32mOpenSSL\033[0m on your system.\n";
+               print "I will default to GnuTLS. If you wish to use OpenSSL\n";
+               print "instead, you should enable the OpenSSL module yourself\n";
+               print "by copying it from src/modules/extra to src/modules.\n\n";
+               print "Detected GnuTLS version: \033[1;32m" . $gnutls_ver . "\033[0m\n";
+               print "Detected OpenSSL version: \033[1;32m" . $openssl_ver . "\033[0m\n\n";
+       }
+
+       if ($config{HAS_GNUTLS} eq "y") {
+               yesno(USE_GNUTLS, "Would you like to enable SSL Support?");
+               if ($config{USE_GNUTLS} eq "y") {
+                       print "\nUsing GnuTLS SSL module.\n";
+               }
+       } elsif ($config{HAS_OPENSSL} eq "y") {
+                       yesno(USE_OPENSSL, "Would you like to enable SSL Support?");
+       if ($config{USE_OPENSSL} eq "y") {
+                       print "\nUsing OpenSSL SSL module.\nYou will get better performance if you move to GnuTLS in the future.\n";
+               }
+       }
+       else {
+               print "\nCould not detect OpenSSL or GnuTLS. Make sure pkg-config is installed if\nyou intend to use OpenSSL, or that GnuTLS is in your path if you intend\nto use GnuTLS.\n\n";
+       }
+
+       print "\nThe following questions will ask you for various figures relating\n";
+       print "To your IRCd install. Please note that these should usually be left\n";
+       print "as defaults unless you have a real reason to change them. If they\n";
+       print "changed, then the values must be identical on all servers on your\n";
+       print "network, or malfunctions and/or crashes may occur, with the exception\n";
+       print "of the 'maximum number of clients' setting which may be different on\n";
+       print "different servers on the network.\n\n";
+
+       # File Descriptor Settings..
+       promptnumeric("number of clients at any one time", "MAX_CLIENT_T");
+       $config{MAX_CLIENT} = $config{MAX_CLIENT_T};
+       $config{MAX_DESCRIPTORS} = $config{MAX_CLIENT_T};
+
+       promptnumeric("length of nicknames", "NICK_LENGT");
+       promptnumeric("length of channel names", "CHAN_LENGT");
+       promptnumeric("number of mode changes in one line", "MAXI_MODES");
+       promptnumeric("length of an ident (username)", "MAX_IDENT");
+       promptnumeric("length of a quit message", "MAX_QUIT");
+       promptnumeric("length of a channel topic", "MAX_TOPIC");
+       promptnumeric("length of a kick message", "MAX_KICK");
+       promptnumeric("length of a GECOS (real name)", "MAX_GECOS");
+       promptnumeric("length of an away message", "MAX_AWAY");
+}
+
+dumphash();
+
+if (($config{USE_GNUTLS} eq "y") && ($config{HAS_GNUTLS} ne "y"))
+{
+       print "Sorry, but i couldn't detect gnutls. Make sure gnutls-config is in your path.\n";
+       exit(0);
+}
+if (($config{USE_OPENSSL} eq "y") && ($config{HAS_OPENSSL} ne "y"))
+{
+       print "Sorry, but i couldn't detect openssl. Make sure openssl is in your path.\n";
+       exit(0);
+}
+
+if ($config{USE_GNUTLS} eq "y") {
+       $failed = 0;
+       open(TMP, "<src/modules/m_ssl_gnutls.cpp") or $failed = 1;
+       close(TMP);
+       if ($failed) {
+               print "Symlinking src/modules/m_ssl_gnutls.cpp from extra/\n";
+               chdir("src/modules");
+               system("ln -s extra/m_ssl_gnutls.cpp");
+               chdir("../..");
+       }
+       getmodules();
+       if ($interactive)
+       {
+               $failed = 0;
+               open(TMP, "<$config{CONFIG_DIR}/key.pem") or $failed = 1;
+               close(TMP);
+               open(TMP, "<$config{CONFIG_DIR}/cert.pem") or $failed = 1;
+               close(TMP);
+               if ($failed) {
+                       print "SSL Certificates Not found, Generating.. \n\n
+*************************************************************
+* Generating the Private Key may take some time, go grab a  *
+* Coffee. Even better, to generate some more entropy if it  *
+* is taking a while, open another console and type du / a   *
+* few times and get that HD going :) Then answer the        *
+* Questions which follow. If you are unsure, just hit enter *
+*************************************************************\n\n";
+                       make_gnutls_cert() or $failed = 1;
+                       if (!$failed) {
+                               print "\nCertificate generation complete, copying to config directory... ";
+                               system("mv key.pem $config{CONFIG_DIR}/key.pem");
+                               system("mv cert.pem $config{CONFIG_DIR}/cert.pem");
+                               print "Done.\n\n";
+                       } else {
+                               print "\n\033[1;32mCertificate generation failed!\033[0m\n\n";
+                       }
+               }
+               else {
+                       print "SSL Certificates found, skipping.\n\n";
+               }
+       }
+       else
+       {
+               print "Skipping SSL certificate generation\nin non-interactive mode.\n\n";
+       }
+} elsif ($config{USE_OPENSSL} eq "y") {
+       $failed = 0;
+       open(TMP, "<src/modules/m_ssl_openssl.cpp") or $failed = 1;
+       close(TMP);
+       if ($failed) {
+               print "Symlinking src/modules/m_ssl_openssl.cpp from extra/\n";
+               chdir("src/modules");
+               system("ln -s extra/m_ssl_openssl.cpp");
+               chdir("../..");
+       }
+       getmodules();
+       $failed = 0;
+       if ($interactive)
+       {
+               open(TMP, "<$config{CONFIG_DIR}/key.pem") or $failed = 1;
+               close(TMP);
+               open(TMP, "<$config{CONFIG_DIR}/cert.pem") or $failed = 1;
+               close(TMP);
+               if ($failed) {
+                       print "SSL Certificates Not found, Generating.. \n\n
+*************************************************************
+* Generating the certificates may take some time, go grab a *
+* coffee, or something.                                     *
+*************************************************************\n\n";
+                       make_openssl_cert();
+                       print "\nCertificate generation complete, copying to config directory... ";
+                       system("mv key.pem $config{CONFIG_DIR}/key.pem");
+                       system("mv cert.pem $config{CONFIG_DIR}/cert.pem");
+                       system("mv dhparams.pem $config{CONFIG_DIR}/dhparams.pem");
+                       print "Done.\n\n";
+               } else {
+                       print "SSL Certificates found, skipping.\n\n"
+               }
+       }
+       else
+       {
+               print "Skipping SSL certificate generation\nin non-interactive mode.\n\n";
+       }
+}
+if (($config{USE_GNUTLS} eq "n") && ($config{USE_OPENSSL} eq "n")) {
+       print "Skipping SSL Certificate generation, SSL support is not available.\n\n";
+}
+
+getosflags();
+writefiles(1);
+makecache();
+
+print "\n\n";
+print "To build your server with these settings, please type '\033[1;32m$config{MAKEPROG}\033[0m' now.\n";
+if (($config{USE_GNUTLS} eq "y") || ($config{USE_OPENSSL} eq "y")) {
+       print "Please remember that to enable \033[1;32mSSL support\033[0m you must\n";
+       print "load the required modules in your config. This configure process\n";
+       print "has just prepared these modules to be compiled for you, and has not\n";
+       print "configured them to be compiled into the core of the ircd.\n";
+}
+print "*** \033[1;32mRemember to edit your configuration files!!!\033[0m ***\n\n\n";
+if (($config{OSNAME} eq "OpenBSD") && ($config{CC} ne "eg++")) {
+       print "\033[1;32mWARNING!\033[0m You are running OpenBSD but you are using the base gcc package\nrather than eg++. This compile will most likely fail, but i'm letting you\ngo ahead with it anyway, just in case i'm wrong :-)\n";
+}
+
+if ($config{GCCVER} < "3") {
+       print <<FOO2;
+\033[1;32mWARNING!\033[0m You are attempting to compile InspIRCd on GCC 2.x!
+GCC 2.x series compilers only had partial (read as broken) C++ support, and
+your compile will most likely fail horribly! If you have any problems, do NOT
+report them to the bugtracker or forums without first upgrading your compiler
+to a newer 3.x or 4.x (or whatever is available currently) version.
+FOO2
+}
+
+################################################################################
+#                            HELPER FUNCTIONS                          #
+################################################################################
+sub getcache {
+       # Retrieves the .config.cache file, and loads values into the main config hash.
+       open(CACHE, ".config.cache") or return undef;
+       while (<CACHE>) {
+               chomp;
+               # Ignore Blank lines, and comments..
+               next if /^\s*$/;
+               next if /^\s*#/;
+               my ($key, $value) = split("=", $_, 2);
+               $value =~ /^\"(.*)\"$/;
+               # Do something with data here!
+               $config{$key} = $1;
+       }
+       close(CONFIG);
+       return "true";
+}
+
+sub makecache {
+       # Dump the contents of %config
+       print "Writing \033[1;32mcache file\033[0m for future ./configures ...\n";
+       open(FILEHANDLE, ">.config.cache");
+       foreach $key (keys %config) {
+               print FILEHANDLE "$key=\"$config{$key}\"\n";
+       }
+       close(FILEHANDLE);
+}
+
+sub dir_check {
+       my ($desc, $hash_key) = @_;
+       my $complete = 0;
+       while (!$complete) {
+               print "In what directory $desc?\n";
+               print "[\033[1;32m$config{$hash_key}\033[0m] -> ";
+               chomp($var = <STDIN>);
+               if ($var eq "") {
+                       $var = $config{$hash_key};
+               }
+               if ($var =~ /^\~\/(.+)$/) {
+                       # Convert it to a full path..
+                       $var = resolve_directory($ENV{HOME} . "/" . $1);
+               }
+               elsif ((($config{OSNAME} =~ /MINGW32/i) and ($var !~ /^[A-Z]{1}:\\.*/)) and (substr($var,0,1) ne "/"))
+               {
+                       # Assume relative Path was given.. fill in the rest.
+                       $var = $this . "/$var";
+               }
+               
+               $var = resolve_directory($var); 
+               if (! -e $var) {
+                       print "$var does not exist. Create it?\n[\033[1;32my\033[0m] ";
+                       chomp($tmp = <STDIN>);
+                       if (($tmp eq "") || ($tmp =~ /^y/i)) {
+                               # Attempt to Create the Dir..
+                               
+                               system("mkdir -p \"$var\" >> /dev/null 2>&1");
+                               $chk = system("mkdir -p \"$var\" >> /dev/null 2>&1") / 256;
+                               if ($chk != 0) {
+                                       print "Unable to create directory. ($var)\n\n";
+                                       # Restart Loop..
+                                       next;
+                               }
+                       } else {
+                               # They said they don't want to create, and we can't install there.
+                               print "\n\n";
+                               next;
+                       }
+               } else {
+                       if (!is_dir($var)) {
+                               # Target exists, but is not a directory.
+                               print "File $var exists, but is not a directory.\n\n";
+                               next;
+                       }
+               }
+               # Either Dir Exists, or was created fine.
+               $config{$hash_key} = $var;
+               $complete = 1;
+               print "\n";
+       }
+}
+
+sub getosflags {
+
+       $config{LDLIBS} = "-lstdc++";
+       $config{FLAGS}  = "-fno-strict-aliasing -fPIC -Wall -Woverloaded-virtual -Wno-deprecated $config{OPTIMISATI}";
+       $config{DEVELOPER} = "-fno-strict-aliasing -fPIC -Wall -Woverloaded-virtual -Wno-deprecated -g";
+       $SHARED = "-Wl,--rpath -Wl,$config{LIBRARY_DIR} -shared";
+       $config{MAKEPROG} = "make";
+
+       if ($config{OSNAME} =~ /darwin/i) {
+               $config{FLAGS}  = "-DDARWIN -frtti -fPIC -Wall -Woverloaded-virtual -Wno-deprecated $config{OPTIMISATI}";
+               $SHARED = "-bundle -twolevel_namespace -undefined dynamic_lookup";
+               $config{LDLIBS} = "-ldl -lstdc++";
+       }
+
+       if ($config{OSNAME} =~ /OpenBSD/i) {
+               $config{MAKEPROG} = "gmake";
+               chomp($foo = `eg++ -dumpversion | cut -c 1`);
+               # theyre running the package version of gcc (eg++)... detect it and set up its version numbers.
+               # if theyre not running this, configure lets the build continue but they probably wont manage to
+               # compile as this standard version is 2.95.3!
+               if ($foo ne "") {
+                       $config{CC} = "eg++";
+                       chomp($config{GCCVER}       = `eg++ -dumpversion | cut -c 1`); # we must redo these if we change the compiler path
+               }
+               return "OpenBSD";
+       }
+
+       if ($config{OSNAME} =~ /Linux/i) {
+               $config{LDLIBS} = "-ldl -lstdc++";
+               $config{FLAGS}  = "-fno-strict-aliasing -fPIC -Wall -Woverloaded-virtual -Wno-deprecated $config{OPTIMISATI}";
+               $config{FLAGS}  .= " " . $ENV{CXXFLAGS} if exists($ENV{CXXFLAGS});
+               $config{LDLIBS} .= " " . $ENV{LDLIBS} if exists($ENV{LDLIBS});
+               $config{MAKEPROG} = "make";
+               if ($config{OSNAME} =~ /CYGWIN/) {
+                       $config{FLAGS}  = "-fno-strict-aliasing -Wall -Woverloaded-virtual -Wno-deprecated $config{OPTIMISATI}";
+                       $config{LDLIBS} = "";
+                       $config{MAKEPROG} = "/usr/bin/make";
+                       $config{MAKEORDER} = "ircd mods";
+                       return "Cygwin";
+               } elsif ($config{OSNAME} eq "CYG-STATIC") {
+                       $config{FLAGS} = "-fno-strict-aliasing -Wall -Woverloaded-virtual -Wno-deprecated $config{OPTIMISATI}";
+                       $config{LDLIBS} = "";
+                       $config{MAKEPROG} = "/usr/bin/make";
+                       $config{MAKEORDER} = "mods ircd";
+                       $config{STATICLIBS} = "modules/mods.a";
+                       $config{STATIC_LINK} = "yes";
+                       return "Cygwin-Static";
+               }
+       }
+
+       if ($config{OSNAME} =~ /FreeBSD/i) {
+               $config{FLAGS}  .= " " . $ENV{CXXFLAGS} if exists($ENV{CXXFLAGS});
+               $config{LDLIBS} .= " " . $ENV{LDLIBS} if exists($ENV{LDLIBS});
+       }
+
+       if ($config{OSNAME} =~ /SunOS/i or $config{OSNAME} =~ /solaris/i)
+       {
+               # solaris/sunos needs these
+               # socket = bsd sockets api
+               # nsl = dns stuff
+               # rt = POSIX realtime extensions
+               # resolv = inet_aton only (why isnt this in nsl?!)
+               $config{MAKEPROG} = "gmake";
+               $config{LDLIBS} .= " -lsocket -lnsl -lrt -lresolv";
+               return "Solaris";
+       }
+       
+       if($config{OSNAME} =~ /MINGW32/i)
+       {
+               # All code is position-independent on windows
+               $config{FLAGS} =~ s/-fPIC //;
+               return "MinGW";
+       }
+
+       return $config{OSNAME};
+}
+
+sub writefiles {
+       my($writeheader) = @_;
+       # First File.. inspircd_config.h
+       chomp(my $incos = `uname -n -s -r`);
+       chomp($version = `sh src/version.sh`);
+       chomp(my $revision2 = getrevision());
+       if ($writeheader == 1)
+       {
+               print "Writing \033[1;32minspircd_config.h\033[0m\n";
+               open(FILEHANDLE, ">include/inspircd_config.h");
+               my $NL = $config{NICK_LENGT}+1;
+               my $CL = $config{CHAN_LENGT}+1;
+               print FILEHANDLE <<EOF;
+/* Auto generated by configure, do not modify! */
+#ifndef __CONFIGURATION_AUTO__
+#define __CONFIGURATION_AUTO__
+
+/* this is for windows support. */
+#define CoreExport /**/
+#define DllExport /**/
+
+#define CONFIG_FILE "$config{CONFIG_DIR}/inspircd.conf"
+#define MOD_PATH "$config{MODULE_DIR}"
+#define VERSION "$version"
+#define REVISION "$revision2"
+#define MAXCLIENTS $config{MAX_CLIENT}
+#define MAXCLIENTS_S "$config{MAX_CLIENT}"
+#define SOMAXCONN_S "$config{_SOMAXCONN}"
+#define MAX_DESCRIPTORS $config{MAX_DESCRIPTORS}
+#define NICKMAX $NL
+#define CHANMAX $CL
+#define MAXMODES $config{MAXI_MODES}
+#define IDENTMAX $config{MAX_IDENT}
+#define MAXQUIT $config{MAX_QUIT}
+#define MAXTOPIC $config{MAX_TOPIC}
+#define MAXKICK $config{MAX_KICK}
+#define MAXGECOS $config{MAX_GECOS}
+#define MAXAWAY $config{MAX_AWAY}
+#define OPTIMISATION $config{OPTIMITEMP}
+#define LIBRARYDIR "$config{LIBRARY_DIR}"
+#define SYSTEM "$incos"
+EOF
+print FILEHANDLE "#define MAXBUF " . ($config{MAXBUF}+2) . "\n";
+
+               if ($config{OSNAME} =~ /SunOS/i) {
+                       print FILEHANDLE "#define IS_SOLARIS\n";
+               }
+               if ($config{OSNAME} =~ /CYGWIN/i) {
+                       print FILEHANDLE "#define IS_CYGWIN\n";
+                       print FILEHANDLE "#ifndef FD_SETSIZE\n#define FD_SETSIZE        1024\n#endif\n";
+               }
+               if ($config{OSNAME} =~ /MINGW32/i) {
+                       print FILEHANDLE "#define IS_MINGW\n";
+               }
+               if ($config{OSNAME} =~ /CYG-STATIC/i) {
+                       print FILEHANDLE "#ifndef FD_SETSIZE\n#define FD_SETSIZE    1024\n#endif\n";
+               }
+               if ($config{STATIC_LINK} eq "yes") {
+                       print FILEHANDLE "#define STATIC_LINK\n";
+               }
+               if ($config{GCCVER} >= 3) {
+                       print FILEHANDLE "#define GCC3\n";
+               }
+               if ($config{HAS_STRLCPY} eq "true") {
+                       print FILEHANDLE "#define HAS_STRLCPY\n";
+               }
+               if ($config{HAS_STDINT} eq "true") {
+                       print FILEHANDLE "#define HAS_STDINT\n";
+               }
+               if ($config{IPV6} =~ /y/i) {
+                       print FILEHANDLE "#define IPV6\n";
+               }
+               if ($config{SUPPORT_IP6LINKS} =~ /y/i) {
+                       print FILEHANDLE "#define SUPPORT_IP6LINKS\n";
+               }
+               my $use_hiperf = 0;
+               if (($has_kqueue) && ($config{USE_KQUEUE} eq "y")) {
+                       print FILEHANDLE "#define USE_KQUEUE\n";
+                       $se = "socketengine_kqueue";
+                       $use_hiperf = 1;
+               }
+               if (($has_epoll) && ($config{USE_EPOLL} eq "y")) {
+                       print FILEHANDLE "#define USE_EPOLL\n";
+                       $se = "socketengine_epoll";
+                       $use_hiperf = 1;
+               }
+               if (($has_ports) && ($config{USE_PORTS} eq "y")) {
+                       print FILEHANDLE "#define USE_PORTS\n";
+                       $se = "socketengine_ports";
+                       $use_hiperf = 1;
+               }
+               # user didn't choose either epoll or select for their OS.
+               # default them to USE_SELECT (ewwy puke puke)
+               if (!$use_hiperf) {
+                       print FILEHANDLE "#define USE_SELECT\n";
+                       $se = "socketengine_select";
+               }
+               print FILEHANDLE "\n#endif\n";
+               close(FILEHANDLE);
+       }
+
+       if ($writeheader)
+       {
+               open(FILEHANDLE, ">include/inspircd_se_config.h");
+               print FILEHANDLE <<EOF;
+/* Auto generated by configure, do not modify or commit to svn! */
+#ifndef __CONFIGURATION_SOCKETENGINE__
+#define __CONFIGURATION_SOCKETENGINE__
+
+#include "$se.h"
+
+#endif
+EOF
+               close(FILEHANDLE);
+       }
+
+
+       # Create a Modules List..
+       my $modules = "";
+       foreach $i (@modlist)
+       {
+               if ($config{STATIC_LINK} eq "yes") {
+                       $modules .= "m_".$i.".o ";
+               }
+               else {
+                       $modules .= "m_".$i.".so ";
+               }
+       }
+       chomp($modules);   # Remove Redundant whitespace..
+
+       opendir(DIRHANDLE, "src/modules");
+       foreach $name (sort readdir(DIRHANDLE)) {
+               if ($name =~ /^m_(.+?)$/) {
+                       if (opendir(MDIRHANDLE, "src/modules/$name") != 0) {
+                               closedir(MDIRHANDLE);
+                               $modules .= "$name.so ";
+                       }
+               }
+       }
+       closedir(DIRHANDLE);
+
+
+       # Write all .in files.
+       my $tmp = "";
+       my $file = "";
+       my $exe = "inspircd";
+
+       if ($config{OSNAME} =~ /CYGWIN/i) {
+               $exe = "inspircd.exe";
+       }
+
+       opendir(DIRHANDLE, $this);
+
+       # Do this once here, and cache it in the .*.inc files,
+       # rather than attempting to read src/version.sh from
+       # compiled code -- we might not have the source to hand.
+       # Fix for bug#177 by Brain.
+
+       chomp(my $version = `sh ./src/version.sh`);
+       chomp(my $revision = getrevision());
+       $version = "$version(r$revision)";
+
+       my $LIBEXT = "so";
+       if ($config{IS_DARWIN} eq "YES")
+       {
+               $LIBEXT = "dylib";
+       }
+       # We can actually parse any file starting with . and ending with .inc,
+       # but right now we only parse .inspircd.inc to form './inspircd'
+
+       foreach $name (sort readdir(DIRHANDLE)) {
+               if ($name =~ /^\.(.+)\.inc$/) {
+                       $file = $1;
+                       # All .name.inc files need parsing!
+                       $tmp = "";
+                       open(FILEHANDLE, ".$file.inc");
+                       while (<FILEHANDLE>) {
+                               $tmp .= $_;
+                       }
+                       close(FILEHANDLE);
+
+                       $tmp =~ s/\@CC\@/$config{CC}/;
+                       $tmp =~ s/\@MAKEPROG\@/$config{MAKEPROG}/;
+                       $tmp =~ s/\@FLAGS\@/$config{FLAGS}/;
+                       $tmp =~ s/\@DEVELOPER\@/$config{DEVELOPER}/;
+                       $tmp =~ s/\@LDLIBS\@/$config{LDLIBS}/;
+                       $tmp =~ s/\@BASE_DIR\@/$config{BASE_DIR}/;
+                       $tmp =~ s/\@CONFIG_DIR\@/$config{CONFIG_DIR}/;
+                       $tmp =~ s/\@MODULE_DIR\@/$config{MODULE_DIR}/;
+                       $tmp =~ s/\@BINARY_DIR\@/$config{BINARY_DIR}/;
+                       $tmp =~ s/\@LIBRARY_DIR\@/$config{LIBRARY_DIR}/;
+                       $tmp =~ s/\@LIBRARY_EXT\@/$LIBEXT/;
+                       $tmp =~ s/\@MODULES\@/$modules/;
+                       $tmp =~ s/\@STARTSCRIPT\@/$config{STARTSCRIPT}/;
+                       $tmp =~ s/\@DESTINATION\@/$config{DESTINATION}/;
+                       $tmp =~ s/\@EXTRA_DIR\@/$config{EXTRA_DIR}/;
+                       $tmp =~ s/\@EXECUTABLE\@/$exe/;
+                       $tmp =~ s/\@MAKEORDER\@/$config{MAKEORDER}/;
+                       $tmp =~ s/\@STATICLIBS\@/$config{STATICLIBS}/;
+                       $tmp =~ s/\@VERSION\@/$version/;
+
+                       print "Writing \033[1;32m$file\033[0m\n";
+                       open(FILEHANDLE, ">$file");
+                       print FILEHANDLE $tmp;
+               }
+       }
+       closedir(DIRHANDLE);
+
+       # Make inspircd executable!
+       chmod 0744, 'inspircd';
+
+       if ($config{STATIC_LINK} eq "yes") {
+               print "Writing static-build \033[1;32msrc/Makefile\033[0m\n";
+               write_static_makefile();
+               write_static_modules_makefile();
+       } elsif ($config{OSNAME} =~ /CYGWIN/i) {
+               print "Writing cygwin-build \033[1;32msrc/Makefile\033[0m\n";
+               write_static_makefile();
+               write_dynamic_modules_makefile();
+       } else {
+               print "Writing dynamic-build \033[1;32msrc/Makefile\033[0m\n";
+               write_dynamic_makefile();
+               write_dynamic_modules_makefile();
+       }
+}
+
+sub write_static_modules_makefile {
+       # Modules Makefile..
+       print "Writing \033[1;32msrc/modules/Makefile\033[0m\n";
+       open(FILEHANDLE, ">src/modules/Makefile");
+
+       ###
+       # Module Makefile Header
+       ###
+       print FILEHANDLE <<EOF;
+# (C) ChatSpike development team
+# Makefile by <Craig\@ChatSpike.net>
+# Many Thanks to Andrew Church <achurch\@achurch.org>
+#    for assisting with making this work right.
+#
+# Automatically Generated by ./configure to add a modules
+# please run ./configure --update
+
+all: \$(MODULES)
+
+EOF
+       ###
+       # End Module Makefile Header
+       ###
+
+       # Create a Modules List..
+       my $modules = "";
+       my $cmflags = "";
+       my $liflags = "";
+
+       open(MODLIST,">include/modlist.h");
+
+       ###
+       # Include File Header
+       ###
+       print MODLIST <<HEADER;
+// Generated automatically by configure. DO NOT EDIT!
+
+#ifndef __SYMBOLS__H_CONFIGURED__
+#define __SYMBOLS__H_CONFIGURED__
+
+HEADER
+       ###
+       # End Include File Header
+       ###
+
+       # Place Module List into Include
+       foreach $i (@modlist) {
+               if ($i !~ /_static$/) {
+                       print MODLIST "extern \"C\" void * $i\_init (void);\n";
+               }
+       }
+       print MODLIST "\nstruct {const char *name; initfunc *value; } modsyms[] = {\n";
+
+       ###
+       # Build Module Crap
+       ###
+       foreach $i (@modlist)
+       {
+               if ($i !~ /_static$/) {
+                       $cmflags = getcompilerflags("src/modules/m_".$i.".cpp");
+                       $liflags = getlinkerflags("src/modules/m_".$i.".cpp");
+                       $deps = getdependencies("src/modules/m_".$i.".cpp");
+
+                       #print "file: $i: cmflags=$cmflags; liflags=$liflags; deps=$deps\n";
+
+                       ###
+                       # Write Entry to the Makefile
+                       ###
+                       print FILEHANDLE <<EOCHEESE;
+m_$i.o: .m_$i\_static.cpp ../../include/modules.h ../../include/users.h ../../include/channels.h ../../include/base.h $deps
+       \$(CC) -pipe -I../../include \$(FLAGS) $flags -export-dynamic -c .m_$i\_static.cpp
+       mv .m_$i\_static.o ../m_$i.o
+
+EOCHEESE
+                       ###
+                       # End Write Entry to the MakeFile
+                       ###
+                       print "Configuring module [\033[1;32mm_$i.so\033[0m] for static linking... ";
+                       open(MODULE,"<src/modules/m_".$i.".cpp") or die("Could not open m_".$i.".cpp");
+                       open(MUNGED,">src/modules/.m_".$i."_static.cpp") or die("Could not create .m_".$i."_static.cpp");
+                       while (chomp($a = <MODULE>)) { 
+                               $a =~ s/init_module/$i\_init/g;
+                               print MUNGED "$a\n";
+                       }
+                       close(MODULE);
+                       close(MUNGED);
+                       print MODLIST <<EOENT;
+{"m_$i.so",\&$i\_init},
+EOENT
+                       print "done\n";
+               }
+       }
+
+       print MODLIST "{0}};\n\n#endif\n";
+       close(MODLIST);
+}
+
+sub write_dynamic_modules_makefile {
+       # Modules Makefile..
+       print "Writing \033[1;32msrc/modules/Makefile\033[0m\n";
+       open(FILEHANDLE, ">src/modules/Makefile");
+       my $extra = "";
+
+       if ($config{OSNAME} =~ /CYGWIN/i) {
+               $extra = "../inspircd.dll.a";
+       }
+
+###
+# Module Makefile Header
+###
+       print FILEHANDLE <<EOF;
+# (C) ChatSpike development team
+# Makefile by <Craig\@ChatSpike.net>
+# Many Thanks to Andrew Church <achurch\@achurch.org>
+#    for assisting with making this work right.
+#
+# Automatically Generated by ./configure to add a modules
+# please run ./configure -update or ./configure -modupdate
+
+all: \$(MODULES)
+
+EOF
+       ###
+       # End Module Makefile Header
+       ###
+
+       # Create a Modules List..
+       my $modules = "";
+       my $cmflags = "";
+       my $liflags = "";
+       my $crud = "";
+
+       foreach $i (@modlist) {
+               ###
+               # Write Entry to the MakeFile
+               ###
+               $cmflags = getcompilerflags("src/modules/m_".$i.".cpp");
+               $liflags = getlinkerflags("src/modules/m_".$i.".cpp");
+               $deps = getdependencies("src/modules/m_".$i.".cpp");
+       
+               #print "file: $i: cmflags=$cmflags; liflags=$liflags; deps=$deps\n";
+       
+               print FILEHANDLE <<EOCHEESE;
+m_$i.so: m_$i.cpp ../../include/modules.h ../../include/users.h ../../include/channels.h ../../include/base.h ../../include/inspircd_config.h ../../include/inspircd.h ../../include/configreader.h $deps
+       \$(CC) -pipe -I../../include \$(FLAGS) $cmflags -export-dynamic -c m_$i.cpp
+EOCHEESE
+
+if ($config{OSNAME} =~ /darwin/) {
+               print FILEHANDLE <<EOCHEESE;
+       \$(CC) -pipe -twolevel_namespace -undefined dynamic_lookup \$(FLAGS) -bundle $liflags -o m_$i.so m_$i.o $extra
+
+EOCHEESE
+} else {
+               print FILEHANDLE <<EOCHEESE;
+       \$(CC) -pipe \$(FLAGS) -shared $liflags -o m_$i.so m_$i.o $extra
+
+EOCHEESE
+}
+               $crud = $crud . "       install -m \$(INSTMODE) m_$i.so \$(MODPATH)\n";
+###
+               # End Write Entry to the MakeFile
+               ###
+       }
+
+       opendir(DIRHANDLE, "src/modules");
+       foreach $name (sort readdir(DIRHANDLE)) {
+               if ($name =~ /^m_(.+?)$/) {
+                       $crapola = "";
+                       $crap3 = "";
+                       # A module made of multiple files, in a dir, e.g. src/modules/m_spanningtree/
+                       if (opendir(MDIRHANDLE, "src/modules/$name") != 0) {
+                               my $i = 0;
+                               print FILEHANDLE "$name.so: ../../include/modules.h ../../include/users.h ../../include/channels.h ../../include/base.h ../../include/inspircd_config.h ../../include/inspircd.h ../../include/configreader.h"; 
+                               foreach $fname (sort readdir(MDIRHANDLE)) {
+                                       if ($fname =~ /\.cpp$/) {
+                                               $cmflags = getcompilerflags("src/modules/$name/$fname");
+                                               $liflags = getlinkerflags("src/modules/$name/$fname");
+                                               $deps = getdependencies("src/modules/$name/$fname");
+                                               $oname = $fname;
+                                               $oname =~ s/\.cpp$/.o/g;
+                                               print FILEHANDLE " $name/$oname";
+                                               $crapola = $crapola .  "$name/$oname: $name/$fname ../../include/modules.h ../../include/users.h ../../include/channels.h ../../include/base.h ../../include/inspircd_config.h ../../include/inspircd.h ../../include/configreader.h $deps\n";
+                                               $crapola = $crapola .  "        \$(CC) -pipe -I../../include -I. \$(FLAGS) $cmflags -export-dynamic -o $name/$oname -c $name/$fname\n\n";
+                                               $crap3 = $crap3 . " $name/$oname";
+                                               $i++;
+                                       }
+                               }
+                               print "Composing Makefile rules for directory \033[1;32m$name\033[0m... (\033[1;32m$i files found\033[0m)\n";
+                               if ($config{IS_DARWIN} eq "YES") {
+                                       print FILEHANDLE "\n    \$(CC) -pipe -twolevel_namespace -undefined dynamic_lookup \$(FLAGS) -bundle -o $name.so $crap3\n"; 
+                               } else {
+                                       print FILEHANDLE "\n    \$(CC) -pipe \$(FLAGS) -shared $liflags -o $name.so $crap3\n";
+                               }
+                               print FILEHANDLE "\n$crapola\n";
+                               closedir(MDIRHANDLE);
+                               $crud = $crud . "       install -m \$(INSTMODE) $name.so \$(MODPATH)\n";
+                       }
+               }
+       }
+       closedir(DIRHANDLE);
+
+       print FILEHANDLE "modinst:\n    \@echo \"Installing modules...\"\n" . $crud;
+}
+
+
+sub write_static_makefile {
+       open(FH,">src/Makefile") or die("Could not write src/Makefile!");
+       my $i = 0;
+       my @cmdlist = ();
+       opendir(DIRHANDLE, "src");
+       foreach $name (sort readdir(DIRHANDLE)) {
+               if ($name =~ /^cmd_(.+)\.cpp$/) {
+                       $cmdlist[$i++] = $1;
+               }
+       }
+       closedir(DIRHANDLE);
+       my $cmdobjs = "";
+       my $srcobjs = "";
+       foreach my $cmd (@cmdlist) {
+               $cmdobjs = $cmdobjs . "cmd_$cmd.o ";
+               $srcobjs = $srcobjs . "cmd_$cmd.cpp ";
+       }
+       print FH <<EOM;
+# Insp Makefile :p
+#
+# (C) ChatSpike development team
+# Makefile by <Craig\@ChatSpike.net>
+# Makefile version 2 (statically linked core) by <brain\@inspircd.org>
+#
+
+CC = im a cheezeball
+
+CXXFLAGS = -I../include \${FLAGS}
+CPPFILES = \$(shell /bin/ls -l modes/ | grep '\\.cpp' | sed 's/^.* //' | grep -v svn)
+RELCPPFILES = \$(shell /bin/ls -l modes/ | grep '\\.cpp' | sed 's/^.* /modes\\//' | grep -v svn)
+
+EOM
+
+$se = "socketengine_select";
+if (($has_kqueue) && ($config{USE_KQUEUE} eq "y")) {
+       $se = "socketengine_kqueue";
+}       
+elsif (($has_epoll) && ($config{USE_EPOLL} eq "y")) {
+       $se = "socketengine_epoll";
+}
+elsif (($has_ports) && ($config{USE_PORTS} eq "y")) {
+       $se = "socketengine_ports";
+}
+
+       ###
+       # This next section is for cygwin dynamic module builds.
+       # Basically, what we do, is build the inspircd core as a library
+       # then the main executable uses that. the library is capable of
+       # loading / unloading the modules dynamically :)
+       # Massive thanks to the guys on #cygwin @ irc.freenode.net for helping
+       # make this work :)
+       ###
+
+       if ($config{OSNAME} =~ /CYGWIN/i) {
+               print FH <<EOM;
+all: timer.o command_parse.o cull_list.o userprocess.o socketengine.o socket.o hashcomp.o channels.o mode.o xline.o inspstring.o dns.o base.o configreader.o inspsocket.o $cmdobjs commands.o dynamic.o users.o modules.o wildcard.o helperfuncs.o snomasks.o inspircd.exe
+
+inspircd.exe: inspircd.dll.a
+       \$(CC) -o \$@ \$^
+
+inspircd.dll inspircd.dll.a: inspircd.o channels.o mode.o xline.o inspstring.o dns.o base.o configreader.o inspsocket.o $cmdobjs  commands.o dynamic.o users.o modules.o wildcard.o helperfuncs.o hashcomp.o socket.o socketengine.o userprocess.o cull_list.o command_parse.o timer.o snomasks.o
+       \$(CC) -shared -Wl,--out-implib=inspircd.dll.a -o inspircd.dll \$^
+EOM
+       } else {
+               print FH <<EOM;
+all: timer.o command_parse.o cull_list.o userprocess.o socketengine.o socket.o hashcomp.o channels.o mode.o xline.o inspstring.o dns.o base.o configreader.o inspsocket.o $cmdobjs commands.o dynamic.o users.o modules.o wildcard.o helperfuncs.o snomasks.o \$(MODULES) inspircd.exe
+
+inspircd.exe: inspircd.cpp ../include/base.h ../include/channels.h ../include/inspircd.h ../include/channels.h ../include/globals.h ../include/inspircd_config.h ../include/base.h
+       \$(CC) -I../include \$(FLAGS) inspircd.cpp -o inspircd.exe \$(LDLIBS) channels.o mode.o xline.o inspstring.o dns.o base.o inspsocket.o configreader.o $cmdobjs commands.o dynamic.o users.o modules.o wildcard.o helperfuncs.o hashcomp.o socket.o socketengine.o userprocess.o cull_list.o command_parse.o timer.o snomasks.o modes/modeclasses.a \$(MODULES)
+EOM
+       }
+
+       print FH <<EOM;
+
+cull_list.o: cull_list.cpp ../include/base.h ../include/hashcomp.h ../include/globals.h ../include/inspircd_config.h ../include/users.h ../include/channels.h
+       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c cull_list.cpp
+
+snomasks.o: snomasks.cpp ../include/base.h ../include/hashcomp.h ../include/inspircd.h ../include/users.h ../include/globals.h ../include/inspircd_config.h ../include/channels.h
+       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c snomasks.cpp
+
+command_parse.o: command_parse.cpp ../include/base.h ../include/hashcomp.h ../include/inspircd.h ../include/users.h ../include/globals.h ../include/inspircd_config.h
+       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c command_parse.cpp
+
+userprocess.o: userprocess.cpp ../include/base.h ../include/hashcomp.h ../include/globals.h ../include/inspircd_config.h
+       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c userprocess.cpp
+
+socketengine.o: $se.cpp socketengine.cpp ../include/base.h ../include/hashcomp.h ../include/globals.h ../include/inspircd_config.h ../include/$se.h
+       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c socketengine.cpp $se.cpp
+
+hashcomp.o: hashcomp.cpp ../include/base.h ../include/hashcomp.h ../include/inspircd.h ../include/users.h ../include/globals.h ../include/inspircd_config.h
+       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c hashcomp.cpp
+
+helperfuncs.o: helperfuncs.cpp ../include/base.h ../include/inspircd.h ../include/users.h ../include/globals.h ../include/inspircd_config.h
+       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c helperfuncs.cpp
+
+channels.o: channels.cpp ../include/base.h ../include/channels.h ../include/inspircd.h ../include/users.h ../include/globals.h ../include/inspircd_config.h
+       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c channels.cpp
+
+mode.o: mode.cpp ../include/base.h ../include/mode.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h \$(RELCPPFILES) modes/modeclasses.a
+       \${MAKE} -C "modes" DIRNAME="src/modes" CC="\$(CC)" \$(MAKEARGS)
+       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c mode.cpp
+
+xline.o: xline.cpp ../include/base.h ../include/xline.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h
+       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c xline.cpp
+
+inspstring.o: inspstring.cpp ../include/base.h ../include/inspstring.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h
+       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c inspstring.cpp
+
+dns.o: dns.cpp ../include/base.h ../include/dns.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h ../include/timer.h
+       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c dns.cpp
+
+base.o: base.cpp ../include/base.h ../include/globals.h ../include/inspircd_config.h
+       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c base.cpp
+
+configreader.o: configreader.cpp ../include/base.h ../include/configreader.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h
+       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c configreader.cpp
+
+commands.o: commands.cpp ../include/base.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h ../include/timer.h $srcobjs
+       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c commands.cpp $cmdobjs
+
+dynamic.o: dynamic.cpp ../include/base.h ../include/dynamic.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h
+       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c dynamic.cpp
+
+users.o: users.cpp ../include/base.h ../include/users.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h ../include/timer.h
+       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c users.cpp
+
+modules.o: modules.cpp ../include/base.h ../include/modules.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h ../include/timer.h
+       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c modules.cpp
+
+wildcard.o: wildcard.cpp ../include/base.h ../include/wildcard.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h
+       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c wildcard.cpp
+
+socket.o: socket.cpp ../include/base.h ../include/inspircd.h ../include/globals.h ../include/inspircd_config.h
+       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c socket.cpp
+       
+inspsocket.o: inspsocket.cpp ../include/base.h ../include/inspircd.h ../include/globals.h ../include/inspircd_config.h ../include/timer.h
+       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c inspsocket.cpp
+
+timer.o: timer.cpp ../include/base.h ../include/inspircd.h ../include/globals.h ../include/inspircd_config.h ../include/timer.h
+       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c timer.cpp
+
+EOM
+       foreach my $cmd (@cmdlist) {
+               print FH <<ITEM;
+cmd_$cmd.o: cmd_$cmd.cpp ../include/base.h ../include/modules.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h ../include/commands/cmd_$cmd.h
+       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c cmd_$cmd.cpp
+ITEM
+       }
+       close(FH);
+}
+
+sub write_dynamic_makefile {
+
+       my $i = 0;
+       my @cmdlist = ();
+       opendir(DIRHANDLE, "src");
+       foreach $name (sort readdir(DIRHANDLE)) {
+               if ($name =~ /^cmd_(.+)\.cpp$/) {
+                       $cmdlist[$i++] = $1;
+               }
+       }
+       closedir(DIRHANDLE);
+
+       my $cmdobjs = "";
+       my $srcobjs = "";
+       foreach my $cmd (@cmdlist) {
+               $cmdobjs = $cmdobjs . "cmd_$cmd.so ";
+               $srcobjs = $srcobjs . "cmd_$cmd.cpp ";
+       }
+
+       $se = "socketengine_select";
+       if (($has_kqueue) && ($config{USE_KQUEUE} eq "y")) {
+               $se = "socketengine_kqueue";
+       }
+       elsif (($has_epoll) && ($config{USE_EPOLL} eq "y")) {
+               $se = "socketengine_epoll";
+       }
+       elsif (($has_ports) && ($config{USE_PORTS} eq "y")) {
+               $se = "socketengine_ports";
+       }
+
+       open(FH,">src/Makefile") or die("Could not write src/Makefile");
+       print FH <<EOM;
+# Insp Makefile :p
+#
+# (C) ChatSpike development team
+# Makefile by <Craig\@ChatSpike.net>
+# Makefile version 2 (dynamically linked core) by <brain\@inspircd.org>
+#
+
+CC = im a cheezeball
+
+CXXFLAGS = -I../include \${FLAGS}
+CPPFILES = \$(shell /bin/ls -l modes/ | grep '\\.cpp' | sed 's/^.* //' | grep -v svn)
+RELCPPFILES = \$(shell /bin/ls -l modes/ | grep '\\.cpp' | sed 's/^.* /modes\\//' | grep -v svn)
+
+EOM
+
+if ($config{IS_DARWIN} eq "YES") {
+       print FH <<EOM;
+all: libIRCDtimer.dylib libIRCDcull_list.dylib libIRCDuserprocess.dylib libIRCDsocketengine.dylib libIRCDsocket.dylib libIRCDhash.dylib libIRCDchannels.dylib libIRCDmode.dylib libIRCDxline.dylib libIRCDstring.dylib libIRCDasyncdns.dylib libIRCDbase.dylib libIRCDconfigreader.dylib libIRCDinspsocket.dylib libIRCDcommands.dylib libIRCDdynamic.dylib libIRCDusers.dylib libIRCDmodules.dylib libIRCDwildcard.dylib libIRCDhelper.dylib libIRCDcommand_parse.dylib libIRCDsnomasks.dylib inspircd
+
+inspircd: inspircd.cpp ../include/base.h ../include/channels.h ../include/inspircd.h ../include/channels.h ../include/globals.h ../include/inspircd_config.h ../include/socket.h $cmdobjs libIRCDtimer.dylib libIRCDcull_list.dylib libIRCDuserprocess.dylib libIRCDsocketengine.dylib libIRCDsocket.dylib libIRCDhash.dylib libIRCDchannels.dylib libIRCDmode.dylib libIRCDxline.dylib libIRCDstring.dylib libIRCDasyncdns.dylib libIRCDbase.dylib libIRCDconfigreader.dylib libIRCDinspsocket.dylib libIRCDsnomasks.dylib libIRCDcommands.dylib libIRCDdynamic.dylib libIRCDusers.dylib libIRCDmodules.dylib libIRCDwildcard.dylib libIRCDhelper.dylib libIRCDcommand_parse.dylib
+       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c inspircd.cpp
+       \$(CC) -pipe -dynamic -bind_at_load -L. -o inspircd \$(LDLIBS) inspircd.o libIRCDchannels.dylib libIRCDmode.dylib libIRCDxline.dylib libIRCDstring.dylib libIRCDasyncdns.dylib libIRCDbase.dylib libIRCDconfigreader.dylib libIRCDinspsocket.dylib libIRCDcommands.dylib libIRCDdynamic.dylib libIRCDusers.dylib libIRCDmodules.dylib libIRCDwildcard.dylib libIRCDhelper.dylib libIRCDhash.dylib libIRCDsocket.dylib libIRCDsocketengine.dylib libIRCDuserprocess.dylib libIRCDcull_list.dylib libIRCDcommand_parse.dylib libIRCDtimer.dylib libIRCDsnomasks.dylib
+
+libIRCDsocketengine.dylib: $se.cpp socketengine.cpp ../include/base.h ../include/hashcomp.h ../include/globals.h ../include/inspircd_config.h ../include/$se.h
+       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c socketengine.cpp
+       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c $se.cpp
+       \$(CC) -pipe -install_name $config{LIBRARY_DIR}/libIRCDsocketengine.dylib -dynamiclib -twolevel_namespace -undefined dynamic_lookup -o libIRCDsocketengine.dylib socketengine.o $se.o
+
+libIRCDsnomasks.dylib: snomasks.cpp ../include/base.h ../include/hashcomp.h ../include/inspircd.h ../include/users.h ../include/globals.h ../include/inspircd_config.h ../include/channels.h
+       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c snomasks.cpp
+       \$(CC) -pipe -install_name $config{LIBRARY_DIR}/libIRCDsnomasks.dylib -dynamiclib -twolevel_namespace -undefined dynamic_lookup -o libIRCDsnomasks.dylib snomasks.o
+
+libIRCDcommand_parse.dylib: command_parse.cpp ../include/base.h ../include/hashcomp.h ../include/inspircd.h ../include/users.h ../include/globals.h ../include/inspircd_config.h
+       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c command_parse.cpp
+       \$(CC) -pipe -install_name $config{LIBRARY_DIR}/libIRCDcommand_parse.dylib -dynamiclib -twolevel_namespace -undefined dynamic_lookup -o libIRCDcommand_parse.dylib command_parse.o
+
+libIRCDcull_list.dylib: cull_list.cpp ../include/base.h ../include/hashcomp.h ../include/globals.h ../include/inspircd_config.h ../include/users.h ../include/channels.h
+       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c cull_list.cpp
+       \$(CC) -pipe -install_name $config{LIBRARY_DIR}/libIRCDcull_list.dylib -dynamiclib -twolevel_namespace -undefined dynamic_lookup -o libIRCDcull_list.dylib cull_list.o
+
+libIRCDuserprocess.dylib: userprocess.cpp ../include/base.h ../include/hashcomp.h ../include/globals.h ../include/inspircd_config.h
+       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c userprocess.cpp
+       \$(CC) -pipe -install_name $config{LIBRARY_DIR}/libIRCDuserprocess.dylib -dynamiclib -twolevel_namespace -undefined dynamic_lookup -o libIRCDuserprocess.dylib userprocess.o
+
+libIRCDhash.dylib: hashcomp.cpp ../include/base.h ../include/hashcomp.h ../include/inspircd.h ../include/users.h ../include/globals.h ../include/inspircd_config.h
+       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c hashcomp.cpp
+       \$(CC) -pipe -install_name $config{LIBRARY_DIR}/libIRCDhash.dylib -dynamiclib -twolevel_namespace -undefined dynamic_lookup -o libIRCDhash.dylib hashcomp.o
+
+libIRCDhelper.dylib: helperfuncs.cpp ../include/base.h ../include/inspircd.h ../include/users.h ../include/globals.h ../include/inspircd_config.h
+       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c helperfuncs.cpp
+       \$(CC) -pipe -install_name $config{LIBRARY_DIR}/libIRCDhelper.dylib -dynamiclib -twolevel_namespace -undefined dynamic_lookup -o libIRCDhelper.dylib helperfuncs.o
+
+libIRCDchannels.dylib: channels.cpp ../include/base.h ../include/channels.h ../include/inspircd.h ../include/users.h ../include/globals.h ../include/inspircd_config.h
+       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c channels.cpp
+       \$(CC) -pipe -install_name $config{LIBRARY_DIR}/libIRCDchannels.dylib -dynamiclib -twolevel_namespace -undefined dynamic_lookup -o libIRCDchannels.dylib channels.o
+
+libIRCDmode.dylib: mode.cpp ../include/base.h ../include/mode.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h \$(RELCPPFILES)
+       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c mode.cpp
+       \${MAKE} -C "modes" DIRNAME="src/modes" CC="\$(CC)" \$(MAKEARGS) CPPFILES="\$(CPPFILES)"
+       \$(CC) -pipe -install_name $config{LIBRARY_DIR}/libIRCDmode.dylib -dynamiclib -twolevel_namespace -undefined dynamic_lookup -o libIRCDmode.dylib mode.o modes/modeclasses.a
+
+libIRCDxline.dylib: xline.cpp ../include/base.h ../include/xline.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h ../include/timer.h
+       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c xline.cpp
+       \$(CC) -pipe -install_name $config{LIBRARY_DIR}/libIRCDxline.dylib -dynamiclib -twolevel_namespace -undefined dynamic_lookup -o libIRCDxline.dylib xline.o
+
+libIRCDstring.dylib: inspstring.cpp ../include/base.h ../include/inspstring.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h
+       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c inspstring.cpp
+       \$(CC) -pipe -install_name $config{LIBRARY_DIR}/libIRCDstring.dylib -dynamiclib -twolevel_namespace -undefined dynamic_lookup -o libIRCDstring.dylib inspstring.o
+
+libIRCDasyncdns.dylib: dns.cpp ../include/base.h ../include/dns.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h ../include/timer.h
+       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c dns.cpp
+       \$(CC) -pipe -install_name $config{LIBRARY_DIR}/libIRCDasyncdns.dylib -dynamiclib -twolevel_namespace -undefined dynamic_lookup -o libIRCDasyncdns.dylib dns.o
+
+libIRCDbase.dylib: base.cpp ../include/base.h ../include/globals.h ../include/inspircd_config.h
+       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c base.cpp
+       \$(CC) -pipe -install_name $config{LIBRARY_DIR}/libIRCDbase.dylib -dynamiclib -twolevel_namespace -undefined dynamic_lookup -o libIRCDbase.dylib base.o
+
+libIRCDconfigreader.dylib: configreader.cpp ../include/base.h ../include/configreader.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h
+       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c configreader.cpp
+       \$(CC) -pipe -install_name $config{LIBRARY_DIR}/libIRCDconfigreader.dylib -dynamiclib -twolevel_namespace -undefined dynamic_lookup -o libIRCDconfigreader.dylib configreader.o
+
+libIRCDcommands.dylib: commands.cpp ../include/base.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h ../include/timer.h
+       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c commands.cpp
+       \$(CC) -pipe -install_name $config{LIBRARY_DIR}/libIRCDcommands.dylib -dynamiclib -twolevel_namespace -undefined dynamic_lookup -o libIRCDcommands.dylib commands.o
+
+libIRCDdynamic.dylib: dynamic.cpp ../include/base.h ../include/dynamic.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h
+       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c dynamic.cpp
+       \$(CC) -pipe -install_name $config{LIBRARY_DIR}/libIRCDdynamic.dylib -dynamiclib -twolevel_namespace -undefined dynamic_lookup -o libIRCDdynamic.dylib dynamic.o
+
+libIRCDusers.dylib: users.cpp ../include/base.h ../include/users.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h ../include/timer.h
+       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c users.cpp
+       \$(CC) -pipe -install_name $config{LIBRARY_DIR}/libIRCDusers.dylib -dynamiclib -twolevel_namespace -undefined dynamic_lookup -o libIRCDusers.dylib users.o
+
+libIRCDmodules.dylib: modules.cpp ../include/base.h ../include/modules.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h ../include/timer.h
+       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c modules.cpp
+       \$(CC) -pipe -install_name $config{LIBRARY_DIR}/libIRCDmodules.dylib -dynamiclib -twolevel_namespace -undefined dynamic_lookup -o libIRCDmodules.dylib modules.o
+
+libIRCDwildcard.dylib: wildcard.cpp ../include/base.h ../include/wildcard.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h
+       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c wildcard.cpp
+       \$(CC) -pipe -install_name $config{LIBRARY_DIR}/libIRCDwildcard.dylib -dynamiclib -twolevel_namespace -undefined dynamic_lookup -o libIRCDwildcard.dylib wildcard.o
+
+libIRCDsocket.dylib: socket.cpp ../include/base.h ../include/inspircd.h ../include/globals.h ../include/inspircd_config.h
+       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c socket.cpp
+       \$(CC) -pipe -install_name $config{LIBRARY_DIR}/libIRCDsocket.dylib -dynamiclib -twolevel_namespace -undefined dynamic_lookup -o libIRCDsocket.dylib socket.o
+
+libIRCDinspsocket.dylib: inspsocket.cpp ../include/base.h ../include/inspircd.h ../include/globals.h ../include/inspircd_config.h ../include/timer.h
+       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c inspsocket.cpp
+       \$(CC) -pipe -install_name $config{LIBRARY_DIR}/libIRCDinspsocket.dylib -dynamiclib -twolevel_namespace -undefined dynamic_lookup -o libIRCDinspsocket.dylib inspsocket.o
+
+libIRCDtimer.dylib: timer.cpp ../include/base.h ../include/inspircd.h ../include/globals.h ../include/inspircd_config.h ../include/timer.h
+       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c timer.cpp
+       \$(CC) -pipe -install_name $config{LIBRARY_DIR}/libIRCDtimer.dylib -dynamiclib -twolevel_namespace -undefined dynamic_lookup -o libIRCDtimer.dylib timer.o
+
+EOM
+
+} else {
+
+       print FH <<EOM;
+all: libIRCDtimer.so libIRCDcull_list.so libIRCDuserprocess.so libIRCDsocketengine.so libIRCDsocket.so libIRCDhash.so libIRCDchannels.so libIRCDmode.so libIRCDxline.so libIRCDstring.so libIRCDasyncdns.so libIRCDbase.so libIRCDconfigreader.so libIRCDinspsocket.so $cmdobjs libIRCDcommands.so libIRCDdynamic.so libIRCDusers.so libIRCDmodules.so libIRCDwildcard.so libIRCDhelper.so libIRCDcommand_parse.so libIRCDsnomasks.so inspircd
+
+inspircd: inspircd.cpp ../include/base.h ../include/channels.h ../include/inspircd.h ../include/channels.h ../include/globals.h ../include/inspircd_config.h ../include/socket.h libIRCDtimer.so libIRCDcull_list.so libIRCDuserprocess.so libIRCDsocketengine.so libIRCDsocket.so libIRCDhash.so libIRCDchannels.so libIRCDmode.so libIRCDxline.so libIRCDstring.so libIRCDasyncdns.so libIRCDbase.so libIRCDconfigreader.so libIRCDinspsocket.so $cmdobjs libIRCDsnomasks.so libIRCDcommands.so libIRCDdynamic.so libIRCDusers.so libIRCDmodules.so libIRCDwildcard.so libIRCDhelper.so libIRCDcommand_parse.so
+       \$(CC) -pipe -I../include $extra -Wl,--rpath -Wl,$config{LIBRARY_DIR} \$(FLAGS) -rdynamic -L. inspircd.cpp -o inspircd \$(LDLIBS) libIRCDchannels.so libIRCDmode.so libIRCDxline.so libIRCDstring.so libIRCDasyncdns.so libIRCDbase.so libIRCDconfigreader.so libIRCDinspsocket.so libIRCDcommands.so libIRCDdynamic.so libIRCDusers.so libIRCDmodules.so libIRCDwildcard.so libIRCDhelper.so libIRCDhash.so libIRCDsocket.so libIRCDsocketengine.so libIRCDuserprocess.so libIRCDcull_list.so libIRCDcommand_parse.so libIRCDtimer.so libIRCDsnomasks.so
+
+libIRCDsocketengine.so: $se.cpp socketengine.cpp ../include/base.h ../include/hashcomp.h ../include/globals.h ../include/inspircd_config.h ../include/$se.h
+       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c socketengine.cpp $se.cpp
+       \$(CC) -pipe -Wl,--rpath -Wl,$config{LIBRARY_DIR} -shared -o libIRCDsocketengine.so socketengine.o $se.o
+
+libIRCDsnomasks.so: snomasks.cpp ../include/base.h ../include/hashcomp.h ../include/inspircd.h ../include/users.h ../include/globals.h ../include/inspircd_config.h ../include/channels.h
+       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c snomasks.cpp
+       \$(CC) -pipe -Wl,--rpath -Wl,$config{LIBRARY_DIR} -shared -o libIRCDsnomasks.so snomasks.o
+
+libIRCDcommand_parse.so: command_parse.cpp ../include/base.h ../include/hashcomp.h ../include/inspircd.h ../include/users.h ../include/globals.h ../include/inspircd_config.h
+       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c command_parse.cpp
+       \$(CC) -pipe -Wl,--rpath -Wl,$config{LIBRARY_DIR} -shared -o libIRCDcommand_parse.so command_parse.o
+
+libIRCDcull_list.so: cull_list.cpp ../include/base.h ../include/hashcomp.h ../include/globals.h ../include/inspircd_config.h ../include/users.h ../include/channels.h
+       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c cull_list.cpp
+       \$(CC) -pipe -Wl,--rpath -Wl,$config{LIBRARY_DIR} -shared -o libIRCDcull_list.so cull_list.o
+
+libIRCDuserprocess.so: userprocess.cpp ../include/base.h ../include/hashcomp.h ../include/globals.h ../include/inspircd_config.h
+       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c userprocess.cpp
+       \$(CC) -pipe -Wl,--rpath -Wl,$config{LIBRARY_DIR} -shared -o libIRCDuserprocess.so userprocess.o
+
+libIRCDhash.so: hashcomp.cpp ../include/base.h ../include/hashcomp.h ../include/inspircd.h ../include/users.h ../include/globals.h ../include/inspircd_config.h
+       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c hashcomp.cpp
+       \$(CC) -pipe -Wl,--rpath -Wl,$config{LIBRARY_DIR} -shared -o libIRCDhash.so hashcomp.o
+
+libIRCDhelper.so: helperfuncs.cpp ../include/base.h ../include/inspircd.h ../include/users.h ../include/globals.h ../include/inspircd_config.h
+       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c helperfuncs.cpp
+       \$(CC) -pipe -Wl,--rpath -Wl,$config{LIBRARY_DIR} -shared -o libIRCDhelper.so helperfuncs.o
+
+libIRCDchannels.so: channels.cpp ../include/base.h ../include/channels.h ../include/inspircd.h ../include/users.h ../include/globals.h ../include/inspircd_config.h
+       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c channels.cpp
+       \$(CC) -pipe -Wl,--rpath -Wl,$config{LIBRARY_DIR} -shared -o libIRCDchannels.so channels.o
+
+libIRCDmode.so: mode.cpp ../include/base.h ../include/mode.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h \$(RELCPPFILES)
+       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c mode.cpp
+       \${MAKE} -C "modes" DIRNAME="src/modes" CC="\$(CC)" \$(MAKEARGS) CPPFILES="\$(CPPFILES)"
+       \$(CC) -pipe -Wl,--rpath -Wl,$config{LIBRARY_DIR} -shared -o libIRCDmode.so mode.o modes/modeclasses.a
+
+libIRCDxline.so: xline.cpp ../include/base.h ../include/xline.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h ../include/timer.h
+       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c xline.cpp
+       \$(CC) -pipe -Wl,--rpath -Wl,$config{LIBRARY_DIR} -shared -o libIRCDxline.so xline.o
+
+libIRCDstring.so: inspstring.cpp ../include/base.h ../include/inspstring.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h
+       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c inspstring.cpp
+       \$(CC) -pipe -Wl,--rpath -Wl,$config{LIBRARY_DIR} -shared -o libIRCDstring.so inspstring.o
+
+libIRCDasyncdns.so: dns.cpp ../include/base.h ../include/dns.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h ../include/timer.h
+       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c dns.cpp
+       \$(CC) -pipe -Wl,--rpath -Wl,$config{LIBRARY_DIR} -shared -o libIRCDasyncdns.so dns.o
+
+libIRCDbase.so: base.cpp ../include/base.h ../include/globals.h ../include/inspircd_config.h
+       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c base.cpp
+       \$(CC) -pipe -Wl,--rpath -Wl,$config{LIBRARY_DIR} -shared -o libIRCDbase.so base.o
+
+libIRCDconfigreader.so: configreader.cpp ../include/base.h ../include/configreader.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h
+       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c configreader.cpp
+       \$(CC) -pipe -Wl,--rpath -Wl,$config{LIBRARY_DIR} -shared -o libIRCDconfigreader.so configreader.o
+
+libIRCDcommands.so: commands.cpp ../include/base.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h ../include/timer.h
+       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c commands.cpp
+       \$(CC) -pipe -Wl,--rpath -Wl,$config{LIBRARY_DIR} -shared -o libIRCDcommands.so commands.o
+
+libIRCDdynamic.so: dynamic.cpp ../include/base.h ../include/dynamic.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h
+       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c dynamic.cpp
+       \$(CC) -pipe -Wl,--rpath -Wl,$config{LIBRARY_DIR} -shared -o libIRCDdynamic.so dynamic.o
+
+libIRCDusers.so: users.cpp ../include/base.h ../include/users.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h ../include/timer.h
+       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c users.cpp
+       \$(CC) -pipe -Wl,--rpath -Wl,$config{LIBRARY_DIR} -shared -o libIRCDusers.so users.o
+
+libIRCDmodules.so: modules.cpp ../include/base.h ../include/modules.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h ../include/timer.h
+       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c modules.cpp
+       \$(CC) -pipe -Wl,--rpath -Wl,$config{LIBRARY_DIR} -shared -o libIRCDmodules.so modules.o
+
+libIRCDwildcard.so: wildcard.cpp ../include/base.h ../include/wildcard.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h
+       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c wildcard.cpp
+       \$(CC) -pipe -Wl,--rpath -Wl,$config{LIBRARY_DIR} -shared -o libIRCDwildcard.so wildcard.o
+
+libIRCDsocket.so: socket.cpp ../include/base.h ../include/inspircd.h ../include/globals.h ../include/inspircd_config.h
+       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c socket.cpp
+       \$(CC) -pipe -Wl,--rpath -Wl,$config{LIBRARY_DIR} -shared -o libIRCDsocket.so socket.o
+
+libIRCDinspsocket.so: inspsocket.cpp ../include/base.h ../include/inspircd.h ../include/globals.h ../include/inspircd_config.h ../include/timer.h
+       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c inspsocket.cpp
+       \$(CC) -pipe -Wl,--rpath -Wl,$config{LIBRARY_DIR} -shared -o libIRCDinspsocket.so inspsocket.o
+
+libIRCDtimer.so: timer.cpp ../include/base.h ../include/inspircd.h ../include/globals.h ../include/inspircd_config.h ../include/timer.h
+       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c timer.cpp
+       \$(CC) -pipe -Wl,--rpath -Wl,$config{LIBRARY_DIR} -shared -o libIRCDtimer.so timer.o
+
+EOM
+}
+       foreach my $cmd (@cmdlist) {
+               print FH <<ITEM;
+cmd_$cmd.so: cmd_$cmd.cpp ../include/base.h ../include/modules.h ../include/inspircd.h ../include/channels.h ../include/users.h ../include/globals.h ../include/inspircd_config.h ../include/commands/cmd_$cmd.h
+       \$(CC) -pipe -I../include \$(FLAGS) -export-dynamic -c cmd_$cmd.cpp
+       \$(CC) -pipe $SHARED -o cmd_$cmd.so cmd_$cmd.o
+
+ITEM
+       }
+       close(FH);
+}
+
index de02fcca0015f5994a9b5dfe3d92faaa203d8c3d..2ef0e31715f1fdcfc93f202ba4333a4657e721de 100644 (file)
@@ -1 +1,346 @@
-NOTE: InspIRCd is licensed under GPL version 2 only.\r      "upgrading" to a later version of the GENERAL PUBLIC\r      LICENSE is not permitted. For further information on\r      this, please contact us at irc.inspircd.org on #inspircd.\r\r----------------------------------------------------------------------\r\r                    GNU GENERAL PUBLIC LICENSE\r                   Version 2, June 1991\r\r Copyright (C) 1989, 1991 Free Software Foundation, Inc.\r                          675 Mass Ave, Cambridge, MA 02139, USA\r Everyone is permitted to copy and distribute verbatim copies\r of this license document, but changing it is not allowed.\r\r                           Preamble\r\r  The licenses for most software are designed to take away your\rfreedom to share and change it.  By contrast, the GNU General Public\rLicense is intended to guarantee your freedom to share and change free\rsoftware--to make sure the software is free for all its users.  This\rGeneral Public License applies to most of the Free Software\rFoundation's software and to any other program whose authors commit to\rusing it.  (Some other Free Software Foundation software is covered by\rthe GNU Library General Public License instead.)  You can apply it to\ryour programs, too.\r\r  When we speak of free software, we are referring to freedom, not\rprice.  Our General Public Licenses are designed to make sure that you\rhave the freedom to distribute copies of free software (and charge for\rthis service if you wish), that you receive source code or can get it\rif you want it, that you can change the software or use pieces of it\rin new free programs; and that you know you can do these things.\r\r  To protect your rights, we need to make restrictions that forbid\ranyone to deny you these rights or to ask you to surrender the rights.\rThese restrictions translate to certain responsibilities for you if you\rdistribute copies of the software, or if you modify it.\r\r  For example, if you distribute copies of such a program, whether\rgratis or for a fee, you must give the recipients all the rights that\ryou have.  You must make sure that they, too, receive or can get the\rsource code.  And you must show them these terms so they know their\rrights.\r\r  We protect your rights with two steps: (1) copyright the software, and\r(2) offer you this license which gives you legal permission to copy,\rdistribute and/or modify the software.\r\r  Also, for each author's protection and ours, we want to make certain\rthat everyone understands that there is no warranty for this free\rsoftware.  If the software is modified by someone else and passed on, we\rwant its recipients to know that what they have is not the original, so\rthat any problems introduced by others will not reflect on the original\rauthors' reputations.\r\r  Finally, any free program is threatened constantly by software\rpatents.  We wish to avoid the danger that redistributors of a free\rprogram will individually obtain patent licenses, in effect making the\rprogram proprietary.  To prevent this, we have made it clear that any\rpatent must be licensed for everyone's free use or not licensed at all.\r\r  The precise terms and conditions for copying, distribution and\rmodification follow.\r\f\r                  GNU GENERAL PUBLIC LICENSE\r   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\r\r  0. This License applies to any program or other work which contains\ra notice placed by the copyright holder saying it may be distributed\runder the terms of this General Public License.  The "Program", below,\rrefers to any such program or work, and a "work based on the Program"\rmeans either the Program or any derivative work under copyright law:\rthat is to say, a work containing the Program or a portion of it,\reither verbatim or with modifications and/or translated into another\rlanguage.  (Hereinafter, translation is included without limitation in\rthe term "modification".)  Each licensee is addressed as "you".\r\rActivities other than copying, distribution and modification are not\rcovered by this License; they are outside its scope.  The act of\rrunning the Program is not restricted, and the output from the Program\ris covered only if its contents constitute a work based on the\rProgram (independent of having been made by running the Program).\rWhether that is true depends on what the Program does.\r\r  1. You may copy and distribute verbatim copies of the Program's\rsource code as you receive it, in any medium, provided that you\rconspicuously and appropriately publish on each copy an appropriate\rcopyright notice and disclaimer of warranty; keep intact all the\rnotices that refer to this License and to the absence of any warranty;\rand give any other recipients of the Program a copy of this License\ralong with the Program.\r\rYou may charge a fee for the physical act of transferring a copy, and\ryou may at your option offer warranty protection in exchange for a fee.\r\r  2. You may modify your copy or copies of the Program or any portion\rof it, thus forming a work based on the Program, and copy and\rdistribute such modifications or work under the terms of Section 1\rabove, provided that you also meet all of these conditions:\r\r    a) You must cause the modified files to carry prominent notices\r    stating that you changed the files and the date of any change.\r\r    b) You must cause any work that you distribute or publish, that in\r    whole or in part contains or is derived from the Program or any\r    part thereof, to be licensed as a whole at no charge to all third\r    parties under the terms of this License.\r\r    c) If the modified program normally reads commands interactively\r    when run, you must cause it, when started running for such\r    interactive use in the most ordinary way, to print or display an\r    announcement including an appropriate copyright notice and a\r    notice that there is no warranty (or else, saying that you provide\r    a warranty) and that users may redistribute the program under\r    these conditions, and telling the user how to view a copy of this\r    License.  (Exception: if the Program itself is interactive but\r    does not normally print such an announcement, your work based on\r    the Program is not required to print an announcement.)\r\f\rThese requirements apply to the modified work as a whole.  If\ridentifiable sections of that work are not derived from the Program,\rand can be reasonably considered independent and separate works in\rthemselves, then this License, and its terms, do not apply to those\rsections when you distribute them as separate works.  But when you\rdistribute the same sections as part of a whole which is a work based\ron the Program, the distribution of the whole must be on the terms of\rthis License, whose permissions for other licensees extend to the\rentire whole, and thus to each and every part regardless of who wrote it.\r\rThus, it is not the intent of this section to claim rights or contest\ryour rights to work written entirely by you; rather, the intent is to\rexercise the right to control the distribution of derivative or\rcollective works based on the Program.\r\rIn addition, mere aggregation of another work not based on the Program\rwith the Program (or with a work based on the Program) on a volume of\ra storage or distribution medium does not bring the other work under\rthe scope of this License.\r\r  3. You may copy and distribute the Program (or a work based on it,\runder Section 2) in object code or executable form under the terms of\rSections 1 and 2 above provided that you also do one of the following:\r\r    a) Accompany it with the complete corresponding machine-readable\r    source code, which must be distributed under the terms of Sections\r    1 and 2 above on a medium customarily used for software interchange; or,\r\r    b) Accompany it with a written offer, valid for at least three\r    years, to give any third party, for a charge no more than your\r    cost of physically performing source distribution, a complete\r    machine-readable copy of the corresponding source code, to be\r    distributed under the terms of Sections 1 and 2 above on a medium\r    customarily used for software interchange; or,\r\r    c) Accompany it with the information you received as to the offer\r    to distribute corresponding source code.  (This alternative is\r    allowed only for noncommercial distribution and only if you\r    received the program in object code or executable form with such\r    an offer, in accord with Subsection b above.)\r\rThe source code for a work means the preferred form of the work for\rmaking modifications to it.  For an executable work, complete source\rcode means all the source code for all modules it contains, plus any\rassociated interface definition files, plus the scripts used to\rcontrol compilation and installation of the executable.  However, as a\rspecial exception, the source code distributed need not include\ranything that is normally distributed (in either source or binary\rform) with the major components (compiler, kernel, and so on) of the\roperating system on which the executable runs, unless that component\ritself accompanies the executable.\r\rIf distribution of executable or object code is made by offering\raccess to copy from a designated place, then offering equivalent\raccess to copy the source code from the same place counts as\rdistribution of the source code, even though third parties are not\rcompelled to copy the source along with the object code.\r\f\r  4. You may not copy, modify, sublicense, or distribute the Program\rexcept as expressly provided under this License.  Any attempt\rotherwise to copy, modify, sublicense or distribute the Program is\rvoid, and will automatically terminate your rights under this License.\rHowever, parties who have received copies, or rights, from you under\rthis License will not have their licenses terminated so long as such\rparties remain in full compliance.\r\r  5. You are not required to accept this License, since you have not\rsigned it.  However, nothing else grants you permission to modify or\rdistribute the Program or its derivative works.  These actions are\rprohibited by law if you do not accept this License.  Therefore, by\rmodifying or distributing the Program (or any work based on the\rProgram), you indicate your acceptance of this License to do so, and\rall its terms and conditions for copying, distributing or modifying\rthe Program or works based on it.\r\r  6. Each time you redistribute the Program (or any work based on the\rProgram), the recipient automatically receives a license from the\roriginal licensor to copy, distribute or modify the Program subject to\rthese terms and conditions.  You may not impose any further\rrestrictions on the recipients' exercise of the rights granted herein.\rYou are not responsible for enforcing compliance by third parties to\rthis License.\r\r  7. If, as a consequence of a court judgment or allegation of patent\rinfringement or for any other reason (not limited to patent issues),\rconditions are imposed on you (whether by court order, agreement or\rotherwise) that contradict the conditions of this License, they do not\rexcuse you from the conditions of this License.  If you cannot\rdistribute so as to satisfy simultaneously your obligations under this\rLicense and any other pertinent obligations, then as a consequence you\rmay not distribute the Program at all.  For example, if a patent\rlicense would not permit royalty-free redistribution of the Program by\rall those who receive copies directly or indirectly through you, then\rthe only way you could satisfy both it and this License would be to\rrefrain entirely from distribution of the Program.\r\rIf any portion of this section is held invalid or unenforceable under\rany particular circumstance, the balance of the section is intended to\rapply and the section as a whole is intended to apply in other\rcircumstances.\r\rIt is not the purpose of this section to induce you to infringe any\rpatents or other property right claims or to contest validity of any\rsuch claims; this section has the sole purpose of protecting the\rintegrity of the free software distribution system, which is\rimplemented by public license practices.  Many people have made\rgenerous contributions to the wide range of software distributed\rthrough that system in reliance on consistent application of that\rsystem; it is up to the author/donor to decide if he or she is willing\rto distribute software through any other system and a licensee cannot\rimpose that choice.\r\rThis section is intended to make thoroughly clear what is believed to\rbe a consequence of the rest of this License.\r\f\r  8. If the distribution and/or use of the Program is restricted in\rcertain countries either by patents or by copyrighted interfaces, the\roriginal copyright holder who places the Program under this License\rmay add an explicit geographical distribution limitation excluding\rthose countries, so that distribution is permitted only in or among\rcountries not thus excluded.  In such case, this License incorporates\rthe limitation as if written in the body of this License.\r\r  9. The Free Software Foundation may publish revised and/or new versions\rof the General Public License from time to time.  Such new versions will\rbe similar in spirit to the present version, but may differ in detail to\raddress new problems or concerns.\r\rEach version is given a distinguishing version number.  If the Program\rspecifies a version number of this License which applies to it and "any\rlater version", you have the option of following the terms and conditions\reither of that version or of any later version published by the Free\rSoftware Foundation.  If the Program does not specify a version number of\rthis License, you may choose any version ever published by the Free Software\rFoundation.\r\r  10. If you wish to incorporate parts of the Program into other free\rprograms whose distribution conditions are different, write to the author\rto ask for permission.  For software which is copyrighted by the Free\rSoftware Foundation, write to the Free Software Foundation; we sometimes\rmake exceptions for this.  Our decision will be guided by the two goals\rof preserving the free status of all derivatives of our free software and\rof promoting the sharing and reuse of software generally.\r\r                        NO WARRANTY\r\r  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\rFOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN\rOTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\rPROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\rOR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\rMERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS\rTO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE\rPROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\rREPAIR OR CORRECTION.\r\r  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\rWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\rREDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\rINCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\rOUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\rTO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\rYOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\rPROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\rPOSSIBILITY OF SUCH DAMAGES.\r\r               END OF TERMS AND CONDITIONS\r\f\r     Appendix: How to Apply These Terms to Your New Programs\r\r  If you develop a new program, and you want it to be of the greatest\rpossible use to the public, the best way to achieve this is to make it\rfree software which everyone can redistribute and change under these terms.\r\r  To do so, attach the following notices to the program.  It is safest\rto attach them to the start of each source file to most effectively\rconvey the exclusion of warranty; and each file should have at least\rthe "copyright" line and a pointer to where the full notice is found.\r\r    <one line to give the program's name and a brief idea of what it does.>\r    Copyright (C) 19yy  <name of author>\r\r    This program is free software; you can redistribute it and/or modify\r    it under the terms of the GNU General Public License as published by\r    the Free Software Foundation; either version 2 of the License, or\r    (at your option) any later version.\r\r    This program is distributed in the hope that it will be useful,\r    but WITHOUT ANY WARRANTY; without even the implied warranty of\r    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r    GNU General Public License for more details.\r\r    You should have received a copy of the GNU General Public License\r    along with this program; if not, write to the Free Software\r    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\r\rAlso add information on how to contact you by electronic and paper mail.\r\rIf the program is interactive, make it output a short notice like this\rwhen it starts in an interactive mode:\r\r    Gnomovision version 69, Copyright (C) 19yy name of author\r    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\r    This is free software, and you are welcome to redistribute it\r    under certain conditions; type `show c' for details.\r\rThe hypothetical commands `show w' and `show c' should show the appropriate\rparts of the General Public License.  Of course, the commands you use may\rbe called something other than `show w' and `show c'; they could even be\rmouse-clicks or menu items--whatever suits your program.\r\rYou should also get your employer (if you work as a programmer) or your\rschool, if any, to sign a "copyright disclaimer" for the program, if\rnecessary.  Here is a sample; alter the names:\r\r  Yoyodyne, Inc., hereby disclaims all copyright interest in the program\r  `Gnomovision' (which makes passes at compilers) written by James Hacker.\r\r  <signature of Ty Coon>, 1 April 1989\r  Ty Coon, President of Vice\r\rThis General Public License does not permit incorporating your program into\rproprietary programs.  If your program is a subroutine library, you may\rconsider it more useful to permit linking proprietary applications with the\rlibrary.  If this is what you want to do, use the GNU Library General\rPublic License instead of this License.\r
\ No newline at end of file
+NOTE: InspIRCd is licensed under GPL version 2 only.
+      "upgrading" to a later version of the GENERAL PUBLIC
+      LICENSE is not permitted. For further information on
+      this, please contact us at irc.inspircd.org on #inspircd.
+
+----------------------------------------------------------------------
+
+                    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.
+\f
+                   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.)
+\f
+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.
+\f
+  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.
+\f
+  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
+\f
+       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.
index 25423247a1c271a39f6a8e14c70994e4589f5884..fdc6ac3b2a0d9f5c20f6e0ed05d358170fed56c9 100644 (file)
@@ -1 +1,10 @@
-Because of the dynamic nature of InspIRCd, we do not have traditional documentation in our tarball.\r\rThe documentation for InspIRCd can be found on our wiki, at http://www.inspircd.org/wiki\rOur bugtracker can be found at http://www.inspircd.org/bugtrack\rOur forums can be found at http://www.inspircd.org/forum\rOur development blog can be found at http://www.inspircd.com\r\rFor online support, please connect to irc.inspircd.org, and join #inspircd.\r\r  -- The InspIRCd Team\r
\ No newline at end of file
+Because of the dynamic nature of InspIRCd, we do not have traditional documentation in our tarball.
+
+The documentation for InspIRCd can be found on our wiki, at http://www.inspircd.org/wiki
+Our bugtracker can be found at http://www.inspircd.org/bugtrack
+Our forums can be found at http://www.inspircd.org/forum
+Our development blog can be found at http://www.inspircd.com
+
+For online support, please connect to irc.inspircd.org, and join #inspircd.
+
+  -- The InspIRCd Team
index 973f22301f93b0e5a366ea6aabdffecfa2ad2833..1fef8f70760cf421940ee2e8e0fbfa4a500b4bf2 100644 (file)
@@ -1 +1,2195 @@
-########################################################################\r#                                                                      #\r#               ___                ___ ____   ____    _                #\r#              |_ _|_ __  ___ _ __|_ _|  _ \ / ___|__| |               #\r#               | || '_ \/ __| '_ \| || |_) | |   / _` |               #\r#               | || | | \__ \ |_) | ||  _ <| |__| (_| |               #\r#              |___|_| |_|___/ .__/___|_| \_\\____\__,_|               #\r#                            |_|                                       #\r#      ____             __ _                       _   _               #\r#     / ___|___  _ __  / _(_) __ _ _   _ _ __ __ _| |_(_) ___  _ __    #\r#    | |   / _ \| '_ \| |_| |/ _` | | | | '__/ _` | __| |/ _ \| '_ \   #\r#    | |__| (_) | | | |  _| | (_| | |_| | | | (_| | |_| | (_) | | | |  #\r#     \____\___/|_| |_|_| |_|\__, |\__,_|_|  \__,_|\__|_|\___/|_| |_|  #\r#                            |___/                                     #\r#                                                                      #\r##################################||####################################\r                                 #||#                                   \r##################################||####################################\r#                                                                      #\r#         This is an example of the config file for InspIRCd.          #\r#             Change the options to suit your network                  #\r#                                                                      #\r#     $Id$\r#                                                                      #\r#    ____                _   _____ _     _       ____  _ _   _         #\r#   |  _ \ ___  __ _  __| | |_   _| |__ (_)___  | __ )(_) |_| |        #\r#   | |_) / _ \/ _` |/ _` |   | | | '_ \| / __| |  _ \| | __| |        #\r#   |  _ <  __/ (_| | (_| |   | | | | | | \__ \ | |_) | | |_|_|        #\r#   |_| \_\___|\__,_|\__,_|   |_| |_| |_|_|___/ |____/|_|\__(_)        #\r#                                                                      #\r#   Lines prefixed with READ THIS BIT, as shown above, are IMPORTANT   #\r#   lines, and you REALLY SHOULD READ THEM. Yes, THIS MEANS YOU. Even  #\r#   if you've configured InspIRCd before, these probably indicate      #\r#   something new or different to this version and you SHOULD READ IT. #\r#                                                                      #\r########################################################################\r#                                                                      #\r#         Unalphabeticalise the modules list at your own risk          #\r#                                                                      #\r########################################################################\r\r\r#-#-#-#-#-#-#-#-#-#-#-#-  SERVER DESCRIPTION  -#-#-#-#-#-#-#-#-#-#-#-#-\r#                                                                     #\r#   Here is where you enter the information about your server.        #\r#                                                                     #\r#  Syntax is as follows:                                              #\r#                                                                     #\r#     <server name="server.name"                                      #\r#      description="Server Description"                               #\r#      networkemail="Email address shown on g/k/z/q lines"            #\r#      network="MyNetwork">                                           #\r#                                                                     #\r\r<server name="penguin.omega.org.za"\r        description="Waddle World"\r   network="Omega">\r\r\r#-#-#-#-#-#-#-#-#-#-#-#-   ADMIN INFORMATION   -#-#-#-#-#-#-#-#-#-#-#-#\r#                                                                     #\r#   Describes the Server Administrator's real name (optionally),      #\r#   nick, and email address.                                          #\r#                                                                     #\r#  Syntax is as follows:                                              #\r#       <admin name="real name"                                       #\r#              nick="nick name"                                       #\r#              email="email@address.com">                             #\r#                                                                     #\r\r<admin name="Johnny English"\r       nick="MI5"\r       email="MI5@the.best.secret.agent">\r\r\r#-#-#-#-#-#-#-#-#-#-#-#-   PORT CONFIGURATION   -#-#-#-#-#-#-#-#-#-#-#-\r#                                                                     #\r#   Enter the port and address bindings here.                         #\r#                                                                     #\r#  bind address - specifies which address ports bind to. Leaving this #\r#                 field blank binds the port to all IPs available.    #\r#                                                                     #\r#  port         - The port number to bind to. You may specify a port  #\r#                 range here, e.g. "6667-6669,7000,7001". If you do   #\r#                 this, the server will count each port within your   #\r#                 range as a seperate binding, making the above       #\r#                 example equivalent to five seperate bind tags.      #\r#                 A failure on one port in the range does not prevent #\r#                 the entire range from being bound, just that one    #\r#                 port number.                                        #\r#                                                                     #\r#  type         - can be 'clients' or 'servers'. The clients type is  #\r#                 a standard tcp based socket, the servers type is a  #\r#                 also a TCP based connection but of a different      #\r#                 format. SSL support is provided by modules, to      #\r#                 enable SSL support, please read the module section  #\r#                 of this configuration file.                         #\r#                                                                     #\r#  ssl          - When using m_ssl_gnutls.so or m_ssl_openssl.so      #\r#                 modules, you must define this value to use ssl on   #\r#                 that port. valid values are 'gnutls' or 'openssl'   #\r#                 respectively. If the module is not loaded, this     #\r#                 setting is ignored.                                 #\r#                                                                     #\r#  transport    - If you have m_spanningtree.so loaded, along with    #\r#                 either of the SSL modules (m_ssl_gnutls or          #\r#                 m_ssl_openssl) or m_ziplinks.so, then you may make  #\r#                 use of this value.                                  #\r#                 setting it to 'openssl' or 'gnutls' or 'zip'        #\r#                 indicates that the port should accept connections   #\r#                 using the given transport name. Transports are      #\r#                 layers which sit on top of a socket and change the  #\r#                 way data is sent and received, e.g. encryption,     #\r#                 compression, and other such things. Because this    #\r#                 may not be limited in use to just encryption,       #\r#                 the 'ssl' value used for client ports does not      #\r#                 exist for servers, and this value is used instead.  #\r#    ____                _   _____ _     _       ____  _ _   _        #\r#   |  _ \ ___  __ _  __| | |_   _| |__ (_)___  | __ )(_) |_| |       #\r#   | |_) / _ \/ _` |/ _` |   | | | '_ \| / __| |  _ \| | __| |       #\r#   |  _ <  __/ (_| | (_| |   | | | | | | \__ \ | |_) | | |_|_|       #\r#   |_| \_\___|\__,_|\__,_|   |_| |_| |_|_|___/ |____/|_|\__(_)       #\r#                                                                     #\r#  If you want to link servers to InspIRCd you must load the          #\r#  m_spanningtree module! Please see the modules list below for       #\r#  information on how to load this module! If you do not load this    #\r#  module, server ports will NOT be bound!                            #\r#                                                                     #\r#  Leaving address empty binds to all available interfaces            #\r#                                                                     #\r#  Syntax is as follows:                                              #\r#                                                                     #\r# <bind address="ip address" port="port" type="clients">              #\r# <bind address="ip address" port="port" type="servers">              #\r#                                                                     #\r# If InspIRCd is built for IPV6, and you wish to accept IPV4 clients, #\r# then you can specify IPV4 ip addresses here to bind. You may also   #\r# use the 4in6 notation, ::ffff:1.2.3.4, where 1.2.3.4 is the IPV4    #\r# address to bind the port, but as of InspIRCd 1.1.1, this is not     #\r# required.                                                           #\r#                                                                     #\r# ------------------------------------------------------------------- #\r#                                                                     #\r# PLEASE NOTE: If you have build InspIRCd as an ipv6 server, and you  #\r# specify an empty bind address, the binding will be bound to ALL THE #\r# IPV6 IP ADDRESSES, and not the ipv4 addresses. If you are using an  #\r# ipv6 enabled InspIRCd and want to bind to multiple IPV4 addresses   #\r# in this way, you must specify them by hand. If you have built the   #\r# server for ipv4 connections only, then specifying an empty bind     #\r# address binds the port to all ipv4 IP addresses, as expected.       #\r#                                                                     #\r\r<bind address="" port="6000" type="clients">\r<bind address="" port="6660-6669" type="clients" ssl="gnutls">\r\r# When linking servers, the openssl and gnutls transports are largely\r# link-compatible and can be used alongside each other or either/or\r# on each end of the link without any significant issues.\r\r<bind address="" port="7000,7001" type="servers">\r<bind address="1.2.3.4" port="7005" type="servers" transport="openssl">\r\r\r#-#-#-#-#-#-#-#-#-#-  DIE/RESTART CONFIGURATION   -#-#-#-#-#-#-#-#-#-#-\r#                                                                     #\r#   You can configure the passwords here which you wish to use for    #\r#   the die and restart commands. Only trusted ircops who will        #\r#   need this ability should know the die and restart password.       #\r#                                                                     #\r#  Syntax is as follows:                                              #\r#       <power diepass="die password" restartpass="restart password"  #\r#        pause="secs before dying">                                   #\r#                                                                     #\r\r<power diepass="" restartpass="" pause="2">\r\r\r#-#-#-#-#-#-#-#-#-#  INCLUDE CONFIGURATION  #-#-#-#-#-#-#-#-#-#-#-#-#-#\r#                                                                     #\r# This optional tag allows you to include another config file         #\r# allowing you to keep your configuration tidy. The configuration     #\r# file you include will be treated as part of the configuration file  #\r# which includes it, in simple terms the inclusion is transparent.    #\r#                                                                     #\r# All paths to config files are relative to the directory of the main #\r# config file inspircd.conf, unless the filename starts with a forward#\r# slash (/) in which case it is treated as an absolute path.          #\r#                                                                     #\r# Syntax is as follows:                                               #\r#<include file="file.conf">                                           #\r#                                                                     #\r\r#-#-#-#-#-#-#-#-#-#-  CONNECTIONS CONFIGURATION  -#-#-#-#-#-#-#-#-#-#-#\r#                                                                     #\r#   This is where you can configure which connections are allowed     #\r#   and denied access onto your server. The password is optional.     #\r#   You may have as many of these as you require. To allow/deny all   #\r#   connections, use a '*' or 0.0.0.0/0.                              #\r#                                                                     #\r#  Syntax is as follows:                                              #\r#                                                                     #\r#       <connect allow="1.2.3.0/24" password="blahblah"               #\r#                timeout="10" timeout="blah" flood="5"                #\r#                threshold="8" pingfreq="120" sendq="99999"           #\r#                revcq="696969" localmax="3" globalmax="3"            #\r#                port="6660">                                         #\r#                                                                     #\r#       <connect deny="127.0.0.1" port="6667">                        #\r#                                                                     #\r#   IP masks may be specified in CIDR format or wildcard format,      #\r#   for IPV4 and IPV6. You *cannot* use hostnames in the allow or     #\r#   deny field, as the state is applied before the user's DNS has     #\r#   been resolved.                                                    #\r#                                                                     #\r#   You may optionally include timeout="x" on any allow line, which   #\r#   specifies the amount of time given before an unknown connection   #\r#   is closed if USER/NICK/PASS are not given. This value is in secs  #\r#                                                                     #\r#   You should also include a flood="x" line which indicates          #\r#   the number of lines a user may place into their buffer at once    #\r#   before they are disconnected for excess flood. This feature can   #\r#   not be disabled, however it can be set to extremely high values,  #\r#   rendering it effectively disabled. A recommended value is 10.     #\r#   A counter is maintained for each user which is reset every        #\r#   'threshold' seconds and specifying this threshold value with      #\r#   threshold="X" indicates how often the counter is reset. For       #\r#   example, with flood="5" and threshold="8", the user may not send  #\r#   more than 5 lines in 8 secs.                                      #\r#                                                                     #\r#   You may optionally specify the sendq size and ping frequency of   #\r#   each connect:allow line using the pingfreq="X" and sendq="X"      #\r#   settings as shown in the full example below.                      #\r#   The ping frequency is specified in seconds, and the sendq size    #\r#   in bytes. It is recommended, although not enforced, that you      #\r#   should never set your sendq size to less than 8k. Send Queues are #\r#   dynamically allocated and can grow as needed up to the maximum    #\r#   size specified.                                                   #\r#                                                                     #\r#   The optional recvq value is the maximum size which users in this  #\r#   group may grow their receive queue to. This is recommended to be  #\r#   kept pretty low compared to the sendq, as users will always       #\r#   receive more than they send in normal circumstances. The default  #\r#   if not specified is 4096.                                         #\r#                                                                     #\r#   The sendq is the data waiting to be sent TO THE USER.             #\r#   The recvq is the data being received FROM THE USER.               #\r#   The names sendq and recvq are from the SERVER'S PERSPECTIVE not   #\r#   that of the user... Just to clear up any confusion or complaints  #\r#   that these are backwards :p                                       #\r#                                                                     #\r#   The localmax and globalmax values can be used to enforce local    #\r#   and global session limits on connections. The session limits are  #\r#   counted against all users, but applied only to users within the   #\r#   class. For example, if you had a class 'A' which has a session    #\r#   limit of 3, and a class 'B' which has a session limit of 5, and   #\r#   somehow, two users managed to get into class B which also match   #\r#   class A, there is only one connection left for this IP now in A,  #\r#   but if they can connect again to B, there are three. You get the  #\r#   idea (i hope).                                                    #\r#                                                                     #\r#   The optional port value determines which port the connect tag is  #\r#   handling. If left out the connect tag covers all bound ports else #\r#   only incoming connections on the specified port will match. Port  #\r#   tags may be used on connect allow and connect deny tags.          #\r#                                                                     #\r\r<connect allow="196.12.*"  password="secret" port="6667">\r\r<connect allow="*"\r         timeout="60"\r         flood="20"\r         threshold="1"\r         pingfreq="120"\r         sendq="262144"\r         recvq="8192"\r         localmax="3"\r         globalmax="3">\r\r<connect deny="69.254.*">\r<connect deny="3ffe::0/32">\r\r\r#-#-#-#-#-#-#-#-#-#-#-#-  CLASS CONFIGURATION   -#-#-#-#-#-#-#-#-#-#-#-\r#                                                                     #\r#   Classes are a group of commands which are grouped together        #\r#   and given a unique name. They used to define which commands       #\r#   are available to certain types of Operators.                      #\r#                                                                     #\r#  Syntax is as follows:                                              #\r#                                                                     #\r#       <class name="name" commands="oper commands">                  #\r#                                                                     #\r#    ____                _   _____ _     _       ____  _ _   _        #\r#   |  _ \ ___  __ _  __| | |_   _| |__ (_)___  | __ )(_) |_| |       #\r#   | |_) / _ \/ _` |/ _` |   | | | '_ \| / __| |  _ \| | __| |       #\r#   |  _ <  __/ (_| | (_| |   | | | | | | \__ \ | |_) | | |_|_|       #\r#   |_| \_\___|\__,_|\__,_|   |_| |_| |_|_|___/ |____/|_|\__(_)       #\r#                                                                     #\r#  You are not forced to give these classes the names given below.    #\r#  You can create your own named classes, if you want, in fact that   #\r#  is the whole idea of this system!                                  #\r#                                                                     #\r#  Note: It is possible to make a class which covers all available    #\r#  commands. To do this, specify commands="*". This is not really     #\r#  recommended, as it negates the whole purpose of the class system,  #\r#  however it is provided for fast configuration (e.g. in test nets)  #\r#                                                                     #\r\r<class name="Shutdown" commands="DIE RESTART REHASH LOADMODULE UNLOADMODULE RELOAD">\r<class name="ServerLink" commands="CONNECT SQUIT RCONNECT MKPASSWD MKSHA256">\r<class name="BanControl" commands="KILL GLINE KLINE ZLINE QLINE ELINE">\r<class name="OperChat" commands="WALLOPS GLOBOPS SETIDLE SPYLIST SPYNAMES">\r<class name="HostCloak" commands="SETHOST SETIDENT SETNAME CHGHOST CHGIDENT">\r\r\r#-#-#-#-#-#-#-#-#-#-#-#-  OPERATOR COMPOSITION   -#-#-#-#-#-#-#-#-#-#-#\r#                                                                     #\r#   This is where you specify which types of operators you have on    #\r#   your server, as well as the commands they are allowed to use.     #\r#   This works alongside with the classes specified above.            #\r#                                                                     #\r#  type name  - a name for the combined class types                   #\r#               a type name cannot contain spaces, however if you     #\r#               put an _ symbol in the name, it will be translated    #\r#               to a space when displayed in a WHOIS.                 #\r#                                                                     #\r#  classes    - specified above, used for flexibility for the         #\r#               server admin to decide on which operators get         #\r#               what commands. Class names are case sensitive,        #\r#               seperate multiple class names with spaces.            #\r#                                                                     #\r#  host       - optional hostmask operators will receive on oper-up.  #\r#                                                                     #\r#  Syntax is as follows:                                              #\r#                                                                     #\r#     <type name="name" classes="class names" host="oper hostmask">   #\r#                                                                     #\r#    ____                _   _____ _     _       ____  _ _   _        #\r#   |  _ \ ___  __ _  __| | |_   _| |__ (_)___  | __ )(_) |_| |       #\r#   | |_) / _ \/ _` |/ _` |   | | | '_ \| / __| |  _ \| | __| |       #\r#   |  _ <  __/ (_| | (_| |   | | | | | | \__ \ | |_) | | |_|_|       #\r#   |_| \_\___|\__,_|\__,_|   |_| |_| |_|_|___/ |____/|_|\__(_)       #\r#                                                                     #\r#  You are not forced to give these types the names given below.      #\r#  You can create your own named types, if you want, in fact that     #\r#  is the whole idea of this system!                                  #\r#                                                                     #\r\r<type name="NetAdmin" classes="OperChat BanControl HostCloak Shutdown ServerLink" host="netadmin.omega.org.za">\r<type name="GlobalOp" classes="OperChat BanControl HostCloak ServerLink" host="ircop.omega.org.za">\r<type name="Helper" classes="HostCloak" host="helper.omega.org.za">\r\r\r#-#-#-#-#-#-#-#-#-#-#-  OPERATOR CONFIGURATION   -#-#-#-#-#-#-#-#-#-#-#\r#                                                                     #\r#   Opers are defined here. This is a very important section.         #\r#   Remember to only make operators out of truthworthy people.        #\r#                                                                     #\r#  name        - oper name, This is case sensitive, so it is best to  #\r#                use lower-case.                                      #\r#                                                                     #\r#  password    - password to oper-up, also case sensitive.            #\r#                encryption is supported via modules. You may load    #\r#                modules for MD5 or SHA256 encryption, and if you do, #\r#                this value will be a hash value, otherwise put a     #\r#                plaintext password in this value.                    #\r#                                                                     #\r#  host        - hosts of client allowed to oper-up.                  #\r#                wildcards accepted, seperate multiple hosts with a   #\r#                space. You may also specify CIDR ip addresses.       #\r#                                                                     #\r#  fingerprint - When using the m_ssl_oper_cert.so module, you may    #\r#                specify a key fingerprint here. This can be obtained #\r#                using the /fingerprint command whilst the module is  #\r#                loaded, or from the notice given to you when you     #\r#                connect to the ircd using a client certificate,      #\r#                and will lock this oper block to only the user who   #\r#                has that specific key/certificate pair.              #\r#                This enhances security a great deal, however it      #\r#                requires that opers use clients which can send ssl   #\r#                client certificates, if this is configured for that  #\r#                oper. Note that if the m_ssl_oper.so module is not   #\r#                loaded, and/or one of m_ssl_openssl or m_ssl_gnutls  #\r#                is not loaded, this configuration option has no      #\r#                effect and will be ignored.                          #\r#                                                                     #\r#  type        - Defines the kind of operator. This must match a type #\r#                tag you defined above, and is case sensitive.        #\r#                                                                     #\r#  Syntax is as follows:                                              #\r#       <oper name="login"                                            #\r#             password="pass"                                         #\r#             host="hostmask@of.oper"                                 #\r#           fingerprint="hexsequence"                               #\r#             type="oper type">                                       #\r#                                                                     #\r\r<oper name="Brain"\r      password="s3cret"\r      host="ident@dialup15.isp.com *@localhost *@server.com *@3ffe::0/16"\r      type="NetAdmin">\r\r\r#-#-#-#-#-#-#-#-#-#-#-  SERVER LINK CONFIGURATION  -#-#-#-#-#-#-#-#-#-#\r#                                                                     #\r# Defines which servers can link to this one, and which servers this  #\r# server may create outbound links to.                                #\r#                                                                     #\r# name        -   The name is the canocial name of the server, does   #\r#                 not have to resolve - but it is expected to be set  #\r#                 in the remote servers connection info.              #\r#                                                                     #\r# ipaddr      -   Valid host or ip address for remote server. These   #\r#                 hosts are resolved on rehash, and cached, if you    #\r#                 specify a hostname, so if you find that your server #\r#                 is still trying to connect to an old IP after you   #\r#                 have updated your dns, try rehashing and then       #\r#                 attempting the connect again.                       #\r#                                                                     #\r# port        -   The TCP port for the remote server.                 #\r#                                                                     #\r# sendpass    -   Password to send to create an outbound connection   #\r#                 to this server.                                     #\r#                                                                     #\r# recvpass    -   Password to receive to accept an inbound connection #\r#                 from this server.                                   #\r#                                                                     #\r# autoconnect -   Sets the server to autoconnect. Where x is the num. #\r# (optional)      of seconds between attempts. e.g. 300 = 5 minutes.  #\r#                                                                     #\r# transport     - If defined, this is a transport name implemented by #\r#                 another module. Transports are layers on top of     #\r#                 plaintext connections, which alter them in certain  #\r#                 ways. Currently the three supported transports are  #\r#                 'openssl' and 'gnutls' which are types of SSL       #\r#                 encryption, and 'zip' which is for compression.     #\r#                 If you define a transport, both ends of the         #\r#                 connection must use a compatible transport for the  #\r#                 link to succeed. OpenSSL and GnuTLS are link-       #\r#                 compatible with each other.                         #\r#                                                                     #\r# statshidden   - When using m_spanningtree.so for linking. you may   #\r#                 set this to 'yes', and if you do, the IP address/   #\r#                 hostname of this connection will NEVER be shown to  #\r#                 any opers on the network. In /STATS c its address   #\r#                 will show as *@<hidden>, and during CONNECT and     #\r#                 inbound connections, its IP will show as <hidden>   #\r#                 UNLESS the connection fails (e.g. due to a bad      #\r#                 password or servername)                             #\r#                                                                     #\r# allowmask     - When this is defined, it indicates a range of IP    #\r#                 addresses to allow for this link (You may use CIDR  #\r#                 or wildcard form for this address).                 #\r#                 e.g. if your server is going to connect to you from #\r#                 the range 1.2.3.1 through 1.2.3.255, put 1.2.3.0/24 #\r#                 into this value. If it is not defined, then only    #\r#                 the ipaddr field of the server shall be allowed.    #\r#                                                                     #\r# failover      - If you define this option, it must be the name of a #\r#                 different link tag in your configuration. This      #\r#                 option causes the ircd to attempt a connection to   #\r#                 the failover link in the event that the connection  #\r#                 to this server fails. For example, you could define #\r#                 two hub uplinks to a leaf server, and set an        #\r#                 american server to autoconnect, with a european     #\r#                 hub as its failover. In this situation, your ircd   #\r#                 will only try the link to the european hub if the   #\r#                 american hub is unreachable. NOTE that for the      #\r#                 intents and purposes of this option, an unreachable #\r#                 server is one which DOES NOT ANSWER THE CONNECTION. #\r#                 If the server answers the connection with accept(), #\r#                 EVEN IF THE CREDENTIALS ARE INVALID, the failover   #\r#                 link will not be tried! Failover settings will also #\r#                 apply to autoconnected servers as well as manually  #\r#                 connected ones.                                     #\r#                                                                     #\r# timeout       - If this is defined, then outbound connections will  #\r#                 time out if they are not connected within this many #\r#                 seconds. If this is not defined, the default of ten #\r#                 seconds is used.                                    #\r#                                                                     #\r# bind          - If you specify this value, then when creating an    #\r#                 outbound connection to the given server, the IP you #\r#                 place here will be bound to. This is for multi-     #\r#                 homed servers which may have multiple IP addresses. #\r#                 If you do not define this value, the first IP that  #\r#                 is not empty or localhost from your <bind> tags     #\r#                 will be bound to. This is usually acceptable,       #\r#                 however if your server has multiple network cards   #\r#                 then you may have to manually specify the bind      #\r#                 value instead of leaving it to automatic binding.   #\r#                 You can usually tell if you need to set this by     #\r#                 looking for the error 'Could not assign requested   #\r#                 address' in your log when connecting to servers.    #\r#                                                                     #\r# hidden        - If this is set to true, yes, or 1, then the server  #\r#                 is completely hidden from non-opers. It does not    #\r#                 show in LINKS and it does not show in MAP. Also,    #\r#                 any servers which are child servers of this one     #\r#                 in the network will *also* be hidden. Use with      #\r#                 care! You can use this to 'mask off' sections of    #\r#                 the network so that users only see a small portion  #\r#                 of a much larger net. It should NOT be relied upon  #\r#                 as a security tool, unless it is being used for     #\r#                 example to hide a non-client hub, for which clients #\r#                 do not have an IP address or resolvable hostname.   #\r#                                                                     #\r# to u:line a server (give it extra privilages required for running   #\r# services, Q, etc) you must include the <uline server> tag as shown  #\r# in the example below. You can have as many of these as you like.    #\r#                                                                     #\r# WARNING: Unlike other ircds, u:lining a server allows ALL users on  #\r# that server to operoverride modes. This should only be used for     #\r# services and protected oper servers!                                #\r#                                                                     #\r# ------------------------------------------------------------------- #\r#                                                                     #\r# NOTE: If you have built your server as an ipv6 server, then when a  #\r# DNS lookup of a server's host occurs, AAAA records (ipv6) are       #\r# priorotized over A records (ipv4). Therefore, if the server you are #\r# connecting to has both an IPV6 ip address and an IPV4 ip address in #\r# its DNS entry, the IPV6 address will *always* be selected. To       #\r# change this behaviour simply specify the IPV4 IP address rather     #\r# than the hostname of the server.                                    #\r#                                                                     #\r# ------------------------------------------------------------------- #\r#                                                                     #\r#    ____                _   _____ _     _       ____  _ _   _        #\r#   |  _ \ ___  __ _  __| | |_   _| |__ (_)___  | __ )(_) |_| |       #\r#   | |_) / _ \/ _` |/ _` |   | | | '_ \| / __| |  _ \| | __| |       #\r#   |  _ <  __/ (_| | (_| |   | | | | | | \__ \ | |_) | | |_|_|       #\r#   |_| \_\___|\__,_|\__,_|   |_| |_| |_|_|___/ |____/|_|\__(_)       #\r#                                                                     #\r#  If you want to link servers to InspIRCd you must load the          #\r#  m_spanningtree module! Please see the modules list below for       #\r#  information on how to load this module! If you do not load this    #\r#  module, server links will NOT work!                                #\r#                                                                     #\r#  Also, if you define any transports, you must load the modules for  #\r#  these transports BEFORE you load m_spanningtree, e.g. place them   #\r#  above it in the configuration file. Currently this means the three #\r#  modules m_ssl_gnutls, m_ziplinks and m_ssl_openssl, depending on   #\r#  which you choose to use.                                           #\r#                                                                     #\r\r<link name="hub.penguin.org"\r      ipaddr="penguin.box.com"\r      port="7000"\r      allowmask="69.58.44.0/24"\r      autoconnect="300"\r      failover="hub.other.net"\r      timeout="15"\r      transport="gnutls"\r      bind="1.2.3.4"\r      statshidden="no"\r      hidden="no"\r      sendpass="outgoing!password"\r      recvpass="incoming!password">\r\r<link name="services.antarctic.com"\r      ipaddr="localhost"\r      port="7000"\r      allowmask="127.0.0.0/8"\r      sendpass="penguins"\r      recvpass="polarbears">\r\r\r#-#-#-#-#-#-#-#-#-#-#-#- ULINES CONFIGURATION #-#-#-#-#-#-#-#-#-#-#-#-#\r# This tag defines a ulined server. A U-Lined server has special      #\r# permissions, and should be used with caution. Services servers are  #\r# usually u-lined in this manner.                                     #\r#                                                                     #\r# The 'silent' value if set to yes indicates that this server should  #\r# not generate quit and connect notices, which can cut down on noise  #\r# to opers on the network.                                            #\r#                                                                     #\r<uline server="services.antarctic.com" silent="yes">\r\r\r#-#-#-#-#-#-#-#-#-#-  MISCELLANEOUS CONFIGURATION  -#-#-#-#-#-#-#-#-#-#\r#                                                                     #\r#   These options let you define the path to your motd and rules      #\r#   files. If these are relative paths, they are relative to the      #\r#   configurtion directory.                                           #\r#                                                                     #\r\r<files motd="inspircd.motd.example"\r       rules="inspircd.rules.example">\r\r#-#-#-#-#-#-#-#-#-#-#-# MAXIMUM CHANNELS -#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r#                                                                     #\r# This optional configuration tag lets you define the maximum number  #\r# of channels that both opers and users may be on at any one time.    #\r# the default is 20 for user and 60 for opers if this tag is not      #\r# defined. Remote users are not restricted in any manner.             #\r#                                                                     #\r\r<channels users="20"\r          opers="60">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-# DNS SERVER -#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r#                                                                     #\r# Define your DNS server address here. InspIRCd has its own resolver. #\r# If you do not define this value, then then InspIRCd will attempt to #\r# determine your DNS server from your operating system. On POSIX      #\r# platforms, InspIRCd will read /etc/resolv.conf, and populate this   #\r# value with the first DNS server address found. On Windows platforms #\r# InspIRCd will check the registry, and use the DNS server of the     #\r# first active network interface, if one exists.                      #\r# If a DNS server cannot be determined from these checks, the default #\r# value '127.0.0.1' is used instead. The timeout value is in seconds. #\r#                                                                     #\r#    ____                _   _____ _     _       ____  _ _   _        #\r#   |  _ \ ___  __ _  __| | |_   _| |__ (_)___  | __ )(_) |_| |       #\r#   | |_) / _ \/ _` |/ _` |   | | | '_ \| / __| |  _ \| | __| |       #\r#   |  _ <  __/ (_| | (_| |   | | | | | | \__ \ | |_) | | |_|_|       #\r#   |_| \_\___|\__,_|\__,_|   |_| |_| |_|_|___/ |____/|_|\__(_)       #\r#                                                                     #\r# When choosing a server, be sure to choose one which will do a       #\r# RECURSIVE LOOKUP. InspIRCd's resolver does not currently do these   #\r# recursive lookups itself, to save time and resources. The dns       #\r# server recommended by the InspIRCd team is bind, available from the #\r# ISC website. If your DNS server does not do a recursive lookup, you #\r# will be able to notice this by the fact that none of your users are #\r# resolving even though the DNS server appears to be up! Most ISP and #\r# hosting provider DNS servers support recursive lookups.             #\r#                                                                     #\r# ------------------------------------------------------------------- #\r#                                                                     #\r# NOTE: if you have built InspIRCd with IPV6 support, then both       #\r# ipv6 and ipv4 addresses are allowed here, and also in the system    #\r# resolv.conf file. Remember that an ipv4 dns server can still        #\r# resolve ipv6 addresses, and vice versa.                             #\r#                                                                     #\r\r<dns server="127.0.0.1" timeout="5">\r\r# An example of using an IPV6 nameserver\r#<dns server="::1" timeout="5">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#  PID FILE  -#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r#                                                                     #\r# Define the path to the PID file here. The PID file can be used to   #\r# rehash the ircd from the shell or to terminate the ircd from the    #\r# shell using shell scripts, perl scripts etc, and to monitor the     #\r# ircd's state via cron jobs. If this is a relative path, it will be  #\r# relative to the configuration directory, and if it is not defined,  #\r# the default of 'inspircd.pid' is used.                              #\r#                                                                     #\r\r#<pid file="/path/to/inspircd.pid">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#- BANLIST LIMITS #-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r#                                                                     #\r# Use these tags to customise the ban limits on a per channel basis.  #\r# the tags are read from top to bottom, and any tag found which       #\r# matches the channels name applies the banlimit to that channel.     #\r# It is advisable to put an entry with the channel as '*' at the      #\r# bottom of the list. If none are specified or no maxbans tag is      #\r# matched, the banlist size defaults to 64 entries.                   #\r#                                                                     #\r\r<banlist chan="#morons" limit="128">\r<banlist chan="*" limit="69">\r\r#-#-#-#-#-#-#-#-#-#-#-  DISABLED COMMANDS  -#-#-#-#-#-#-#-#-#-#-#-#-#-#\r#                                                                     #\r# This tag is optional, and specifies one or more commands which are  #\r# not available to non-operators. For example you may wish to disable #\r# NICK and prevent non-opers from changing their nicknames.           #\r# Note that any disabled commands take effect only after the user has #\r# 'registered' (e.g. after the initial USER/NICK/PASS on connection)  #\r# so for example disabling NICK will not cripple your network.        #\r#                                                                     #\r\r#<disabled commands="TOPIC MODE">\r\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-  RTFM LINE  -#-#-#-#-#-#-#-#-#-#-#-#-#-#\r#                                                                     #\r#   Just remove this... Its here to make you read ALL of the config   #\r#   file options ;)                                                   #\r\r<die value="You should probably edit your config *PROPERLY* and try again.">\r\r\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-  SERVER OPTIONS   -#-#-#-#-#-#-#-#-#-#-#-#-#\r#                                                                     #\r#   Settings to define which features are useable on your server.     #\r#                                                                     #\r#  prefixquit    - A prefix to be placed on the start of a client's   #\r#                  quit message                                       #\r#                                                                     #\r#  suffixquit    - A suffix to be placed on the end of a client's     #\r#                  quit message.                                      #\r#                                                                     #\r#  fixedquit     - A fixed quit message to display for all client     #\r#                  QUITS. If specified, overrides both prefixquit     #\r#                  and suffixquit options.                            #\r#                                                                     #\r#  loglevel      - specifies what detail of messages to log in the    #\r#                  log file. You may select from debug, verbose,      #\r#                  default, sparse and none.                          #\r#                                                                     #\r#  allowhalfop   - allows the +h channel mode                         #\r#                                                                     #\r#  noservices    - If noservices is true, yes, or 1, then the first   #\r#                  user into a channel gets founder status. This is   #\r#                  only useful on networks running the m_chanprotect  #\r#                  module without services.                           #\r#                                                                     #\r#  qaprefixes    - If qaprefixes is true, yes, or 1, then users       #\r#                  with +q or +a will get the ~ or & prefixes         #\r#                  used in unreal. This is only useful on networks    #\r#                  running the m_chanprotect module                   #\r#                                                                     #\r#  deprotectself - If this value is set to yes, true, or 1, then any  #\r#                  user with +q or +a may remove the +q or +a from    #\r#                  themselves. The default setting is to not enable   #\r#                  this feature, which stops even the founder taking  #\r#                  away their founder status without using services.  #\r#                                                                     #\r#  deprotectothers-If this value is set to yes, true, or 1, then any  #\r#                  user with +q or +a may remove the +q or +a from    #\r#                  other users. The default setting is to not enable  #\r#                  this feature, so that only +q may remove +a, and   #\r#                  nothing but services may remove +q.                #\r#                                                                     #\r#  cyclehosts    - If this is set to true, yes or 1, then when a      #\r#                  user's hostname changes, they will appear to quit  #\r#                  and then rejoin with their new host. This prevents #\r#                  clients from being confused by host changes,       #\r#                  especially in the case of bots, and it is          #\r#                  recommended that this option is enabled.           #\r#                                                                     #\r#  netbuffersize - size of the buffer used to receive data from       #\r#                  clients. The ircd may only read() this amount      #\r#                  of text in one go at any time. (OPTIONAL)          #\r#                                                                     #\r#  maxwho        - The maximum number of results returned by a /WHO   #\r#                  query. This is to prevent /WHO being used as a     #\r#                  spam vector or means of flooding an ircd. The      #\r#                  default is 128, it is not recommended to raise it  #\r#                  above 1024. Values up to 65535 are permitted. If   #\r#                  this value is omitted, any size WHO is allowed by  #\r#                  anyone.                                            #\r#                                                                     #\r#  somaxconn     - The maximum number of sockets that may be waiting  #\r#                  in the accept queue. This usually allows the ircd  #\r#                  to soak up more connections in a shorter space of  #\r#                  time when increased but please be aware there is a #\r#                  system defined maximum value to this, the same way #\r#                  there is a system defined maximum number of file   #\r#                  descriptors. Some systems may only allow this to   #\r#                  be up to 5 (ugh) while others such as FreeBSD will #\r#                  default to a much nicer 128.                       #\r#                                                                     #\r#  moduledir     - This optional value indicates a runtime change of  #\r#                  the location where modules are to be found. This   #\r#                  does not add a supplementary directory. There can  #\r#                  only be one module path.                           #\r#                                                                     #\r#  softlimit     - This optional feature allows a defined softlimit.  #\r#                  if defined sets a soft maxconnections value, has   #\r#                  to be less than the ./configure maxclients         #\r#                                                                     #\r#  userstats     - The userstats field is optional and specifies      #\r#                  which stats characters in /STATS may be requested  #\r#                  by non-operators. Stats characters in this field   #\r#                  are case sensitive and are allowed to users        #\r#                  independent of if they are in a module or the core #\r#                                                                     #\r#  operspywhois  - If this is set then when an IRC operator uses      #\r#                  /WHOIS on a user they will see all channels, even  #\r#                  ones if channels are secret (+s), private (+p) or  #\r#                  if the target user is invisible +i.                #\r#                                                                     #\r#  customversion - If you specify this configuration item, and it is  #\r#                  not set to an empty value, then when a user does   #\r#                  a /VERSION command on the ircd, this string will   #\r#                  be displayed as the second portion of the output,  #\r#                  replacing the system 'uname', compile flags and    #\r#                  socket engine/dns engine names. You may use this   #\r#                  to enhance security, or simply for vanity.         #\r#                                                                     #\r#  maxtargets    - The maxtargets field is optional, and if not       #\r#                  defined, defaults to 20. It indicates the maximum  #\r#                  number of targets which may be given to commands   #\r#                  such as PRIVMSG, KICK etc.                         #\r#                                                                     #\r#  hidesplits    - When set to 'yes', will hide split server names    #\r#                  from non-opers. Non-opers will see '*.net *.split' #\r#                  instead of the server names in the quit message,   #\r#                  identical to the way IRCu displays them.           #\r#                                                                     #\r#  hidebans      - When set to 'yes', will hide gline, kline, zline   #\r#                  and qline quit messages from non-opers. For        #\r#                  example, user A who is not an oper will just see   #\r#                  (G-Lined) while user B who is an oper will see the #\r#                  text (G-Lined: Reason here) instead.               #\r#                                                                     #\r#  hidewhois     - When defined with a non-empty value, the given     #\r#                  text will be used in place of the user's server    #\r#                  in WHOIS, when a user is WHOISed by a non-oper.    #\r#                  For example, most nets will want to set this to    #\r#                  something like '*.netname.net' to conceal the      #\r#                  actual server the user is on.                      #\r#                                                                     #\r#  flatlinks     - When you are using m_spanningtree.so, and this     #\r#                  value is set to true, yes or 1, /MAP and /LINKS    #\r#                  will be flattened when shown to a non-oper.        #\r#                                                                     #\r#  hideulines    - When you are using m_spanningtree.so, and this     #\r#                  value is set to true, yes or 1, then U-lined       #\r#                  servers will be hidden in /LINKS and /MAP. For non #\r#                  opers. Please be aware that this will also hide    #\r#                  any leaf servers of a U-lined server, e.g. jupes.  #\r#                                                                     #\r#  nouserdns     - If set to 'yes', 'true' or '1', no user dns        #\r#                  lookups will be performed for connecting users.    #\r#                  this can save a lot of resources on very busy irc  #\r#                  servers.                                           #\r#                                                                     #\r#  syntaxhints   - If set to 'yes', 'true' or '1', when a user does   #\r#                  not give enough parameters for a command, a syntax #\r#                  hint will be given (using the RPL_TEXT numeric)    #\r#                  as well as the standard ERR_NEEDMOREPARAMS.        #\r#                                                                     #\r#  announcets    - If this value is defined to 'yes', 'true' or '1',  #\r#                  then if a channel's timestamp is updated the users #\r#                  on the channel will be informed of the change via  #\r#                  a server notice to the channel with the old and    #\r#                  new TS values in the timestamp. If you think this  #\r#                  is just pointless noise, define the value to 0.    #\r#                                                                     #\r#  ircumsgprefix - Use undernet style message prefix for channel      #\r#                  NOTICE and PRIVMSG adding the prefix to the line   #\r#                  of text sent out. Eg. NOTICE @#test :@ testing     #\r#                  vs. the off setting: NOTICE @#test :testing        #\r#                                                                     #\r#  hostintopic   - If this is set to yes (the default) then the full  #\r#                  nick!user@host is shown for who set a TOPIC last.  #\r#                  if set to no, then only the nickname is shown.     #\r#                                                                     #\r# announceinvites                                                     #\r#                - If this option is set to yes (the default), then   #\r#                  invites are announced to the channel when a user   #\r#                  invites annother user. If you consider this to be  #\r#                  unnecessary noise, explicitly set this to no.      #\r#                                                                     #\r#  disablehmac   - If you are linking your InspIRCd to older versions #\r#                  then you can specify this option and set it to     #\r#                  yes. 1.1.6 and above support HMAC and challenge-   #\r#                  response for password authentication. These can    #\r#                  greatly enhance security of your server to server  #\r#                  connections when you are not using SSL (as is the  #\r#                  case with a lot of larger networks). Linking to    #\r#                  older versions of InspIRCd should not *usually* be #\r#                  a problem, but if you have problems with HMAC      #\r#                  authentication, this option can be used to turn it #\r#                  off.                                               #\r#                                                                     #\r#  hidemodes     - If this option is enabled, then the listmodes      #\r#                  given (e.g. +eI), will be hidden from users below  #\r#                  halfop. This is not recommended to be set on mode  #\r#                  +b, as it may break some features in popular       #\r#                  clients such as mIRC.                              #\r#                                                                     #\r#  quietbursts   - When synching or splitting from the network, a     #\r#                  server can generate a lot of connect and quit      #\r#                  snotices to the +C and +Q snomasks. Setting this   #\r#                  value to yes squelches those messages, which can   #\r#                  make them more useful for opers, however it will   #\r#                  degrade their use by certain third party programs  #\r#                  such as BOPM which rely on them to scan users when #\r#                  a split heals in certain configurations.           #\r#                                                                     #\r#  pingwarning   - This should be set to a number between 1 and 59 if #\r#                  defined, and if it is defined will cause the server#\r#                  to send out a warning via snomask +l if a server   #\r#                  does not answer to PING after this many seconds.   #\r#                  This can be useful for finding servers which are   #\r#                  at risk of pinging out due to network issues.      #\r#                                                                     #\r#  exemptchanops - This option allows channel operators to be exempted#\r#                  from certain channel modes.                        #\r#                  Supported modes are +SfgNc. Defaults to off.       #\r#                                                                     #\r#  defaultmodes  - The default modes to be given to each channel on   #\r#                  creation. Defaults to 'nt'. There should be no +   #\r#                  or - symbols in this sequence, if you add them     #\r#                  they will be ignored. You may add parameters for   #\r#                  parameterised modes.                               #\r#                                                                     #\r#  moronbanner   - The NOTICE to show to users who are glined, zlined #\r#                  klined or qlined when they are disconnected. This  #\r#                  is totally freeform, you may place any text here   #\r#                  you wish.                                          #\r#                                                                     #\r\r<options prefixquit="Quit: "\r         loglevel="default"\r         netbuffersize="10240"\r         maxwho="128"\r         noservices="no"\r         qaprefixes="no"\r         deprotectself="no"\r         deprotectothers="no"\r         somaxconn="128"\r         softlimit="12800"\r         userstats="Pu"\r         operspywhois="no"\r         customversion=""\r         maxtargets="20"\r         hidesplits="no"\r         hidebans="no"\r         hidewhois=""\r         flatlinks="no"\r         hideulines="no"\r         nouserdns="no"\r         syntaxhints="no"\r         cyclehosts="yes"\r         ircumsgprefix="no"\r         announcets="yes"\r         disablehmac="no"\r         hostintopic="yes"\r         hidemodes="eI"\r         quietbursts="yes"\r         pingwarning="15"\r         allowhalfop="yes"\r  defaultmodes="nt"\r      moronbanner="You're banned! Email haha@abuse.com with the ERROR line below for help."\r  exemptchanops="">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#- TIME SYNC OPTIONS -#-#-#-#-#-#-#-#-#-#-#-#\r# Time sychronization options for m_spanningtree linking.             #\r#                                                                     #\r# Because IRC is very time and clock dependent, InspIRCd provides its #\r# own methods for syncronization of time between servers as shown     #\r# in the example below, for servers that don't have ntpd running.     #\r#                                                                     #\r#  enable    -     If this value is 'yes', 'true', or '1', time       #\r#                  synchronization is enabled on this server. This    #\r#                  means any servers you are linked to will           #\r#                  automatically synchronize time, however you should #\r#                  use ntpd instead where possible, NOT this option.  #\r#                                                                     #\r#  master    -     If this value is set to yes, then this server will #\r#                  act as the authoritative time source for the whole #\r#                  network. All other servers will respect its time   #\r#                  without question, and match their times to it.     #\r#                  only one server should have the master value set   #\r#                  to 'yes'.                                          #\r#                                                                     #\r<timesync enable="no" master="no">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-  WHOWAS OPTIONS   -#-#-#-#-#-#-#-#-#-#-#-#-#\r#                                                                     #\r# This tag lets you define the behaviour of the /whowas command of    #\r# your server.                                                        #\r#                                                                     #\r# groupsize      - Controls the maximum entries per nick shown when   #\r#                  performing a /whowas nick. Setting this to 0 dis-  #\r#                  ables whowas completely.                           #\r#                                                                     #\r# maxgroups      - The maximum number of nickgroups that can be added #\r#                  to the list. If max is reached, oldest group will  #\r#                  be deleted first like a FIFO. A groupsize of 3 and #\r#                  a maxgroups of 5000 will allow for 5000 nicks to   #\r#                  be stored with a history of 3, thus giving a total #\r#                  of 3 * 5000 = 15000 entries. A setting of 0 dis-   #\r#                  ables whowas completely.                           #\r#                                                                     #\r# maxkeep        - The maximum time a nick is kept in the whowas list #\r#                  before being pruned. Time may be specified in      #\r#                  seconds, or in the following format: 1y2w3d4h5m6s  #\r#                  meaning one year, two weeks, three days, 4 hours,  #\r#                  5 minutes and 6 seconds. All fields in this format #\r#                  are optional. Minimum is 1 hour, if less InspIRCd  #\r#                  will default back to 1 hour.                       #\r#                                                                     #\r#<whowas groupsize="10"                                               #\r#        maxgroups="100000"                                           #\r#        maxkeep="3d">                                                #\r\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-  MODULE OPTIONS   -#-#-#-#-#-#-#-#-#-#-#-#-#\r#                                                                     #\r#  These tags define which modules will be loaded on startup by your  #\r#  server. Add modules without any paths. When you make your ircd     #\r#  using the 'make' command, all compiled modules will be moved into  #\r#  the folder you specified when you ran ./configure. The module tag  #\r#  automatically looks for modules in this location.                  #\r#  If you attempt to load a module outside of this location, either   #\r#  in the config, or via /LOADMODULE, you will receive an error.      #\r#                                                                     #\r#  By default, ALL modules are commented out. You must uncomment them #\r#  or add lines to your config to load modules. Please refer to       #\r#  http://www.inspircd.org/wiki/Modules_List for a list of modules and#\r#  each modules link for any additional conf tags they require.       #\r#                                                                     #\r#  You may use wildcards in a <module> tag to load all modules which  #\r#  match a glob pattern (e.g. m_sa????.so would load m_sajoin,        #\r#  m_sapart, m_saquit and m_sanick)                                   #\r#                                                                     #\r#    ____                _   _____ _     _       ____  _ _   _        #\r#   |  _ \ ___  __ _  __| | |_   _| |__ (_)___  | __ )(_) |_| |       #\r#   | |_) / _ \/ _` |/ _` |   | | | '_ \| / __| |  _ \| | __| |       #\r#   |  _ <  __/ (_| | (_| |   | | | | | | \__ \ | |_) | | |_|_|       #\r#   |_| \_\___|\__,_|\__,_|   |_| |_| |_|_|___/ |____/|_|\__(_)       #\r#                                                                     #\r# To link servers to InspIRCd, you MUST load the m_spanningtree       #\r# module, as shown below. If you DO NOT do this, server links will    #\r# NOT work at all. ie. The ports will NOT bind, and /connect will not #\r# work properly. This is by design, to allow for the implementation   #\r# of other linking protocols in modules in the future.                #\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Spanning Tree module - allows linking of servers using the spanning\r# tree protocol (see the READ THIS BIT section above).\r#\r#<module name="m_spanningtree.so">\r\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# MD5 Module - Allows other modules to generate MD5 hashes, usually for\r# cryptographic uses and security.\r#\r# IMPORTANT:\r# Other modules such as m_cloaking.so and m_opermd5.so may rely on\r# this module being loaded to function.\r#\r#<module name="m_md5.so">\r#\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# SHA256 Module - Allows other modules to generate SHA256 hashes,\r# usually for cryptographic uses and security.\r#\r# IMPORTANT:\r# Other modules such as m_opermd5.so may rely on this module being\r# loaded to function.\r#\r#<module name="m_sha256.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Alias module: Allows you to define server-side command aliases\r#<module name="m_alias.so">\r#\r#-#-#-#-#-#-#-#-#-#-#-  ALIAS DEFINITIONS  -#-#-#-#-#-#-#-#-#-#-#-#-#-#\r#                                                                     #\r# If you have the m_alias.so module loaded, you may also define       #\r# aliases as shown below. They are commonly used to provide shortcut  #\r# commands to services, however they are not limited to just this use.#\r# An alias tag requires the following values to be defined in it:     #\r#                                                                     #\r# text        -      The text to detect as the actual command line,   #\r#                    Cant contain spaces, but case insensitive.       #\r#                    You may have multiple aliases with the same      #\r#                    command name (text="" value), however the first  #\r#                    found will be executed if its format value is    #\r#                    matched, or it has no format value. Aliases are  #\r#                    read from the top of the file to the bottom.     #\r#                                                                     #\r# format      -      If this is defined, the parameters of the alias  #\r#                    must match this glob pattern. For example if you #\r#                    want the first parameter to start with a # for   #\r#                    the alias to be executed, set format="#*" in the #\r#                    alias definition. Note that the :'s which are    #\r#                    part of IRC formatted lines will be preserved    #\r#                    for matching of this text. This value is         #\r#                    optional.                                        #\r#                                                                     #\r# replace     -      The text to replace 'text' with. Usually this    #\r#                    will be "PRIVMSG ServiceName :$2-" or similar.   #\r#                    You may use the variables $1 through $9 in the   #\r#                    replace string, which refer to the first through #\r#                    ninth word in the original string typed by the   #\r#                    user. You may also use $1- through $9- which     #\r#                    refer to the first word onwards, through to the  #\r#                    ninth word onwards, e.g. if the user types the   #\r#                    command "foo bar baz qux quz" then $3- will hold #\r#                    "baz qux quz" and $2 will contain "bar". You may #\r#                    also use the special variables: $nick, $ident,   #\r#                    $host and $vhost, and you may seperate multiple  #\r#                    commands with \n. If you wish to use the ACTUAL  #\r#                    characters \ and n together in a line, you must  #\r#                    use the sequence "\\n".                          #\r#                                                                     #\r# requires    -      If you provide a value for 'requires' this means #\r#                    the given nickname MUST be online for the alias  #\r#                    to successfully trigger. If they are not, then   #\r#                    the user receives a 'no such nick' 401 numeric.  #\r#                                                                     #\r# uline       -      Defining this value with 'yes', 'true' or '1'    #\r#                    will ensure that the user given in 'requires'    #\r#                    must also be on a u-lined server, as well as     #\r#                    actually being on the network. If the user is    #\r#                    online, but not on a u-lined server, then an     #\r#                    oper-alert is sent out as this is possibly signs #\r#                    of a user trying to impersonate a service.       #\r#                                                                     #\r# operonly    -      Defining this value, with a value of 'yes', '1'  #\r#                    or true will make the alias oper only. If a non- #\r#                    oper attempts to use the alias, it will appear   #\r#                    to not exist.                                    #\r#                                                                     #\r#<alias text="NICKSERV" replace="PRIVMSG NickServ :$2-" requires="NickServ" uline="yes">\r#<alias text="CHANSERV" replace="PRIVMSG ChanServ :$2-" requires="ChanServ" uline="yes">\r#<alias text="OPERSERV" replace="PRIVMSG OperServ :$2-" requires="OperServ" uline="yes" operonly="yes">\r#<alias text="NS" replace="PRIVMSG NickServ :$2-" requires="NickServ" uline="yes">\r#<alias text="CS" replace="PRIVMSG ChanServ :$2-" requires="ChanServ" uline="yes">\r#<alias text="OS" replace="PRIVMSG OperServ :$2-" requires="OperServ" uline="yes" operonly="yes">\r#\r# An example of using the format value to create an alias with two\r# different behaviours depending on the format of the parameters.\r#\r#<alias text="ID" format="#*" replace="PRIVMSG ChanServ :IDENTIFY $2 $3"\r#  requires="ChanServ" uline="yes">\r#\r#<alias text="ID" replace="PRIVMSG NickServ :IDENTIFY $2"\r#  requires="NickServ" uline="yes">\r#\r# This alias fixes a glitch in xchat 2.6.x and above and the way it\r# assumes IDENTIFY must be prefixed by a colon (:) character. It should\r# be placed ABOVE the default NICKSERV alias (the first example) listed\r# above.\r#\r#<alias text="NICKSERV" format=":IDENTIFY *" replace="PRIVMSG NickServ :IDENTIFY $3-"\r#  requires="NickServ" uline="yes">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Alltime module: Shows time on all connected servers at once\r#<module name="m_alltime.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Antibear security module: Prevents 'bear.txt' based trojans from\r# connecting to your network by sending them a numeric they can't handle.\r#<module name="m_antibear.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Antibottler module: Labels bottler leech bots\r#<module name="m_antibottler.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Auditorium module: Adds channel mode +u which makes everyone else\r# except you in the channel invisible, used for large meetings etc.\r#<module name="m_auditorium.so">\r#\r# Auditorium settings:\r#\r#<auditorium showops="no">\r#\r# Setting this value to yes makes m_auditorium behave like unrealircd\r# +u channel mode, e.g. ops see users joining, parting, etc, and users\r# joining the channel see the ops. Without this flag, the mode acts\r# like ircnet's +a (anonymous channels), showing only the user in the\r# names list, and not even showing the ops in the list, or showing the\r# ops that the user has joined.\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Ban except module: Adds support for channel ban exceptions (+e)\r#<module name="m_banexception.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Ban redirection module: Allows bans which redirect to a specified\r# channel. e.g. +b nick!ident@host#channelbanneduserissentto\r#<module name="m_banredirect.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Block amsg module: Attempt to block all usage of /amsg and /ame\r#<module name="m_blockamsg.so">\r#\r#-#-#-#-#-#-#-#-#-#-#-  BLOCKAMSG CONFIGURATION  -#-#-#-#-#-#-#-#-#-#-#\r#                                                                     #\r# If you have the m_blockamsg.so module loaded, you can configure it  #\r# with the <blockamsg> tag:                                           #\r#                                                                     #\r# delay          -   How many seconds between two messages to force   #\r#                    them to be recognised as unrelated.              #\r# action         -   Any of 'notice', 'noticeopers', 'silent', 'kill' #\r#                    or 'killopers'. Define how to take action when   #\r#                    a user uses /amsg or /ame.                       #\r#\r#<blockamsg delay="3" action="killopers">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Block CAPS module: Blocking all-CAPS messages with cmode +P\r#<module name="m_blockcaps.so">\r#                                                                     #\r#-#-#-#-#-#-#-#-#-#-#-  BLOCKCAPS CONFIGURATION  -#-#-#-#-#-#-#-#-#-#-#\r#                                                                     #\r# percent        - How many percent of text must be caps before text  #\r#                  will be blocked.                                   #\r#                                                                     #\r# minlen         - The minimum length a line must be for the block    #\r#                  percent to have any effect.                        #\r#                                                                     #\r# capsmap        - A list of chars to be considered CAPS, this was    #\r#                  you can add CAPS for your language. Also you can   #\r#                  add things like ! and space to further lock down   #\r#                  on caps usage.                                     #\r#<blockcaps percent="50"\r#           minlen="5"\r#           capsmap="ABCDEFGHIJKLMNOPQRSTUVWXYZ! ">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Block colour module: Blocking colour-coded messages with cmode +c\r#<module name="m_blockcolor.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Botmode module: Adds the user mode +B\r#<module name="m_botmode.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# CBAN module: Lets you disallow channels from being used at runtime.\r#<module name="m_cban.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Censor module: Adds the channel mode +G\r#<module name="m_censor.so">\r#\r#-#-#-#-#-#-#-#-#-#-#-  CENSOR  CONFIGURATION  -#-#-#-#-#-#-#-#-#-#-#-#\r#                                                                     #\r# Optional - If you specify to use the m_censor module, then you must #\r# specify some censor tags. See also:                                 #\r# http://www.inspircd.org/wiki/Censor_Module                          #\r#\r#<include file="censor.conf">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# CGI:IRC module: Adds support for automatic host changing in CGI:IRC\r# (http://cgiirc.sourceforge.net).\r#<module name="m_cgiirc.so">\r#\r#-#-#-#-#-#-#-#-#-#-#-# CGIIRC  CONFIGURATION #-#-#-#-#-#-#-#-#-#-#-#-#\r#\r# Optional - If you specify to use m_cgiirc, then you must specify one\r# or more cgihost tags which indicate authorized CGI:IRC servers which\r# will be connecting to your network, and an optional cgiirc tag.\r# For more information see: http://www.inspircd.org/wiki/CGI-IRC_Module\r#\r# Set to yes if you want to notice opers when CGI clients connect\r# <cgiirc opernotice="no">\r#\r# The type field indicates where the module should get the real\r# client's IP address from, for further information, please see the\r# CGI:IRC documentation.\r#\r# <cgihost type="pass" mask="www.mysite.com">       # Get IP from PASS\r# <cgihost type="webirc" mask="somebox.mysite.com"> # Get IP from WEBIRC\r# <cgihost type="ident" mask="otherbox.mysite.com"> # Get IP from ident\r# <cgihost type="passfirst" mask="www.mysite.com">  # See the docs\r#\r# IMPORTANT NOTE:\r# ---------------\r#\r# When you connect CGI:IRC clients, there are two connect classes which\r# apply to these clients. When the client initially connects, the connect\r# class which matches the cgi:irc site's host is checked. Therefore you\r# must raise the maximum local/global clients for this ip as high as you\r# want to allow cgi clients. After the client has connected and is\r# determined to be a cgi:irc client, the class which matches the client's\r# real IP is then checked. You may set this class to a lower value, so that\r# the real IP of the client can still be restricted to, for example, 3\r# sessions maximum.\r#\r\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Channel create module: Adds snomask +j, which will notify opers of\r# any new channels that are created\r#<module name="m_chancreate.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Channel filter module: Allows channel-op defined message\r# filtering using simple string matches (channel mode +g)\r#<module name="m_chanfilter.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Chanprotect module: gives +q and +a channel modes\r#<module name="m_chanprotect.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Check module: gives /check\r# Check is useful for looking up information on channels,\r# users, IP addresses and hosts.\r#<module name="m_check.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# CHGHOST module: Adds the /CHGHOST command\r#<module name="m_chghost.so">\r#\r#-#-#-#-#-#-#-#-# /CHGHOST - /SETHOST  CONFIGURATION #-#-#-#-#-#-#-#-#\r# Optional - If you want to use special chars for hostnames you can  #\r# specify your own custom list of chars with the <hostname> tag:     #\r#                                                                    #\r# charmap        - A list of chars accepted as valid by the /CHGHOST #\r#                  and /SETHOST commands. Also note that the list is # \r#                  case-sensitive.                                   #\r#<hostname charmap="abcdefghijklmnopqrstuvwxyz.-_/0123456789">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# CHGIDENT module: Adds the /CHGIDENT command\r#<module name="m_chgident.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# CHGNAME module: Adds the /CHGNAME command\r#<module name="m_chgname.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Cloaking module: Adds usermode +x and cloaking support.\r# Relies on the module m_md5.so being loaded before m_cloaking.so in\r# the configuration file.\r#<module name="m_cloaking.so">\r#\r#-#-#-#-#-#-#-#-#-#-#- CLOAKING  CONFIGURATION -#-#-#-#-#-#-#-#-#-#-#-#\r#                                                                     #\r# Optional - If you specify the m_cloaking.so module as above, you    #\r# must define cloak keys, and optionally a cloak prefix as shown      #\r# below. When using cloaking, the cloak keys are MANDITORY and must   #\r# be included. However, if prefix is not included, it will default    #\r# to your networks name from the <server> tag.                        #\r#                                                                     #\r# <cloak key1="0x2AF39F40"                                            #\r#        key2="0x78E10B32"                                            #\r#        key3="0x4F2D2E82"                                            #\r#        key4="0x043A4C81"                                            #\r#        prefix="mynet">                                              #\r#                                                                     #\r# Please note that the key values will accept any number, and should  #\r# be large numbers. Using small numbers such as "7" or "1924" will    #\r# seriously weaken the security of your cloak. It is recommended you  #\r# use hexdecimal numbers prefixed by "0x", as shown in this example,  #\r# with each key eight hex digits long.                                #\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Clones module: Adds an oper command /CLONES for detecting cloned\r# users. Warning: This module may be resource intensive when its\r# command is issued, use with care.\r#<module name="m_clones.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Conn-Join: Allows you to force users to join one or more channels\r# automatically upon connecting to the server.\r#<module name="m_conn_join.so">\r#\r#-#-#-#-#-#-#-#-#-#-#-#- CONNJOIN CONFIGURATION  -#-#-#-#-#-#-#-#-#-#-#\r#\r# If you have m_conn_join.so loaded, you can configure it using the\r# follow values:\r#\r#<autojoin channel="#one,#two,#three">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Conn-Usermodes: Set modes on users when they connect\r# When this module is loaded <connect:allow> tags may have an optional\r# modes="" value, which contains modes to add or remove from users\r# when they connect to the server.\r#<module name="m_conn_umodes.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Conn-Wait-for-Pong: Don't let a user connect until they PONG\r#<module name="m_conn_waitpong.so">\r#\r#-#-#-#-#-#-#-#-#-#-#-   WAITPONG CONFIGURATION  -#-#-#-#-#-#-#-#-#-#-#\r#                                                                     #\r# If you have the m_conn_waitpong.so module loaded, configure it with #\r# the <waitpong> tag:                                                 #\r#                                                                     #\r# sendsnotice    -   Whether to send a snotice on connect, like other #\r#                    older ircds                                      #\r#                                                                     #\r# killonbadreply -   Whether to kill the user if they send the wrong  #\r#                    PONG reply.                                      #\r#                                                                     #\r#<waitpong sendsnotice="yes" killonbadreply="yes">\r\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Channel cycle module. Server side /hop, with +ilk etc bypass.\r#<module name="m_cycle.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Connection throttle module. Configuration:\r#<module name="m_connflood.so">\r#\r#-#-#-#-#-#-#-#-#-#-#- CONTHROTTLE CONFIGURATION -#-#-#-#-#-#-#-#-#-#-#\r#  seconds, maxconns -  Amount of connections per <seconds>.\r#\r#  timeout           -  Time to wait after the throttle was activated\r#                       before deactivating it. Be aware that the time\r#                       is seconds + timeout.\r#\r#  quitmsg           -  The message that users get if they attempt to\r#                       connect while the throttle is active.\r#\r#  bootwait          -  Amount of time to wait before enforcing the\r#                       throttling when the server just booted.\r#\r#<connflood seconds="30" maxconns="3" timeout="30"\r#   quitmsg="Throttled" bootwait="10">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# DCCALLOW module: Adds the /DCCALLOW command\r#<module name="m_dccallow.so">\r#\r#-#-#-#-#-#-#-#-#-#-#-  DCCALLOW CONFIGURATION   -#-#-#-#-#-#-#-#-#-#-#\r#  blockchat         - Whether to block DCC CHAT as well as DCC SEND\r#  length            - Default duration of entries in DCCALLOW list\r#  action            - Default action to take if no action is specified\r#                      can be 'block' or 'allow'\r#\r# File configuration:\r#  pattern           - The glob pattern to match against\r#  action            - Action to take if a user attempts to send a file\r#                      that matches this pattern, can be 'block' or 'allow'\r#\r#<dccallow blockchat="yes" length="5m" action="block">\r#<banfile pattern="*.exe" action="block">\r#<banfile pattern="*.txt" action="allow">\r#\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Deaf module: adds support for ircu style usermode +d - deaf to\r# channel messages and channel notices.\r#<module name="m_deaf.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Deny Channels: Deny Channels from being used by users\r#<module name="m_denychans.so"> \r#\r#-#-#-#-#-#-#-#-#-#-#-   DENYCHAN DEFINITIONS  -#-#-#-#-#-#-#-#-#-#-#-#\r#                                                                     #\r# If you have the m_denychans.so module loaded, you need to specify   #\r# the channels to deny:                                               #\r#                                                                     #\r# name        -      The channel name to deny.                        #\r#                                                                     #\r# allowopers  -      If operators are allowed to override the deny.   #\r#                                                                     #\r# reason      -      Reason given for the deny.                       #\r#                                                                     #\r#<badchan name="#gods" allowopers="yes" reason="Tortoises!">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Devoice Module: Let users devoice themselves.\r#<module name="m_devoice.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# DNS Blacklist Module: Provides support for looking up IPs on one or #\r# more blacklists.                                                    #\r#<module name="m_dnsbl.so">                                           #\r#                                                                     #\r# For configuration options please see the wiki page for m_dnsbl at   #\r# http://inspircd.org/wiki/DNS_Blacklist_Module                       #\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Filter module: Provides glob-based message filtering\r#<module name="m_filter.so">\r# OR\r# PCRE filter module: Filters messages using regular expressions\r#<module name="m_filter_pcre.so">\r#\r# You may only use one or the other with these modules, network-wide.\r#\r#-#-#-#-#-#-#-#-#-#-#-  FILTER  CONFIGURATION  -#-#-#-#-#-#-#-#-#-#-#-#\r#                                                                     #\r# Optional - If you specify to use the m_filter or m_filter_pcre      #\r# modules, then specfiy below the path to the filter.conf file,       #\r# or define some <filter> tags.                                       #\r#                                                                     #\r#<include file="filter.conf">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Foobar module: does nothing - historical relic\r#<module name="m_foobar.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Globops module: gives /GLOBOPS and usermode +g\r#<module name="m_globops.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Global load module: Allows loading and unloading of modules network-\r# wide (USE WITH EXTREME CAUTION!)\r#<module name="m_globalload.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# HELPOP module: Provides the /HELPOP command\r#<module name="m_helpop.so">\r#\r#-#-#-#-#-#-#-#-#-#-#-#-  HELPOP  CONFIGURATION  -#-#-#-#-#-#-#-#-#-#-#\r#                                                                     #\r# Optional - If you specify to use the m_helpop.so module, then       #\r# specify below the path to the helpop.conf file, or if you like to   #\r# make a mess, define your helpop tags in this conf.                  #\r#                                                                     #\r#<include file="helpop.conf">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# HIDECHANS module: Allows opers to hide their channels list from non-\r# opers by setting user mode +I on themselves.\r# <module name="m_hidechans.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# HIDEOPER module: Allows opers to hide their oper status from non-\r# opers by setting user mode +H on themselves.\r# <module name="m_hideoper.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Hostchange module: Allows a different style of cloaking\r#<module name="m_hostchange.so">\r#\r#-#-#-#-#-#-#-#-#-#-#-  HOSTCHANGE  CONFIGURATION  -#-#-#-#-#-#-#-#-#-#\r#                                                                     #\r# Optional - If you choose to use the m_hostchange.so module.         #\r# Config Help -  See http://www.inspircd.org/wiki/Host_Changer_Module #\r#                                                                     #\r#<host suffix="polarbears.org" separator="." prefix="">\r#<hostchange mask="*@fbi.gov" action="addnick">\r#<hostchange mask="*r00t@*" action="suffix">\r#<hostchange mask="a@b.com" action="set" value="blah.blah.blah">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# httpd module: Provides http server support for InspIRCd\r#<module name="m_httpd.so">\r#\r#-#-#-#-#-#-#-#-#-#-#-#-  HTTPD   CONFIGURATION  -#-#-#-#-#-#-#-#-#-#-#\r#\r# Optional - If you choose to use the m_httpd.so module,  then you must\r# specify the port number and other details of your http server:\r#\r#<http ip="192.168.1.10" host="brainwave" port="32006"\r#      index="/home/brain/inspircd/http/index.html">\r#\r# You may have as many of these tags as you wish, each with a different\r# IP, port, host or index file. Each one will act as an independent\r# HTTP server.\r#\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# http stats module: Provides basic stats pages over HTTP\r# Requires m_httpd.so to be loaded for it to function.\r#<module name="m_httpd_stats.so">\r#\r#-#-#-#-#-#-#-#-#-#-#-#- HTTPD STATS CONFIGURATION -#-#-#-#-#-#-#-#-#-#\r#\r#<httpstats stylesheet="http://remote.style/sheet.css">\r#\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Ident: Provides RFC 1413 ident lookup support\r#<module name="m_ident.so">\r#\r#-#-#-#-#-#-#-#-#-#-#-#-   IDENT CONFIGURATION   -#-#-#-#-#-#-#-#-#-#-#\r#                                                                     #\r# Optional - If you are using the m_ident.so module, then you can     #\r# specify the timeout for ident lookups here. If not defined, it will #\r# default to one second. This is a non-blocking timeout which holds   #\r# the user in a 'connecting' state until the lookup is complete.      #\r# The bind value indicates which IP to bind outbound requests to.     #\r#                                                                     #\r#<ident timeout="5" bind="">                                          #\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Invite except module: Adds support for channel invite exceptions (+I)\r#<module name="m_inviteexception.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Invisible module - Adds support for usermode +Q (quiet) which lets an\r# oper go 'invisible' similar to unrealircd 3.1's +I mode. Note that\r# opers are still able to see invisible users, and if an oper with +Q\r# deopers, they will become visible. \r\r# IMPORTANT NOTE: To allow this mode to be used by a type of oper, you\r# must first add the value canquiet="yes" to that oper's type tag.\r#\r#<module name="m_invisible.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Join flood module: Adds support for join flood protection (+j)\r#<module name="m_joinflood.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Jump Server module: Adds support for the RPL_REDIR numeric\r#<module name="m_jumpserver.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Anti-Auto-Rejoin: Adds support for prevention of auto-rejoin (+J)\r#<module name="m_kicknorejoin.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Knock module: adds the /KNOCK command and +K channel mode\r#<module name="m_knock.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Lock server module: Adds /LOCKSERV and /UNLOCKSERV commands that is #\r# used to temporarily close/open for new connections to the server.   #\r# These commands require OPER status and that the LOCKSERV UNLOCKSERV #\r# are specified in a <class> tag that the oper is part of. This is so #\r# you can control who has access to this possible dangerous command.  #\r# If your server is locked and you got disconnected, do a REHASH from #\r# shell to open up again.\r#<module name="m_lockserv.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Msg flood module: Adds message/notice flood protection (+f)\r#<module name="m_messageflood.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# MySQL module: Allows other SQL modules to access MySQL databases\r# through a unified API. You must copy the source for this module\r# from the directory src/modules/extra, plus the file m_sqlv2.h\r#<module name="m_mysql.so">\r#\r#-#-#-#-#-#-#-#-#-#-#-#- SQL CONFIGURATION   -#-#-#-#-#-#-#-#-#-#-#-#-#\r#                                                                     #\r# m_mysql.so is more complex than described here, see the wiki for    #\r# more: http://www.inspircd.org/wiki/SQL_Service_Provider_Module      #\r#\r#<database name="mydb" username="myuser" password="mypass" hostname="localhost" id="my_database2">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# NAMESX module: Provides support for the NAMESX extension which allows\r# clients to see all the prefixes set on a user without getting confused.\r# This is supported by mIRC, x-chat, klient, and maybe more.\r#<module name="m_namesx.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Nicklock module: Let opers change a user's nick and then stop that\r# user from changing their nick again.\r#<module name="m_nicklock.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# No ctcp module: Adds the channel mode +C to block CTCPs\r#<module name="m_noctcp.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Noinvite module: Gives channel mode +V\r#<module name="m_noinvite.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# No kicks module: Adds the +Q channel mode\r#<module name="m_nokicks.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# No nicks module: Adds the +N channel mode\r#<module name="m_nonicks.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# No Notice module: adds the channel mode +T\r#<module name="m_nonotice.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Oper channels mode: Adds the +O channel mode\r#<module name="m_operchans.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Oper hash module: Allows hashed oper passwords\r# Relies on the module m_md5.so and/or m_sha256.so being loaded before\r# m_oper_hash.so in the configuration file.\r#<module name="m_oper_hash.so">\r#\r#-#-#-#-#-#-#-#-#-#-# OPER HASH CONFIGURATION #-#-#-#-#-#-#-#-#-#-#-#-#\r#\r# To use this module, you must define a hash type for each oper's\r# password you want to hash. For example:\r#\r#     <oper name="Brain"\r#           host="ident@dialup15.isp.com"\r#           hash="sha256"\r#           password="a41d730937a53b79f788c0ab13e9e1d5"\r#           type="NetAdmin">\r\r# The types of hashing available vary depending on which hashing modules\r# you load, but usually if you load m_sha256.so and m_md5.so, both md5\r# and sha256 type hashing will be available (the most secure of which\r# is SHA256).\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Oper Join module: Forces opers to join a channel on oper-up\r#<module name="m_operjoin.so">\r#\r#-#-#-#-#-#-#-#-#-#-#   OPERJOIN CONFIGURATION   -#-#-#-#-#-#-#-#-#-#-#\r#                                                                     #\r# If you are using the m_operjoin.so module, specify the channel here #\r#                                                                     #\r#<operjoin channel="#channel">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Oper MOTD module: Provides support for seperate message of the day\r# on oper-up\r#<module name="m_opermotd.so">\r#\r#-#-#-#-#-#-#-#-#-#-#   OPERMOTD CONFIGURATION   -#-#-#-#-#-#-#-#-#-#-#\r#                                                                     #\r# If you are using the m_opermotd.so module, specify the motd here    #\r#                                                                     #\r#<opermotd file="oper.motd">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Override module: Adds support for oper override\r#<module name="m_override.so">\r#\r#-#-#-#-#-#-#-#-#-#-#   OVERRIDE CONFIGURATION   -#-#-#-#-#-#-#-#-#-#-#\r#                                                                     #\r# m_override.so is too complex it describe here, see the wiki:        #\r# http://www.inspircd.org/wiki/Oper_Override_Module                   #\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Oper levels module: Gives each oper a level and prevents\r# actions being taken against higher level opers\r# Specify the level as the 'level' parameter of the <type> tag\r#<module name="m_operlevels.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Oper modes module: Allows you to specify modes to add/remove on oper\r# Specify the modes as the 'modes' parameter of the <type> tag\r#<module name="m_opermodes.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# PostgreSQL module: Allows other SQL modules to access PgSQL databases\r# through a unified API. You must copy the source for this module\r# from the directory src/modules/extra, plus the file m_sqlv2.h\r#<module name="m_pgsql.so">\r#\r#-#-#-#-#-#-#-#-#-#-#-#- SQL CONFIGURATION   -#-#-#-#-#-#-#-#-#-#-#-#-#\r#                                                                     #\r# m_pgsql.so is more complex than described here, see the wiki for    #\r# more: http://www.inspircd.org/wiki/SQL_Service_Provider_Module      #\r#\r#<database name="mydb" username="myuser" password="mypass" hostname="localhost" id="my_database" ssl="no">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Random Quote module: provides a random quote on connect.\r# NOTE: Some of these may mimic fatal errors and confuse users and \r# opers alike! - BEWARE!\r#<module name="m_randquote.so">\r#\r#-#-#-#-#-#-#-#-#-#-  RANDOMQUOTES CONFIGURATION -#-#-#-#-#-#-#-#-#-#-#\r#                                                                     #\r# Optional - If you specify to use the m_randquote.so module, then    #\r# specify below the path to the randquotes.conf file.                 #\r#                                                                     #\r#<randquote file="randquotes.conf">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Redirect module: Adds channel redirection (mode +L)\r#<module name="m_redirect.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Registered users only channel creation\r# Allows only registered users and opers to create new channels.\r#<module name="m_regonlycreate.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Remove module: Adds the /REMOVE command which is a peaceful\r# alternative to /KICK\r#<module name="m_remove.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Restrict banned users module:\r# Disallows banned users on a channel from messaging the channel,\r# changing nick, or changing the topic, if loaded.\r#<module name="m_restrictbanned.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Restricted channels module: Allows only opers to create channels\r#<module name="m_restrictchans.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Restrict message module: Allows users to only message opers\r#<module name="m_restrictmsg.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Provide /LIST throttling (to prevent flooding) and /LIST safety to\r# prevent excess flood when the list is large.\r#<module name="m_safelist.so">\r#\r#-#-#-#-#-#-#-#-#-#-# SAFELIST CONFIGURATION -#-#-#-#-#-#-#-#-#-#-#-#-#\r#\r# When using Safelist, you may set the following values;\r#\r# The first value, 'throttle', sets the amount of time in seconds a user\r# must wait between LIST commands. For example, if this is set to 60\r# (the default) then the user may not /LIST more than once a minute.\r# If not defined, the default value is 60 seconds.\r#\r# The second value, 'maxlisters', indicates the maximum number of users\r# which may be retrieving a LIST at once. It is not recommended you raise\r# this value, as increasing it too high can make your network vulnerable\r# to floodbots which waste your bandwidth and CPU time with LIST requests.\r#\r#<safelist throttle="60" maxlisters="50">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# SAJOIN module: Adds the /SAJOIN command\r#<module name="m_sajoin.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# SAMODE module: Adds the oper /SAMODE command\r#<module name="m_samode.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# SANICK module: Allows opers to change user's nicks\r#<module name="m_sanick.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# SAPART module: Adds the oper /SAPART command\r#<module name="m_sapart.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# SAQUIT module: Adds the oper /SAQUIT command (abusable!!!)\r#<module name="m_saquit.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Secure list module: Prevent /LIST in the first minute of connection,\r# crippling most spambots and trojan spreader bots.\r#<module name="m_securelist.so">\r#\r#-#-#-#-#-#-#-#-#-# SECURELIST CONFIGURATION -#-#-#-#-#-#-#-#-#-#-#-#-#\r#                                                                     #\r# Securelist can be harmful to some irc search engines such as        #\r# netsplit.de and searchirc.com. To prevent securelist blocking these #\r# sites from listing, define exception tags as shown below:           #\r<securehost exception="*@*.searchirc.org">\r<securehost exception="*@*.netsplit.de">\r<securehost exception="*@echo940.server4you.de">\r#                                                                     #\r# Define the following variable to change how long a user must wait   #\r# before issuing a LIST. If not defined, defaults to 60 seconds.      #\r#                                                                     #\r#<securelist waittime="60">                                           #\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# See nicks module: Allow for SNOMASK +N which shows nick changes.\r#<module name="m_seenicks.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Set Idle module: Adds a command for opers to change their\r# idle time (mainly a toy)\r#<module name="m_setidle.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Services support module: Adds several usermodes such as +R and +M\r# this module implements the 'identified' state via user mode +r, which\r# is similar to the DALnet and dreamforge systems.\r#<module name="m_services.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Services support module: Adds several usermodes such as +R and +M\r# this module implements the 'identified' state via account names (AC)\r# and is similar in operation to the way asuka and ircu handle services.\r# it cannot be used at the same time as m_services, above.\r#<module name="m_services_account.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Sethost module: Adds the /SETHOST command\r# See m_chghost for how to customise valid chars for hostnames\r#<module name="m_sethost.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Setident module: Adds the /SETIDENT command\r#<module name="m_setident.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# SETNAME module: Adds the /SETNAME command\r#<module name="m_setname.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Show Whois module: Adds the +W usermode which allows opers\r# to see when they are whois'ed (can be annoying).\r#<module name="m_showwhois.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Spy module: Adds the commands SPYLIST and SPYNAMES that let opers\r# see who is in a +s channel, and list +s channels, show keys of keyed\r# channels the oper is not a member of etc. (standard 'abusive' features\r# of many other ircds, modulized here in InspIRCd).\r#<module name="m_spy.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# SSL channel mode module: Adds support for SSL-only channels (+z).\r# does not do anything useful without a working SSL module (see below)\r#<module name="m_sslmodes.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Dummy ssl module: If you have other servers on your network which\r# have SSL, but your server does not have ssl enabled, you should load\r# this module, which will handle SSL metadata (e.g. the "Is using ssl"\r# field in the WHOIS information).\r#<module name="m_ssl_dummy.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# GnuTLS ssl module: Adds support for client-server SSL using GnuTLS,\r# if enabled. You must copy the source for this module from the directory\r# src/modules/extra, or answer 'yes' in ./configure when asked if you\r# want to enable this, or it will not load.\r#<module name="m_ssl_gnutls.so">\r#\r#-#-#-#-#-#-#-#-#-#-#-  GNUTLS CONFIGURATION   -#-#-#-#-#-#-#-#-#-#-#-#\r#                                                                     #\r# m_ssl_gnutls.so is too complex it describe here, see the wiki:      #\r# http://www.inspircd.org/wiki/GnuTLS_SSL_Module                      #\r#                                                                     #\r# NOTE: If you want to use this module to encrypt and sign your       #\r# server to server traffic, you MUST load it before m_spanningtree in #\r# your configuration file!                                            #\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# SSL Info module: Allows users to retrieve information about other\r# user's peer SSL certificates and keys. This can be used by client\r# scripts to validate users. For this to work, one of m_ssl_gnutls.so\r# or m_ssl_openssl.so must be loaded. You must symlink the source for\r# this module from the directory src/modules/extra.\r#<module name="m_sslinfo.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# OpenSSL ssl module: Adds support for client-server SSL using OpenSSL,\r# if enabled. You must copy the source for this module from the directory\r# src/modules/extra, or answer 'yes' in ./configure when asked if you\r# want to enable this, or it will not load.\r#<module name="m_ssl_openssl.so">\r#\r#-#-#-#-#-#-#-#-#-#-#- OPENSSL CONFIGURATION   -#-#-#-#-#-#-#-#-#-#-#-#\r#                                                                     #\r# m_ssl_openssl.so is too complex it describe here, see the wiki:     #\r# http://www.inspircd.org/wiki/OpenSSL_SSL_Module                     #\r#                                                                     #\r# NOTE: If you want to use this module to encrypt and sign your       #\r# server to server traffic, you MUST load it before m_spanningtree in #\r# your configuration file!                                            #\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# SSL Cert Oper module: Allows opers to oper up using the key fingerprint\r# stored within their SSL certificate and key pair.\r# When using this module, one of m_ssl_gnutls.so or m_ssl_openssl.so must\r# be loaded. An extra value should be added to enabled opers, which\r# is in the following format: fingerprint="<hash>". For more information,\r# see the example in the oper blocks.\r#<module name="m_ssl_oper_cert.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Strip colour module: Adds the channel mode +S\r#<module name="m_stripcolor.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# SILENCE module: Adds support for /SILENCE\r#<module name="m_silence.so">\r#\r# Configuration tags:\r#\r#<silence maxentries="32">\r#\r# Sets the maximum number of entries on a users silence list.\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Extended SILENCE module: Adds support for /SILENCE with additional\r# features to silence based on invites, channel messages, etc.\r#<module name="m_silence_ext.so">\r#\r# The configuration tags for this module are identical to those of\r# m_silence, shown above.\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# SQLite3 module: Allows other SQL modules to access SQLite3          #\r# databases through a unified API. You must link the source for this  #\r# module from the directory src/modules/extra to src/modules, plus    #\r# the file m_sqlv2.h                                                  #\r#<module name="m_sqlite3.so">\r#\r#-#-#-#-#-#-#-#-#-#-#-#- SQL CONFIGURATION   -#-#-#-#-#-#-#-#-#-#-#-#-#\r#                                                                     #\r# m_sqlite.so is more complex than described here, see the wiki for   #\r# more: http://www.inspircd.org/wiki/SQLite3_Service_Provider_Module  #\r#\r#<database hostname="/full/path/to/database.db" id="anytext">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# SQLutils module: Provides some utilities to SQL client modules, such\r# as mapping queries to users and channels. You must copy the source\r# for this module from the directory src/modules/extra/m_sqlutils.cpp\r# and src/modules/extra/m_sqlutils.h into /src/modules\r# Needed for, and loaded before: SQLauth and SQLoper\r#<module name="m_sqlutils.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# SQL authentication module: Allows IRCd connections to be tied into\r# a database table (for example a forum). You must copy the source for\r# this module from the directory src/modules/extra\r# Depends on the SQLutils module being loaded first.\r#<module name="m_sqlauth.so">\r#\r#-#-#-#-#-#-#-#-#-#-#- SQLAUTH CONFIGURATION   -#-#-#-#-#-#-#-#-#-#-#-#\r#                                                                     #\r# m_sqlauth.so is too complex it describe here, see the wiki:         #\r# http://www.inspircd.org/wiki/SQL_Authentication_Module              #\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# SQL logging module: Allows you to log network-wide data for your\r# network in a fully normalized set of SQL tables. You must copy the\r# source for this module from the directory src/modules/extra\r#<module name="m_sqllog.so">\r#\r#-#-#-#-#-#-#-#-#-#-#-  SQLLOG CONFIGURATION   -#-#-#-#-#-#-#-#-#-#-#-#\r#                                                                     #\r# dbid       - Database ID to use (see m_sql)                         #\r#                                                                     #\r# See also: http://www.inspircd.org/wiki/SQL_Logging_Module           #\r#                                                                     #\r#<sqllog dbid="1">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# SQL oper module: Allows you to store oper credentials in an SQL table\r# You must copy the source for this module from the directory src/modules/extra\r# Depends on the SQLutils module being loaded first.\r#<module name="m_sqloper.so">\r#\r#-#-#-#-#-#-#-#-#-#-#- SQLOPER CONFIGURATION   -#-#-#-#-#-#-#-#-#-#-#-#\r#                                                                     #\r# dbid       - Database ID to use (see m_sql)                         #\r#                                                                     #\r# See also: http://www.inspircd.org/wiki/SQL_Oper_Storage_Module      #\r#                                                                     #\r#<sqloper dbid="1">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# SVSHold module: Implements SVSHOLD. Like Q:Lines, but can only be   #\r# added/removed by Services.                                          #\r#<module name="m_svshold.so">\r\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# SWHOIS module: Allows you to add arbitary lines to user WHOIS.\r#<module name="m_swhois.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Test command module: Does nothing significant. Read: pointless.\r#<module name="m_testcommand.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Timed bans module: Adds timed bans and the /TBAN command\r#<module name="m_timedbans.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Test line module: Adds the /TLINE command, used to test how many\r# users a /GLINE or /ZLINE etc would match.\r#<module name="m_tline.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# UHNAMES support module: Adds support for the IRCX style UHNAMES\r# extension, which displays ident and hostname in the names list for\r# each user, saving clients from doing a WHO on the channel. Note that\r# this module is not widely supported yet. If a client does not support\r# UHNAMES it will not enable it, this will not break incompatible\r# clients.\r#<module name="m_uhnames.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Uninvite module: Adds the /UNINVITE command which lets users remove\r# pending invites from channels without waiting for the user to join.\r#<module name="m_uninvite.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Userip module: Adds the /USERIP command\r#<module name="m_userip.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Vhost module: Adds the VHOST command which allows for adding virtual\r# hosts which are accessible using a username and password in the config.\r#<module name="m_vhost.so">\r#\r#-#-#-#-#-#-#-#-#-#-#- VHOST CONFIGURATION   -#-#-#-#-#-#-#-#-#-#-#-#-#\r#                                                                     #\r# user       - Username for the vhost.                                #\r#                                                                     #\r# pass       - Password for the vhost.                                #\r#                                                                     #\r# host       - Vhost to set.                                          #\r#\r#<vhost user="some_username" pass="some_password" host="some.host">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# Watch module: Adds the WATCH command, which is used by clients to \r# maintain notify lists.\r#<module name="m_watch.so">\r#\r# Configuration tags:\r#\r#<watch maxentries="32">\r#\r# Sets the maximum number of entries on a user's watch list.\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# XMLSocket module: Adds support for connections using the shockwave\r# flash XMLSocket. Note that this does not work if the client you are\r# using has retarded ideas of the IRC protocol. Your client must still\r# send RFC-correct lines to the server, this module only changes the\r# line ending from newlines to null terminators.\r#\r#<module name="m_xmlsocket.so">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r# ZipLinks module: Adds support for zlib deflate on server to server\r# connections. Both ends of the connection must load this module.\r#\r#<module name="m_ziplink.so">\r#\r# To use this module, you must enable it as a transport type in your\r# <link> tags or <bind> tags using the transport name 'zip'.\r# See the documentation of <link> and <bind>, respectively.\r#\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-  BAN OPTIONS  -#-#-#-#-#-#-#-#-#-#-#-#-#-#\r#                                                                     #\r# The ban tags define nick masks, host masks and ip ranges which are  #\r# banned from your server. All details in these tags are local to     #\r# Your server.                                                        #\r#                                                                     #\r#                                                                     #\r# badip lines ban an ip range (same as a zline)                       #\r#                                                                     #\r# ipmask       -          The ip range to ban (wildcards possible)    #\r#                         CIDR is supported in the IP mask.           #\r# reason       -          Reason to display when disconnected         #\r#                                                                     #\r# badnick lines ban a nick mask (same as a qline)                     #\r#                                                                     #\r# nick         -          Nick mask to ban (wildcards possible)       #\r# reason       -          Reason to display on /NICK                  #\r#                                                                     #\r# badhost lines ban a user@host mask (same as a kline)                #\r#                                                                     #\r# host         -          ident@hostname (wildcards possible)         #\r#                         If you specify an IP, CIDR is supported.    #\r# reason       -          Reason to display on disconnection          #\r#                                                                     #\r# exception lines define a hostmask that is excempt from [kzg]lines   #\r#                                                                     #\r# host         -          ident@hostname (wildcards possible)         #\r#                         If you specify an IP, CIDR is supported.    #\r# reason       -          Reason, shown only in /stats e              #\r#                                                                     #\r\r<badip ipmask="69.69.69.69" reason="No porn here thanks.">\r\r<badnick nick="ChanServ" reason="Reserved For Services">\r<badnick nick="NickServ" reason="Reserved For Services">\r<badnick nick="OperServ" reason="Reserved For Services">\r<badnick nick="MemoServ" reason="Reserved For Services">\r\r<badhost host="*@hundredz.n.hundredz.o.1337.kiddies.com" reason="Too many 1337 kiddiots">\r<badhost host="*@localhost" reason="No irc from localhost!">\r<badhost host="*@172.32.0.0/16" reason="This subnet is bad.">\r\r<exception host="*@ircop.host.com" reason="Opers hostname">\r\r#-#-#-#-#-#-#-#-#-#-#- INSANE BAN OPTIONS  -#-#-#-#-#-#-#-#-#-#-#-#-#-#\r#                                                                     #\r# This optional tag allows you to specify how wide a gline, eline,    #\r# kline, zline or qline can be before it is forbidden from being      #\r# set. By setting hostmasks="yes", you can allow all G, K, E lines,   #\r# no matter how many users the ban would cover. This is not           #\r# recommended! By setting ipmasks="yes", you can allow all Z lines,   #\r# no matter how many users these cover too. Needless to say we        #\r# don't recommend you do this, or, set nickmasks="yes", which will    #\r# allow any qline.                                                    #\r#                                                                     #\r# The trigger value indicates how wide any mask will be before it is  #\r# prevented from being set. The default value is 95.5% if this tag is #\r# not defined in your configuration file, meaning that if your        #\r# network has 1000 users, a gline matching over 955 of them will be   #\r# prevented from being added.                                         #\r#                                                                     #\r# Please note that remote servers (and services) are exempt from      #\r# these restrictions and expected to enforce their own policies       #\r# locally!                                                            #\r#                                                                     #\r\r<insane hostmasks="no" ipmasks="no" nickmasks="no" trigger="95.5">\r\r#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#- YAWN  -#-#-#-#-#-#-#-#-#-#-#-#-#-#-#\r#                                                                     #\r#   You should already know what to do here :)                        #\r\r<die value="User error. Insert new user and press any key. (you didn't edit your config properly.)">\r\r\r#########################################################################\r#                                                                       #\r#                     - InspIRCd Development Team -                     #\r#                        http://www.inspircd.org                        #\r#                                                                       #\r#########################################################################\r
\ No newline at end of file
+########################################################################
+#                                                                      #
+#               ___                ___ ____   ____    _                #
+#              |_ _|_ __  ___ _ __|_ _|  _ \ / ___|__| |               #
+#               | || '_ \/ __| '_ \| || |_) | |   / _` |               #
+#               | || | | \__ \ |_) | ||  _ <| |__| (_| |               #
+#              |___|_| |_|___/ .__/___|_| \_\\____\__,_|               #
+#                            |_|                                       #
+#      ____             __ _                       _   _               #
+#     / ___|___  _ __  / _(_) __ _ _   _ _ __ __ _| |_(_) ___  _ __    #
+#    | |   / _ \| '_ \| |_| |/ _` | | | | '__/ _` | __| |/ _ \| '_ \   #
+#    | |__| (_) | | | |  _| | (_| | |_| | | | (_| | |_| | (_) | | | |  #
+#     \____\___/|_| |_|_| |_|\__, |\__,_|_|  \__,_|\__|_|\___/|_| |_|  #
+#                            |___/                                     #
+#                                                                      #
+##################################||####################################
+                                 #||#                                   
+##################################||####################################
+#                                                                      #
+#         This is an example of the config file for InspIRCd.          #
+#             Change the options to suit your network                  #
+#                                                                      #
+#     $Id$
+#                                                                      #
+#    ____                _   _____ _     _       ____  _ _   _         #
+#   |  _ \ ___  __ _  __| | |_   _| |__ (_)___  | __ )(_) |_| |        #
+#   | |_) / _ \/ _` |/ _` |   | | | '_ \| / __| |  _ \| | __| |        #
+#   |  _ <  __/ (_| | (_| |   | | | | | | \__ \ | |_) | | |_|_|        #
+#   |_| \_\___|\__,_|\__,_|   |_| |_| |_|_|___/ |____/|_|\__(_)        #
+#                                                                      #
+#   Lines prefixed with READ THIS BIT, as shown above, are IMPORTANT   #
+#   lines, and you REALLY SHOULD READ THEM. Yes, THIS MEANS YOU. Even  #
+#   if you've configured InspIRCd before, these probably indicate      #
+#   something new or different to this version and you SHOULD READ IT. #
+#                                                                      #
+########################################################################
+#                                                                      #
+#         Unalphabeticalise the modules list at your own risk          #
+#                                                                      #
+########################################################################
+
+
+#-#-#-#-#-#-#-#-#-#-#-#-  SERVER DESCRIPTION  -#-#-#-#-#-#-#-#-#-#-#-#-
+#                                                                     #
+#   Here is where you enter the information about your server.        #
+#                                                                     #
+#  Syntax is as follows:                                              #
+#                                                                     #
+#     <server name="server.name"                                      #
+#      description="Server Description"                               #
+#      networkemail="Email address shown on g/k/z/q lines"            #
+#      network="MyNetwork">                                           #
+#                                                                     #
+
+<server name="penguin.omega.org.za"
+        description="Waddle World"
+       network="Omega">
+
+
+#-#-#-#-#-#-#-#-#-#-#-#-   ADMIN INFORMATION   -#-#-#-#-#-#-#-#-#-#-#-#
+#                                                                     #
+#   Describes the Server Administrator's real name (optionally),      #
+#   nick, and email address.                                          #
+#                                                                     #
+#  Syntax is as follows:                                              #
+#       <admin name="real name"                                       #
+#              nick="nick name"                                       #
+#              email="email@address.com">                             #
+#                                                                     #
+
+<admin name="Johnny English"
+       nick="MI5"
+       email="MI5@the.best.secret.agent">
+
+
+#-#-#-#-#-#-#-#-#-#-#-#-   PORT CONFIGURATION   -#-#-#-#-#-#-#-#-#-#-#-
+#                                                                     #
+#   Enter the port and address bindings here.                         #
+#                                                                     #
+#  bind address - specifies which address ports bind to. Leaving this #
+#                 field blank binds the port to all IPs available.    #
+#                                                                     #
+#  port         - The port number to bind to. You may specify a port  #
+#                 range here, e.g. "6667-6669,7000,7001". If you do   #
+#                 this, the server will count each port within your   #
+#                 range as a seperate binding, making the above       #
+#                 example equivalent to five seperate bind tags.      #
+#                 A failure on one port in the range does not prevent #
+#                 the entire range from being bound, just that one    #
+#                 port number.                                        #
+#                                                                     #
+#  type         - can be 'clients' or 'servers'. The clients type is  #
+#                 a standard tcp based socket, the servers type is a  #
+#                 also a TCP based connection but of a different      #
+#                 format. SSL support is provided by modules, to      #
+#                 enable SSL support, please read the module section  #
+#                 of this configuration file.                         #
+#                                                                     #
+#  ssl          - When using m_ssl_gnutls.so or m_ssl_openssl.so      #
+#                 modules, you must define this value to use ssl on   #
+#                 that port. valid values are 'gnutls' or 'openssl'   #
+#                 respectively. If the module is not loaded, this     #
+#                 setting is ignored.                                 #
+#                                                                     #
+#  transport    - If you have m_spanningtree.so loaded, along with    #
+#                 either of the SSL modules (m_ssl_gnutls or          #
+#                 m_ssl_openssl) or m_ziplinks.so, then you may make  #
+#                 use of this value.                                  #
+#                 setting it to 'openssl' or 'gnutls' or 'zip'        #
+#                 indicates that the port should accept connections   #
+#                 using the given transport name. Transports are      #
+#                 layers which sit on top of a socket and change the  #
+#                 way data is sent and received, e.g. encryption,     #
+#                 compression, and other such things. Because this    #
+#                 may not be limited in use to just encryption,       #
+#                 the 'ssl' value used for client ports does not      #
+#                 exist for servers, and this value is used instead.  #
+#    ____                _   _____ _     _       ____  _ _   _        #
+#   |  _ \ ___  __ _  __| | |_   _| |__ (_)___  | __ )(_) |_| |       #
+#   | |_) / _ \/ _` |/ _` |   | | | '_ \| / __| |  _ \| | __| |       #
+#   |  _ <  __/ (_| | (_| |   | | | | | | \__ \ | |_) | | |_|_|       #
+#   |_| \_\___|\__,_|\__,_|   |_| |_| |_|_|___/ |____/|_|\__(_)       #
+#                                                                     #
+#  If you want to link servers to InspIRCd you must load the          #
+#  m_spanningtree module! Please see the modules list below for       #
+#  information on how to load this module! If you do not load this    #
+#  module, server ports will NOT be bound!                            #
+#                                                                     #
+#  Leaving address empty binds to all available interfaces            #
+#                                                                     #
+#  Syntax is as follows:                                              #
+#                                                                     #
+# <bind address="ip address" port="port" type="clients">              #
+# <bind address="ip address" port="port" type="servers">              #
+#                                                                     #
+# If InspIRCd is built for IPV6, and you wish to accept IPV4 clients, #
+# then you can specify IPV4 ip addresses here to bind. You may also   #
+# use the 4in6 notation, ::ffff:1.2.3.4, where 1.2.3.4 is the IPV4    #
+# address to bind the port, but as of InspIRCd 1.1.1, this is not     #
+# required.                                                           #
+#                                                                     #
+# ------------------------------------------------------------------- #
+#                                                                     #
+# PLEASE NOTE: If you have build InspIRCd as an ipv6 server, and you  #
+# specify an empty bind address, the binding will be bound to ALL THE #
+# IPV6 IP ADDRESSES, and not the ipv4 addresses. If you are using an  #
+# ipv6 enabled InspIRCd and want to bind to multiple IPV4 addresses   #
+# in this way, you must specify them by hand. If you have built the   #
+# server for ipv4 connections only, then specifying an empty bind     #
+# address binds the port to all ipv4 IP addresses, as expected.       #
+#                                                                     #
+
+<bind address="" port="6000" type="clients">
+<bind address="" port="6660-6669" type="clients" ssl="gnutls">
+
+# When linking servers, the openssl and gnutls transports are largely
+# link-compatible and can be used alongside each other or either/or
+# on each end of the link without any significant issues.
+
+<bind address="" port="7000,7001" type="servers">
+<bind address="1.2.3.4" port="7005" type="servers" transport="openssl">
+
+
+#-#-#-#-#-#-#-#-#-#-  DIE/RESTART CONFIGURATION   -#-#-#-#-#-#-#-#-#-#-
+#                                                                     #
+#   You can configure the passwords here which you wish to use for    #
+#   the die and restart commands. Only trusted ircops who will        #
+#   need this ability should know the die and restart password.       #
+#                                                                     #
+#  Syntax is as follows:                                              #
+#       <power diepass="die password" restartpass="restart password"  #
+#        pause="secs before dying">                                   #
+#                                                                     #
+
+<power diepass="" restartpass="" pause="2">
+
+
+#-#-#-#-#-#-#-#-#-#  INCLUDE CONFIGURATION  #-#-#-#-#-#-#-#-#-#-#-#-#-#
+#                                                                     #
+# This optional tag allows you to include another config file         #
+# allowing you to keep your configuration tidy. The configuration     #
+# file you include will be treated as part of the configuration file  #
+# which includes it, in simple terms the inclusion is transparent.    #
+#                                                                     #
+# All paths to config files are relative to the directory of the main #
+# config file inspircd.conf, unless the filename starts with a forward#
+# slash (/) in which case it is treated as an absolute path.          #
+#                                                                     #
+# Syntax is as follows:                                               #
+#<include file="file.conf">                                           #
+#                                                                     #
+
+#-#-#-#-#-#-#-#-#-#-  CONNECTIONS CONFIGURATION  -#-#-#-#-#-#-#-#-#-#-#
+#                                                                     #
+#   This is where you can configure which connections are allowed     #
+#   and denied access onto your server. The password is optional.     #
+#   You may have as many of these as you require. To allow/deny all   #
+#   connections, use a '*' or 0.0.0.0/0.                              #
+#                                                                     #
+#  Syntax is as follows:                                              #
+#                                                                     #
+#       <connect allow="1.2.3.0/24" password="blahblah"               #
+#                timeout="10" timeout="blah" flood="5"                #
+#                threshold="8" pingfreq="120" sendq="99999"           #
+#                revcq="696969" localmax="3" globalmax="3"            #
+#                port="6660">                                         #
+#                                                                     #
+#       <connect deny="127.0.0.1" port="6667">                        #
+#                                                                     #
+#   IP masks may be specified in CIDR format or wildcard format,      #
+#   for IPV4 and IPV6. You *cannot* use hostnames in the allow or     #
+#   deny field, as the state is applied before the user's DNS has     #
+#   been resolved.                                                    #
+#                                                                     #
+#   You may optionally include timeout="x" on any allow line, which   #
+#   specifies the amount of time given before an unknown connection   #
+#   is closed if USER/NICK/PASS are not given. This value is in secs  #
+#                                                                     #
+#   You should also include a flood="x" line which indicates          #
+#   the number of lines a user may place into their buffer at once    #
+#   before they are disconnected for excess flood. This feature can   #
+#   not be disabled, however it can be set to extremely high values,  #
+#   rendering it effectively disabled. A recommended value is 10.     #
+#   A counter is maintained for each user which is reset every        #
+#   'threshold' seconds and specifying this threshold value with      #
+#   threshold="X" indicates how often the counter is reset. For       #
+#   example, with flood="5" and threshold="8", the user may not send  #
+#   more than 5 lines in 8 secs.                                      #
+#                                                                     #
+#   You may optionally specify the sendq size and ping frequency of   #
+#   each connect:allow line using the pingfreq="X" and sendq="X"      #
+#   settings as shown in the full example below.                      #
+#   The ping frequency is specified in seconds, and the sendq size    #
+#   in bytes. It is recommended, although not enforced, that you      #
+#   should never set your sendq size to less than 8k. Send Queues are #
+#   dynamically allocated and can grow as needed up to the maximum    #
+#   size specified.                                                   #
+#                                                                     #
+#   The optional recvq value is the maximum size which users in this  #
+#   group may grow their receive queue to. This is recommended to be  #
+#   kept pretty low compared to the sendq, as users will always       #
+#   receive more than they send in normal circumstances. The default  #
+#   if not specified is 4096.                                         #
+#                                                                     #
+#   The sendq is the data waiting to be sent TO THE USER.             #
+#   The recvq is the data being received FROM THE USER.               #
+#   The names sendq and recvq are from the SERVER'S PERSPECTIVE not   #
+#   that of the user... Just to clear up any confusion or complaints  #
+#   that these are backwards :p                                       #
+#                                                                     #
+#   The localmax and globalmax values can be used to enforce local    #
+#   and global session limits on connections. The session limits are  #
+#   counted against all users, but applied only to users within the   #
+#   class. For example, if you had a class 'A' which has a session    #
+#   limit of 3, and a class 'B' which has a session limit of 5, and   #
+#   somehow, two users managed to get into class B which also match   #
+#   class A, there is only one connection left for this IP now in A,  #
+#   but if they can connect again to B, there are three. You get the  #
+#   idea (i hope).                                                    #
+#                                                                     #
+#   The optional port value determines which port the connect tag is  #
+#   handling. If left out the connect tag covers all bound ports else #
+#   only incoming connections on the specified port will match. Port  #
+#   tags may be used on connect allow and connect deny tags.          #
+#                                                                     #
+
+<connect allow="196.12.*"  password="secret" port="6667">
+
+<connect allow="*"
+         timeout="60"
+         flood="20"
+         threshold="1"
+         pingfreq="120"
+         sendq="262144"
+         recvq="8192"
+         localmax="3"
+         globalmax="3">
+
+<connect deny="69.254.*">
+<connect deny="3ffe::0/32">
+
+
+#-#-#-#-#-#-#-#-#-#-#-#-  CLASS CONFIGURATION   -#-#-#-#-#-#-#-#-#-#-#-
+#                                                                     #
+#   Classes are a group of commands which are grouped together        #
+#   and given a unique name. They used to define which commands       #
+#   are available to certain types of Operators.                      #
+#                                                                     #
+#  Syntax is as follows:                                              #
+#                                                                     #
+#       <class name="name" commands="oper commands">                  #
+#                                                                     #
+#    ____                _   _____ _     _       ____  _ _   _        #
+#   |  _ \ ___  __ _  __| | |_   _| |__ (_)___  | __ )(_) |_| |       #
+#   | |_) / _ \/ _` |/ _` |   | | | '_ \| / __| |  _ \| | __| |       #
+#   |  _ <  __/ (_| | (_| |   | | | | | | \__ \ | |_) | | |_|_|       #
+#   |_| \_\___|\__,_|\__,_|   |_| |_| |_|_|___/ |____/|_|\__(_)       #
+#                                                                     #
+#  You are not forced to give these classes the names given below.    #
+#  You can create your own named classes, if you want, in fact that   #
+#  is the whole idea of this system!                                  #
+#                                                                     #
+#  Note: It is possible to make a class which covers all available    #
+#  commands. To do this, specify commands="*". This is not really     #
+#  recommended, as it negates the whole purpose of the class system,  #
+#  however it is provided for fast configuration (e.g. in test nets)  #
+#                                                                     #
+
+<class name="Shutdown" commands="DIE RESTART REHASH LOADMODULE UNLOADMODULE RELOAD">
+<class name="ServerLink" commands="CONNECT SQUIT RCONNECT MKPASSWD MKSHA256">
+<class name="BanControl" commands="KILL GLINE KLINE ZLINE QLINE ELINE">
+<class name="OperChat" commands="WALLOPS GLOBOPS SETIDLE SPYLIST SPYNAMES">
+<class name="HostCloak" commands="SETHOST SETIDENT SETNAME CHGHOST CHGIDENT">
+
+
+#-#-#-#-#-#-#-#-#-#-#-#-  OPERATOR COMPOSITION   -#-#-#-#-#-#-#-#-#-#-#
+#                                                                     #
+#   This is where you specify which types of operators you have on    #
+#   your server, as well as the commands they are allowed to use.     #
+#   This works alongside with the classes specified above.            #
+#                                                                     #
+#  type name  - a name for the combined class types                   #
+#               a type name cannot contain spaces, however if you     #
+#               put an _ symbol in the name, it will be translated    #
+#               to a space when displayed in a WHOIS.                 #
+#                                                                     #
+#  classes    - specified above, used for flexibility for the         #
+#               server admin to decide on which operators get         #
+#               what commands. Class names are case sensitive,        #
+#               seperate multiple class names with spaces.            #
+#                                                                     #
+#  host       - optional hostmask operators will receive on oper-up.  #
+#                                                                     #
+#  Syntax is as follows:                                              #
+#                                                                     #
+#     <type name="name" classes="class names" host="oper hostmask">   #
+#                                                                     #
+#    ____                _   _____ _     _       ____  _ _   _        #
+#   |  _ \ ___  __ _  __| | |_   _| |__ (_)___  | __ )(_) |_| |       #
+#   | |_) / _ \/ _` |/ _` |   | | | '_ \| / __| |  _ \| | __| |       #
+#   |  _ <  __/ (_| | (_| |   | | | | | | \__ \ | |_) | | |_|_|       #
+#   |_| \_\___|\__,_|\__,_|   |_| |_| |_|_|___/ |____/|_|\__(_)       #
+#                                                                     #
+#  You are not forced to give these types the names given below.      #
+#  You can create your own named types, if you want, in fact that     #
+#  is the whole idea of this system!                                  #
+#                                                                     #
+
+<type name="NetAdmin" classes="OperChat BanControl HostCloak Shutdown ServerLink" host="netadmin.omega.org.za">
+<type name="GlobalOp" classes="OperChat BanControl HostCloak ServerLink" host="ircop.omega.org.za">
+<type name="Helper" classes="HostCloak" host="helper.omega.org.za">
+
+
+#-#-#-#-#-#-#-#-#-#-#-  OPERATOR CONFIGURATION   -#-#-#-#-#-#-#-#-#-#-#
+#                                                                     #
+#   Opers are defined here. This is a very important section.         #
+#   Remember to only make operators out of truthworthy people.        #
+#                                                                     #
+#  name        - oper name, This is case sensitive, so it is best to  #
+#                use lower-case.                                      #
+#                                                                     #
+#  password    - password to oper-up, also case sensitive.            #
+#                encryption is supported via modules. You may load    #
+#                modules for MD5 or SHA256 encryption, and if you do, #
+#                this value will be a hash value, otherwise put a     #
+#                plaintext password in this value.                    #
+#                                                                     #
+#  host        - hosts of client allowed to oper-up.                  #
+#                wildcards accepted, seperate multiple hosts with a   #
+#                space. You may also specify CIDR ip addresses.       #
+#                                                                     #
+#  fingerprint - When using the m_ssl_oper_cert.so module, you may    #
+#                specify a key fingerprint here. This can be obtained #
+#                using the /fingerprint command whilst the module is  #
+#                loaded, or from the notice given to you when you     #
+#                connect to the ircd using a client certificate,      #
+#                and will lock this oper block to only the user who   #
+#                has that specific key/certificate pair.              #
+#                This enhances security a great deal, however it      #
+#                requires that opers use clients which can send ssl   #
+#                client certificates, if this is configured for that  #
+#                oper. Note that if the m_ssl_oper.so module is not   #
+#                loaded, and/or one of m_ssl_openssl or m_ssl_gnutls  #
+#                is not loaded, this configuration option has no      #
+#                effect and will be ignored.                          #
+#                                                                     #
+#  type        - Defines the kind of operator. This must match a type #
+#                tag you defined above, and is case sensitive.        #
+#                                                                     #
+#  Syntax is as follows:                                              #
+#       <oper name="login"                                            #
+#             password="pass"                                         #
+#             host="hostmask@of.oper"                                 #
+#           fingerprint="hexsequence"                               #
+#             type="oper type">                                       #
+#                                                                     #
+
+<oper name="Brain"
+      password="s3cret"
+      host="ident@dialup15.isp.com *@localhost *@server.com *@3ffe::0/16"
+      type="NetAdmin">
+
+
+#-#-#-#-#-#-#-#-#-#-#-  SERVER LINK CONFIGURATION  -#-#-#-#-#-#-#-#-#-#
+#                                                                     #
+# Defines which servers can link to this one, and which servers this  #
+# server may create outbound links to.                                #
+#                                                                     #
+# name        -   The name is the canocial name of the server, does   #
+#                 not have to resolve - but it is expected to be set  #
+#                 in the remote servers connection info.              #
+#                                                                     #
+# ipaddr      -   Valid host or ip address for remote server. These   #
+#                 hosts are resolved on rehash, and cached, if you    #
+#                 specify a hostname, so if you find that your server #
+#                 is still trying to connect to an old IP after you   #
+#                 have updated your dns, try rehashing and then       #
+#                 attempting the connect again.                       #
+#                                                                     #
+# port        -   The TCP port for the remote server.                 #
+#                                                                     #
+# sendpass    -   Password to send to create an outbound connection   #
+#                 to this server.                                     #
+#                                                                     #
+# recvpass    -   Password to receive to accept an inbound connection #
+#                 from this server.                                   #
+#                                                                     #
+# autoconnect -   Sets the server to autoconnect. Where x is the num. #
+# (optional)      of seconds between attempts. e.g. 300 = 5 minutes.  #
+#                                                                     #
+# transport     - If defined, this is a transport name implemented by #
+#                 another module. Transports are layers on top of     #
+#                 plaintext connections, which alter them in certain  #
+#                 ways. Currently the three supported transports are  #
+#                 'openssl' and 'gnutls' which are types of SSL       #
+#                 encryption, and 'zip' which is for compression.     #
+#                 If you define a transport, both ends of the         #
+#                 connection must use a compatible transport for the  #
+#                 link to succeed. OpenSSL and GnuTLS are link-       #
+#                 compatible with each other.                         #
+#                                                                     #
+# statshidden   - When using m_spanningtree.so for linking. you may   #
+#                 set this to 'yes', and if you do, the IP address/   #
+#                 hostname of this connection will NEVER be shown to  #
+#                 any opers on the network. In /STATS c its address   #
+#                 will show as *@<hidden>, and during CONNECT and     #
+#                 inbound connections, its IP will show as <hidden>   #
+#                 UNLESS the connection fails (e.g. due to a bad      #
+#                 password or servername)                             #
+#                                                                     #
+# allowmask     - When this is defined, it indicates a range of IP    #
+#                 addresses to allow for this link (You may use CIDR  #
+#                 or wildcard form for this address).                 #
+#                 e.g. if your server is going to connect to you from #
+#                 the range 1.2.3.1 through 1.2.3.255, put 1.2.3.0/24 #
+#                 into this value. If it is not defined, then only    #
+#                 the ipaddr field of the server shall be allowed.    #
+#                                                                     #
+# failover      - If you define this option, it must be the name of a #
+#                 different link tag in your configuration. This      #
+#                 option causes the ircd to attempt a connection to   #
+#                 the failover link in the event that the connection  #
+#                 to this server fails. For example, you could define #
+#                 two hub uplinks to a leaf server, and set an        #
+#                 american server to autoconnect, with a european     #
+#                 hub as its failover. In this situation, your ircd   #
+#                 will only try the link to the european hub if the   #
+#                 american hub is unreachable. NOTE that for the      #
+#                 intents and purposes of this option, an unreachable #
+#                 server is one which DOES NOT ANSWER THE CONNECTION. #
+#                 If the server answers the connection with accept(), #
+#                 EVEN IF THE CREDENTIALS ARE INVALID, the failover   #
+#                 link will not be tried! Failover settings will also #
+#                 apply to autoconnected servers as well as manually  #
+#                 connected ones.                                     #
+#                                                                     #
+# timeout       - If this is defined, then outbound connections will  #
+#                 time out if they are not connected within this many #
+#                 seconds. If this is not defined, the default of ten #
+#                 seconds is used.                                    #
+#                                                                     #
+# bind          - If you specify this value, then when creating an    #
+#                 outbound connection to the given server, the IP you #
+#                 place here will be bound to. This is for multi-     #
+#                 homed servers which may have multiple IP addresses. #
+#                 If you do not define this value, the first IP that  #
+#                 is not empty or localhost from your <bind> tags     #
+#                 will be bound to. This is usually acceptable,       #
+#                 however if your server has multiple network cards   #
+#                 then you may have to manually specify the bind      #
+#                 value instead of leaving it to automatic binding.   #
+#                 You can usually tell if you need to set this by     #
+#                 looking for the error 'Could not assign requested   #
+#                 address' in your log when connecting to servers.    #
+#                                                                     #
+# hidden        - If this is set to true, yes, or 1, then the server  #
+#                 is completely hidden from non-opers. It does not    #
+#                 show in LINKS and it does not show in MAP. Also,    #
+#                 any servers which are child servers of this one     #
+#                 in the network will *also* be hidden. Use with      #
+#                 care! You can use this to 'mask off' sections of    #
+#                 the network so that users only see a small portion  #
+#                 of a much larger net. It should NOT be relied upon  #
+#                 as a security tool, unless it is being used for     #
+#                 example to hide a non-client hub, for which clients #
+#                 do not have an IP address or resolvable hostname.   #
+#                                                                     #
+# to u:line a server (give it extra privilages required for running   #
+# services, Q, etc) you must include the <uline server> tag as shown  #
+# in the example below. You can have as many of these as you like.    #
+#                                                                     #
+# WARNING: Unlike other ircds, u:lining a server allows ALL users on  #
+# that server to operoverride modes. This should only be used for     #
+# services and protected oper servers!                                #
+#                                                                     #
+# ------------------------------------------------------------------- #
+#                                                                     #
+# NOTE: If you have built your server as an ipv6 server, then when a  #
+# DNS lookup of a server's host occurs, AAAA records (ipv6) are       #
+# priorotized over A records (ipv4). Therefore, if the server you are #
+# connecting to has both an IPV6 ip address and an IPV4 ip address in #
+# its DNS entry, the IPV6 address will *always* be selected. To       #
+# change this behaviour simply specify the IPV4 IP address rather     #
+# than the hostname of the server.                                    #
+#                                                                     #
+# ------------------------------------------------------------------- #
+#                                                                     #
+#    ____                _   _____ _     _       ____  _ _   _        #
+#   |  _ \ ___  __ _  __| | |_   _| |__ (_)___  | __ )(_) |_| |       #
+#   | |_) / _ \/ _` |/ _` |   | | | '_ \| / __| |  _ \| | __| |       #
+#   |  _ <  __/ (_| | (_| |   | | | | | | \__ \ | |_) | | |_|_|       #
+#   |_| \_\___|\__,_|\__,_|   |_| |_| |_|_|___/ |____/|_|\__(_)       #
+#                                                                     #
+#  If you want to link servers to InspIRCd you must load the          #
+#  m_spanningtree module! Please see the modules list below for       #
+#  information on how to load this module! If you do not load this    #
+#  module, server links will NOT work!                                #
+#                                                                     #
+#  Also, if you define any transports, you must load the modules for  #
+#  these transports BEFORE you load m_spanningtree, e.g. place them   #
+#  above it in the configuration file. Currently this means the three #
+#  modules m_ssl_gnutls, m_ziplinks and m_ssl_openssl, depending on   #
+#  which you choose to use.                                           #
+#                                                                     #
+
+<link name="hub.penguin.org"
+      ipaddr="penguin.box.com"
+      port="7000"
+      allowmask="69.58.44.0/24"
+      autoconnect="300"
+      failover="hub.other.net"
+      timeout="15"
+      transport="gnutls"
+      bind="1.2.3.4"
+      statshidden="no"
+      hidden="no"
+      sendpass="outgoing!password"
+      recvpass="incoming!password">
+
+<link name="services.antarctic.com"
+      ipaddr="localhost"
+      port="7000"
+      allowmask="127.0.0.0/8"
+      sendpass="penguins"
+      recvpass="polarbears">
+
+
+#-#-#-#-#-#-#-#-#-#-#-#- ULINES CONFIGURATION #-#-#-#-#-#-#-#-#-#-#-#-#
+# This tag defines a ulined server. A U-Lined server has special      #
+# permissions, and should be used with caution. Services servers are  #
+# usually u-lined in this manner.                                     #
+#                                                                     #
+# The 'silent' value if set to yes indicates that this server should  #
+# not generate quit and connect notices, which can cut down on noise  #
+# to opers on the network.                                            #
+#                                                                     #
+<uline server="services.antarctic.com" silent="yes">
+
+
+#-#-#-#-#-#-#-#-#-#-  MISCELLANEOUS CONFIGURATION  -#-#-#-#-#-#-#-#-#-#
+#                                                                     #
+#   These options let you define the path to your motd and rules      #
+#   files. If these are relative paths, they are relative to the      #
+#   configurtion directory.                                           #
+#                                                                     #
+
+<files motd="inspircd.motd.example"
+       rules="inspircd.rules.example">
+
+#-#-#-#-#-#-#-#-#-#-#-# MAXIMUM CHANNELS -#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+#                                                                     #
+# This optional configuration tag lets you define the maximum number  #
+# of channels that both opers and users may be on at any one time.    #
+# the default is 20 for user and 60 for opers if this tag is not      #
+# defined. Remote users are not restricted in any manner.             #
+#                                                                     #
+
+<channels users="20"
+          opers="60">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-# DNS SERVER -#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+#                                                                     #
+# Define your DNS server address here. InspIRCd has its own resolver. #
+# If you do not define this value, then then InspIRCd will attempt to #
+# determine your DNS server from your operating system. On POSIX      #
+# platforms, InspIRCd will read /etc/resolv.conf, and populate this   #
+# value with the first DNS server address found. On Windows platforms #
+# InspIRCd will check the registry, and use the DNS server of the     #
+# first active network interface, if one exists.                      #
+# If a DNS server cannot be determined from these checks, the default #
+# value '127.0.0.1' is used instead. The timeout value is in seconds. #
+#                                                                     #
+#    ____                _   _____ _     _       ____  _ _   _        #
+#   |  _ \ ___  __ _  __| | |_   _| |__ (_)___  | __ )(_) |_| |       #
+#   | |_) / _ \/ _` |/ _` |   | | | '_ \| / __| |  _ \| | __| |       #
+#   |  _ <  __/ (_| | (_| |   | | | | | | \__ \ | |_) | | |_|_|       #
+#   |_| \_\___|\__,_|\__,_|   |_| |_| |_|_|___/ |____/|_|\__(_)       #
+#                                                                     #
+# When choosing a server, be sure to choose one which will do a       #
+# RECURSIVE LOOKUP. InspIRCd's resolver does not currently do these   #
+# recursive lookups itself, to save time and resources. The dns       #
+# server recommended by the InspIRCd team is bind, available from the #
+# ISC website. If your DNS server does not do a recursive lookup, you #
+# will be able to notice this by the fact that none of your users are #
+# resolving even though the DNS server appears to be up! Most ISP and #
+# hosting provider DNS servers support recursive lookups.             #
+#                                                                     #
+# ------------------------------------------------------------------- #
+#                                                                     #
+# NOTE: if you have built InspIRCd with IPV6 support, then both       #
+# ipv6 and ipv4 addresses are allowed here, and also in the system    #
+# resolv.conf file. Remember that an ipv4 dns server can still        #
+# resolve ipv6 addresses, and vice versa.                             #
+#                                                                     #
+
+<dns server="127.0.0.1" timeout="5">
+
+# An example of using an IPV6 nameserver
+#<dns server="::1" timeout="5">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#  PID FILE  -#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+#                                                                     #
+# Define the path to the PID file here. The PID file can be used to   #
+# rehash the ircd from the shell or to terminate the ircd from the    #
+# shell using shell scripts, perl scripts etc, and to monitor the     #
+# ircd's state via cron jobs. If this is a relative path, it will be  #
+# relative to the configuration directory, and if it is not defined,  #
+# the default of 'inspircd.pid' is used.                              #
+#                                                                     #
+
+#<pid file="/path/to/inspircd.pid">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#- BANLIST LIMITS #-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+#                                                                     #
+# Use these tags to customise the ban limits on a per channel basis.  #
+# the tags are read from top to bottom, and any tag found which       #
+# matches the channels name applies the banlimit to that channel.     #
+# It is advisable to put an entry with the channel as '*' at the      #
+# bottom of the list. If none are specified or no maxbans tag is      #
+# matched, the banlist size defaults to 64 entries.                   #
+#                                                                     #
+
+<banlist chan="#morons" limit="128">
+<banlist chan="*" limit="69">
+
+#-#-#-#-#-#-#-#-#-#-#-  DISABLED COMMANDS  -#-#-#-#-#-#-#-#-#-#-#-#-#-#
+#                                                                     #
+# This tag is optional, and specifies one or more commands which are  #
+# not available to non-operators. For example you may wish to disable #
+# NICK and prevent non-opers from changing their nicknames.           #
+# Note that any disabled commands take effect only after the user has #
+# 'registered' (e.g. after the initial USER/NICK/PASS on connection)  #
+# so for example disabling NICK will not cripple your network.        #
+#                                                                     #
+
+#<disabled commands="TOPIC MODE">
+
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-  RTFM LINE  -#-#-#-#-#-#-#-#-#-#-#-#-#-#
+#                                                                     #
+#   Just remove this... Its here to make you read ALL of the config   #
+#   file options ;)                                                   #
+
+<die value="You should probably edit your config *PROPERLY* and try again.">
+
+
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-  SERVER OPTIONS   -#-#-#-#-#-#-#-#-#-#-#-#-#
+#                                                                     #
+#   Settings to define which features are useable on your server.     #
+#                                                                     #
+#  prefixquit    - A prefix to be placed on the start of a client's   #
+#                  quit message                                       #
+#                                                                     #
+#  suffixquit    - A suffix to be placed on the end of a client's     #
+#                  quit message.                                      #
+#                                                                     #
+#  fixedquit     - A fixed quit message to display for all client     #
+#                  QUITS. If specified, overrides both prefixquit     #
+#                  and suffixquit options.                            #
+#                                                                     #
+#  loglevel      - specifies what detail of messages to log in the    #
+#                  log file. You may select from debug, verbose,      #
+#                  default, sparse and none.                          #
+#                                                                     #
+#  allowhalfop   - allows the +h channel mode                         #
+#                                                                     #
+#  noservices    - If noservices is true, yes, or 1, then the first   #
+#                  user into a channel gets founder status. This is   #
+#                  only useful on networks running the m_chanprotect  #
+#                  module without services.                           #
+#                                                                     #
+#  qaprefixes    - If qaprefixes is true, yes, or 1, then users       #
+#                  with +q or +a will get the ~ or & prefixes         #
+#                  used in unreal. This is only useful on networks    #
+#                  running the m_chanprotect module                   #
+#                                                                     #
+#  deprotectself - If this value is set to yes, true, or 1, then any  #
+#                  user with +q or +a may remove the +q or +a from    #
+#                  themselves. The default setting is to not enable   #
+#                  this feature, which stops even the founder taking  #
+#                  away their founder status without using services.  #
+#                                                                     #
+#  deprotectothers-If this value is set to yes, true, or 1, then any  #
+#                  user with +q or +a may remove the +q or +a from    #
+#                  other users. The default setting is to not enable  #
+#                  this feature, so that only +q may remove +a, and   #
+#                  nothing but services may remove +q.                #
+#                                                                     #
+#  cyclehosts    - If this is set to true, yes or 1, then when a      #
+#                  user's hostname changes, they will appear to quit  #
+#                  and then rejoin with their new host. This prevents #
+#                  clients from being confused by host changes,       #
+#                  especially in the case of bots, and it is          #
+#                  recommended that this option is enabled.           #
+#                                                                     #
+#  netbuffersize - size of the buffer used to receive data from       #
+#                  clients. The ircd may only read() this amount      #
+#                  of text in one go at any time. (OPTIONAL)          #
+#                                                                     #
+#  maxwho        - The maximum number of results returned by a /WHO   #
+#                  query. This is to prevent /WHO being used as a     #
+#                  spam vector or means of flooding an ircd. The      #
+#                  default is 128, it is not recommended to raise it  #
+#                  above 1024. Values up to 65535 are permitted. If   #
+#                  this value is omitted, any size WHO is allowed by  #
+#                  anyone.                                            #
+#                                                                     #
+#  somaxconn     - The maximum number of sockets that may be waiting  #
+#                  in the accept queue. This usually allows the ircd  #
+#                  to soak up more connections in a shorter space of  #
+#                  time when increased but please be aware there is a #
+#                  system defined maximum value to this, the same way #
+#                  there is a system defined maximum number of file   #
+#                  descriptors. Some systems may only allow this to   #
+#                  be up to 5 (ugh) while others such as FreeBSD will #
+#                  default to a much nicer 128.                       #
+#                                                                     #
+#  moduledir     - This optional value indicates a runtime change of  #
+#                  the location where modules are to be found. This   #
+#                  does not add a supplementary directory. There can  #
+#                  only be one module path.                           #
+#                                                                     #
+#  softlimit     - This optional feature allows a defined softlimit.  #
+#                  if defined sets a soft maxconnections value, has   #
+#                  to be less than the ./configure maxclients         #
+#                                                                     #
+#  userstats     - The userstats field is optional and specifies      #
+#                  which stats characters in /STATS may be requested  #
+#                  by non-operators. Stats characters in this field   #
+#                  are case sensitive and are allowed to users        #
+#                  independent of if they are in a module or the core #
+#                                                                     #
+#  operspywhois  - If this is set then when an IRC operator uses      #
+#                  /WHOIS on a user they will see all channels, even  #
+#                  ones if channels are secret (+s), private (+p) or  #
+#                  if the target user is invisible +i.                #
+#                                                                     #
+#  customversion - If you specify this configuration item, and it is  #
+#                  not set to an empty value, then when a user does   #
+#                  a /VERSION command on the ircd, this string will   #
+#                  be displayed as the second portion of the output,  #
+#                  replacing the system 'uname', compile flags and    #
+#                  socket engine/dns engine names. You may use this   #
+#                  to enhance security, or simply for vanity.         #
+#                                                                     #
+#  maxtargets    - The maxtargets field is optional, and if not       #
+#                  defined, defaults to 20. It indicates the maximum  #
+#                  number of targets which may be given to commands   #
+#                  such as PRIVMSG, KICK etc.                         #
+#                                                                     #
+#  hidesplits    - When set to 'yes', will hide split server names    #
+#                  from non-opers. Non-opers will see '*.net *.split' #
+#                  instead of the server names in the quit message,   #
+#                  identical to the way IRCu displays them.           #
+#                                                                     #
+#  hidebans      - When set to 'yes', will hide gline, kline, zline   #
+#                  and qline quit messages from non-opers. For        #
+#                  example, user A who is not an oper will just see   #
+#                  (G-Lined) while user B who is an oper will see the #
+#                  text (G-Lined: Reason here) instead.               #
+#                                                                     #
+#  hidewhois     - When defined with a non-empty value, the given     #
+#                  text will be used in place of the user's server    #
+#                  in WHOIS, when a user is WHOISed by a non-oper.    #
+#                  For example, most nets will want to set this to    #
+#                  something like '*.netname.net' to conceal the      #
+#                  actual server the user is on.                      #
+#                                                                     #
+#  flatlinks     - When you are using m_spanningtree.so, and this     #
+#                  value is set to true, yes or 1, /MAP and /LINKS    #
+#                  will be flattened when shown to a non-oper.        #
+#                                                                     #
+#  hideulines    - When you are using m_spanningtree.so, and this     #
+#                  value is set to true, yes or 1, then U-lined       #
+#                  servers will be hidden in /LINKS and /MAP. For non #
+#                  opers. Please be aware that this will also hide    #
+#                  any leaf servers of a U-lined server, e.g. jupes.  #
+#                                                                     #
+#  nouserdns     - If set to 'yes', 'true' or '1', no user dns        #
+#                  lookups will be performed for connecting users.    #
+#                  this can save a lot of resources on very busy irc  #
+#                  servers.                                           #
+#                                                                     #
+#  syntaxhints   - If set to 'yes', 'true' or '1', when a user does   #
+#                  not give enough parameters for a command, a syntax #
+#                  hint will be given (using the RPL_TEXT numeric)    #
+#                  as well as the standard ERR_NEEDMOREPARAMS.        #
+#                                                                     #
+#  announcets    - If this value is defined to 'yes', 'true' or '1',  #
+#                  then if a channel's timestamp is updated the users #
+#                  on the channel will be informed of the change via  #
+#                  a server notice to the channel with the old and    #
+#                  new TS values in the timestamp. If you think this  #
+#                  is just pointless noise, define the value to 0.    #
+#                                                                     #
+#  ircumsgprefix - Use undernet style message prefix for channel      #
+#                  NOTICE and PRIVMSG adding the prefix to the line   #
+#                  of text sent out. Eg. NOTICE @#test :@ testing     #
+#                  vs. the off setting: NOTICE @#test :testing        #
+#                                                                     #
+#  hostintopic   - If this is set to yes (the default) then the full  #
+#                  nick!user@host is shown for who set a TOPIC last.  #
+#                  if set to no, then only the nickname is shown.     #
+#                                                                     #
+# announceinvites                                                     #
+#                - If this option is set to yes (the default), then   #
+#                  invites are announced to the channel when a user   #
+#                  invites annother user. If you consider this to be  #
+#                  unnecessary noise, explicitly set this to no.      #
+#                                                                     #
+#  disablehmac   - If you are linking your InspIRCd to older versions #
+#                  then you can specify this option and set it to     #
+#                  yes. 1.1.6 and above support HMAC and challenge-   #
+#                  response for password authentication. These can    #
+#                  greatly enhance security of your server to server  #
+#                  connections when you are not using SSL (as is the  #
+#                  case with a lot of larger networks). Linking to    #
+#                  older versions of InspIRCd should not *usually* be #
+#                  a problem, but if you have problems with HMAC      #
+#                  authentication, this option can be used to turn it #
+#                  off.                                               #
+#                                                                     #
+#  hidemodes     - If this option is enabled, then the listmodes      #
+#                  given (e.g. +eI), will be hidden from users below  #
+#                  halfop. This is not recommended to be set on mode  #
+#                  +b, as it may break some features in popular       #
+#                  clients such as mIRC.                              #
+#                                                                     #
+#  quietbursts   - When synching or splitting from the network, a     #
+#                  server can generate a lot of connect and quit      #
+#                  snotices to the +C and +Q snomasks. Setting this   #
+#                  value to yes squelches those messages, which can   #
+#                  make them more useful for opers, however it will   #
+#                  degrade their use by certain third party programs  #
+#                  such as BOPM which rely on them to scan users when #
+#                  a split heals in certain configurations.           #
+#                                                                     #
+#  pingwarning   - This should be set to a number between 1 and 59 if #
+#                  defined, and if it is defined will cause the server#
+#                  to send out a warning via snomask +l if a server   #
+#                  does not answer to PING after this many seconds.   #
+#                  This can be useful for finding servers which are   #
+#                  at risk of pinging out due to network issues.      #
+#                                                                     #
+#  exemptchanops - This option allows channel operators to be exempted#
+#                  from certain channel modes.                        #
+#                  Supported modes are +SfgNc. Defaults to off.       #
+#                                                                     #
+#  defaultmodes  - The default modes to be given to each channel on   #
+#                  creation. Defaults to 'nt'. There should be no +   #
+#                  or - symbols in this sequence, if you add them     #
+#                  they will be ignored. You may add parameters for   #
+#                  parameterised modes.                               #
+#                                                                     #
+#  moronbanner   - The NOTICE to show to users who are glined, zlined #
+#                  klined or qlined when they are disconnected. This  #
+#                  is totally freeform, you may place any text here   #
+#                  you wish.                                          #
+#                                                                     #
+
+<options prefixquit="Quit: "
+         loglevel="default"
+         netbuffersize="10240"
+         maxwho="128"
+         noservices="no"
+         qaprefixes="no"
+         deprotectself="no"
+         deprotectothers="no"
+         somaxconn="128"
+         softlimit="12800"
+         userstats="Pu"
+         operspywhois="no"
+         customversion=""
+         maxtargets="20"
+         hidesplits="no"
+         hidebans="no"
+         hidewhois=""
+         flatlinks="no"
+         hideulines="no"
+         nouserdns="no"
+         syntaxhints="no"
+         cyclehosts="yes"
+         ircumsgprefix="no"
+         announcets="yes"
+         disablehmac="no"
+         hostintopic="yes"
+         hidemodes="eI"
+         quietbursts="yes"
+         pingwarning="15"
+         allowhalfop="yes"
+        defaultmodes="nt"
+        moronbanner="You're banned! Email haha@abuse.com with the ERROR line below for help."
+        exemptchanops="">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#- TIME SYNC OPTIONS -#-#-#-#-#-#-#-#-#-#-#-#
+# Time sychronization options for m_spanningtree linking.             #
+#                                                                     #
+# Because IRC is very time and clock dependent, InspIRCd provides its #
+# own methods for syncronization of time between servers as shown     #
+# in the example below, for servers that don't have ntpd running.     #
+#                                                                     #
+#  enable    -     If this value is 'yes', 'true', or '1', time       #
+#                  synchronization is enabled on this server. This    #
+#                  means any servers you are linked to will           #
+#                  automatically synchronize time, however you should #
+#                  use ntpd instead where possible, NOT this option.  #
+#                                                                     #
+#  master    -     If this value is set to yes, then this server will #
+#                  act as the authoritative time source for the whole #
+#                  network. All other servers will respect its time   #
+#                  without question, and match their times to it.     #
+#                  only one server should have the master value set   #
+#                  to 'yes'.                                          #
+#                                                                     #
+<timesync enable="no" master="no">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-  WHOWAS OPTIONS   -#-#-#-#-#-#-#-#-#-#-#-#-#
+#                                                                     #
+# This tag lets you define the behaviour of the /whowas command of    #
+# your server.                                                        #
+#                                                                     #
+# groupsize      - Controls the maximum entries per nick shown when   #
+#                  performing a /whowas nick. Setting this to 0 dis-  #
+#                  ables whowas completely.                           #
+#                                                                     #
+# maxgroups      - The maximum number of nickgroups that can be added #
+#                  to the list. If max is reached, oldest group will  #
+#                  be deleted first like a FIFO. A groupsize of 3 and #
+#                  a maxgroups of 5000 will allow for 5000 nicks to   #
+#                  be stored with a history of 3, thus giving a total #
+#                  of 3 * 5000 = 15000 entries. A setting of 0 dis-   #
+#                  ables whowas completely.                           #
+#                                                                     #
+# maxkeep        - The maximum time a nick is kept in the whowas list #
+#                  before being pruned. Time may be specified in      #
+#                  seconds, or in the following format: 1y2w3d4h5m6s  #
+#                  meaning one year, two weeks, three days, 4 hours,  #
+#                  5 minutes and 6 seconds. All fields in this format #
+#                  are optional. Minimum is 1 hour, if less InspIRCd  #
+#                  will default back to 1 hour.                       #
+#                                                                     #
+#<whowas groupsize="10"                                               #
+#        maxgroups="100000"                                           #
+#        maxkeep="3d">                                                #
+
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-  MODULE OPTIONS   -#-#-#-#-#-#-#-#-#-#-#-#-#
+#                                                                     #
+#  These tags define which modules will be loaded on startup by your  #
+#  server. Add modules without any paths. When you make your ircd     #
+#  using the 'make' command, all compiled modules will be moved into  #
+#  the folder you specified when you ran ./configure. The module tag  #
+#  automatically looks for modules in this location.                  #
+#  If you attempt to load a module outside of this location, either   #
+#  in the config, or via /LOADMODULE, you will receive an error.      #
+#                                                                     #
+#  By default, ALL modules are commented out. You must uncomment them #
+#  or add lines to your config to load modules. Please refer to       #
+#  http://www.inspircd.org/wiki/Modules_List for a list of modules and#
+#  each modules link for any additional conf tags they require.       #
+#                                                                     #
+#  You may use wildcards in a <module> tag to load all modules which  #
+#  match a glob pattern (e.g. m_sa????.so would load m_sajoin,        #
+#  m_sapart, m_saquit and m_sanick)                                   #
+#                                                                     #
+#    ____                _   _____ _     _       ____  _ _   _        #
+#   |  _ \ ___  __ _  __| | |_   _| |__ (_)___  | __ )(_) |_| |       #
+#   | |_) / _ \/ _` |/ _` |   | | | '_ \| / __| |  _ \| | __| |       #
+#   |  _ <  __/ (_| | (_| |   | | | | | | \__ \ | |_) | | |_|_|       #
+#   |_| \_\___|\__,_|\__,_|   |_| |_| |_|_|___/ |____/|_|\__(_)       #
+#                                                                     #
+# To link servers to InspIRCd, you MUST load the m_spanningtree       #
+# module, as shown below. If you DO NOT do this, server links will    #
+# NOT work at all. ie. The ports will NOT bind, and /connect will not #
+# work properly. This is by design, to allow for the implementation   #
+# of other linking protocols in modules in the future.                #
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Spanning Tree module - allows linking of servers using the spanning
+# tree protocol (see the READ THIS BIT section above).
+#
+#<module name="m_spanningtree.so">
+
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# MD5 Module - Allows other modules to generate MD5 hashes, usually for
+# cryptographic uses and security.
+#
+# IMPORTANT:
+# Other modules such as m_cloaking.so and m_opermd5.so may rely on
+# this module being loaded to function.
+#
+#<module name="m_md5.so">
+#
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# SHA256 Module - Allows other modules to generate SHA256 hashes,
+# usually for cryptographic uses and security.
+#
+# IMPORTANT:
+# Other modules such as m_opermd5.so may rely on this module being
+# loaded to function.
+#
+#<module name="m_sha256.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Alias module: Allows you to define server-side command aliases
+#<module name="m_alias.so">
+#
+#-#-#-#-#-#-#-#-#-#-#-  ALIAS DEFINITIONS  -#-#-#-#-#-#-#-#-#-#-#-#-#-#
+#                                                                     #
+# If you have the m_alias.so module loaded, you may also define       #
+# aliases as shown below. They are commonly used to provide shortcut  #
+# commands to services, however they are not limited to just this use.#
+# An alias tag requires the following values to be defined in it:     #
+#                                                                     #
+# text        -      The text to detect as the actual command line,   #
+#                    Cant contain spaces, but case insensitive.       #
+#                    You may have multiple aliases with the same      #
+#                    command name (text="" value), however the first  #
+#                    found will be executed if its format value is    #
+#                    matched, or it has no format value. Aliases are  #
+#                    read from the top of the file to the bottom.     #
+#                                                                     #
+# format      -      If this is defined, the parameters of the alias  #
+#                    must match this glob pattern. For example if you #
+#                    want the first parameter to start with a # for   #
+#                    the alias to be executed, set format="#*" in the #
+#                    alias definition. Note that the :'s which are    #
+#                    part of IRC formatted lines will be preserved    #
+#                    for matching of this text. This value is         #
+#                    optional.                                        #
+#                                                                     #
+# replace     -      The text to replace 'text' with. Usually this    #
+#                    will be "PRIVMSG ServiceName :$2-" or similar.   #
+#                    You may use the variables $1 through $9 in the   #
+#                    replace string, which refer to the first through #
+#                    ninth word in the original string typed by the   #
+#                    user. You may also use $1- through $9- which     #
+#                    refer to the first word onwards, through to the  #
+#                    ninth word onwards, e.g. if the user types the   #
+#                    command "foo bar baz qux quz" then $3- will hold #
+#                    "baz qux quz" and $2 will contain "bar". You may #
+#                    also use the special variables: $nick, $ident,   #
+#                    $host and $vhost, and you may seperate multiple  #
+#                    commands with \n. If you wish to use the ACTUAL  #
+#                    characters \ and n together in a line, you must  #
+#                    use the sequence "\\n".                          #
+#                                                                     #
+# requires    -      If you provide a value for 'requires' this means #
+#                    the given nickname MUST be online for the alias  #
+#                    to successfully trigger. If they are not, then   #
+#                    the user receives a 'no such nick' 401 numeric.  #
+#                                                                     #
+# uline       -      Defining this value with 'yes', 'true' or '1'    #
+#                    will ensure that the user given in 'requires'    #
+#                    must also be on a u-lined server, as well as     #
+#                    actually being on the network. If the user is    #
+#                    online, but not on a u-lined server, then an     #
+#                    oper-alert is sent out as this is possibly signs #
+#                    of a user trying to impersonate a service.       #
+#                                                                     #
+# operonly    -      Defining this value, with a value of 'yes', '1'  #
+#                    or true will make the alias oper only. If a non- #
+#                    oper attempts to use the alias, it will appear   #
+#                    to not exist.                                    #
+#                                                                     #
+#<alias text="NICKSERV" replace="PRIVMSG NickServ :$2-" requires="NickServ" uline="yes">
+#<alias text="CHANSERV" replace="PRIVMSG ChanServ :$2-" requires="ChanServ" uline="yes">
+#<alias text="OPERSERV" replace="PRIVMSG OperServ :$2-" requires="OperServ" uline="yes" operonly="yes">
+#<alias text="NS" replace="PRIVMSG NickServ :$2-" requires="NickServ" uline="yes">
+#<alias text="CS" replace="PRIVMSG ChanServ :$2-" requires="ChanServ" uline="yes">
+#<alias text="OS" replace="PRIVMSG OperServ :$2-" requires="OperServ" uline="yes" operonly="yes">
+#
+# An example of using the format value to create an alias with two
+# different behaviours depending on the format of the parameters.
+#
+#<alias text="ID" format="#*" replace="PRIVMSG ChanServ :IDENTIFY $2 $3"
+#  requires="ChanServ" uline="yes">
+#
+#<alias text="ID" replace="PRIVMSG NickServ :IDENTIFY $2"
+#  requires="NickServ" uline="yes">
+#
+# This alias fixes a glitch in xchat 2.6.x and above and the way it
+# assumes IDENTIFY must be prefixed by a colon (:) character. It should
+# be placed ABOVE the default NICKSERV alias (the first example) listed
+# above.
+#
+#<alias text="NICKSERV" format=":IDENTIFY *" replace="PRIVMSG NickServ :IDENTIFY $3-"
+#  requires="NickServ" uline="yes">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Alltime module: Shows time on all connected servers at once
+#<module name="m_alltime.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Antibear security module: Prevents 'bear.txt' based trojans from
+# connecting to your network by sending them a numeric they can't handle.
+#<module name="m_antibear.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Antibottler module: Labels bottler leech bots
+#<module name="m_antibottler.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Auditorium module: Adds channel mode +u which makes everyone else
+# except you in the channel invisible, used for large meetings etc.
+#<module name="m_auditorium.so">
+#
+# Auditorium settings:
+#
+#<auditorium showops="no">
+#
+# Setting this value to yes makes m_auditorium behave like unrealircd
+# +u channel mode, e.g. ops see users joining, parting, etc, and users
+# joining the channel see the ops. Without this flag, the mode acts
+# like ircnet's +a (anonymous channels), showing only the user in the
+# names list, and not even showing the ops in the list, or showing the
+# ops that the user has joined.
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Ban except module: Adds support for channel ban exceptions (+e)
+#<module name="m_banexception.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Ban redirection module: Allows bans which redirect to a specified
+# channel. e.g. +b nick!ident@host#channelbanneduserissentto
+#<module name="m_banredirect.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Block amsg module: Attempt to block all usage of /amsg and /ame
+#<module name="m_blockamsg.so">
+#
+#-#-#-#-#-#-#-#-#-#-#-  BLOCKAMSG CONFIGURATION  -#-#-#-#-#-#-#-#-#-#-#
+#                                                                     #
+# If you have the m_blockamsg.so module loaded, you can configure it  #
+# with the <blockamsg> tag:                                           #
+#                                                                     #
+# delay          -   How many seconds between two messages to force   #
+#                    them to be recognised as unrelated.              #
+# action         -   Any of 'notice', 'noticeopers', 'silent', 'kill' #
+#                    or 'killopers'. Define how to take action when   #
+#                    a user uses /amsg or /ame.                       #
+#
+#<blockamsg delay="3" action="killopers">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Block CAPS module: Blocking all-CAPS messages with cmode +P
+#<module name="m_blockcaps.so">
+#                                                                     #
+#-#-#-#-#-#-#-#-#-#-#-  BLOCKCAPS CONFIGURATION  -#-#-#-#-#-#-#-#-#-#-#
+#                                                                     #
+# percent        - How many percent of text must be caps before text  #
+#                  will be blocked.                                   #
+#                                                                     #
+# minlen         - The minimum length a line must be for the block    #
+#                  percent to have any effect.                        #
+#                                                                     #
+# capsmap        - A list of chars to be considered CAPS, this was    #
+#                  you can add CAPS for your language. Also you can   #
+#                  add things like ! and space to further lock down   #
+#                  on caps usage.                                     #
+#<blockcaps percent="50"
+#           minlen="5"
+#           capsmap="ABCDEFGHIJKLMNOPQRSTUVWXYZ! ">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Block colour module: Blocking colour-coded messages with cmode +c
+#<module name="m_blockcolor.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Botmode module: Adds the user mode +B
+#<module name="m_botmode.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# CBAN module: Lets you disallow channels from being used at runtime.
+#<module name="m_cban.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Censor module: Adds the channel mode +G
+#<module name="m_censor.so">
+#
+#-#-#-#-#-#-#-#-#-#-#-  CENSOR  CONFIGURATION  -#-#-#-#-#-#-#-#-#-#-#-#
+#                                                                     #
+# Optional - If you specify to use the m_censor module, then you must #
+# specify some censor tags. See also:                                 #
+# http://www.inspircd.org/wiki/Censor_Module                          #
+#
+#<include file="censor.conf">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# CGI:IRC module: Adds support for automatic host changing in CGI:IRC
+# (http://cgiirc.sourceforge.net).
+#<module name="m_cgiirc.so">
+#
+#-#-#-#-#-#-#-#-#-#-#-# CGIIRC  CONFIGURATION #-#-#-#-#-#-#-#-#-#-#-#-#
+#
+# Optional - If you specify to use m_cgiirc, then you must specify one
+# or more cgihost tags which indicate authorized CGI:IRC servers which
+# will be connecting to your network, and an optional cgiirc tag.
+# For more information see: http://www.inspircd.org/wiki/CGI-IRC_Module
+#
+# Set to yes if you want to notice opers when CGI clients connect
+# <cgiirc opernotice="no">
+#
+# The type field indicates where the module should get the real
+# client's IP address from, for further information, please see the
+# CGI:IRC documentation.
+#
+# <cgihost type="pass" mask="www.mysite.com">       # Get IP from PASS
+# <cgihost type="webirc" mask="somebox.mysite.com"> # Get IP from WEBIRC
+# <cgihost type="ident" mask="otherbox.mysite.com"> # Get IP from ident
+# <cgihost type="passfirst" mask="www.mysite.com">  # See the docs
+#
+# IMPORTANT NOTE:
+# ---------------
+#
+# When you connect CGI:IRC clients, there are two connect classes which
+# apply to these clients. When the client initially connects, the connect
+# class which matches the cgi:irc site's host is checked. Therefore you
+# must raise the maximum local/global clients for this ip as high as you
+# want to allow cgi clients. After the client has connected and is
+# determined to be a cgi:irc client, the class which matches the client's
+# real IP is then checked. You may set this class to a lower value, so that
+# the real IP of the client can still be restricted to, for example, 3
+# sessions maximum.
+#
+
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Channel create module: Adds snomask +j, which will notify opers of
+# any new channels that are created
+#<module name="m_chancreate.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Channel filter module: Allows channel-op defined message
+# filtering using simple string matches (channel mode +g)
+#<module name="m_chanfilter.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Chanprotect module: gives +q and +a channel modes
+#<module name="m_chanprotect.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Check module: gives /check
+# Check is useful for looking up information on channels,
+# users, IP addresses and hosts.
+#<module name="m_check.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# CHGHOST module: Adds the /CHGHOST command
+#<module name="m_chghost.so">
+#
+#-#-#-#-#-#-#-#-# /CHGHOST - /SETHOST  CONFIGURATION #-#-#-#-#-#-#-#-#
+# Optional - If you want to use special chars for hostnames you can  #
+# specify your own custom list of chars with the <hostname> tag:     #
+#                                                                    #
+# charmap        - A list of chars accepted as valid by the /CHGHOST #
+#                  and /SETHOST commands. Also note that the list is # 
+#                  case-sensitive.                                   #
+#<hostname charmap="abcdefghijklmnopqrstuvwxyz.-_/0123456789">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# CHGIDENT module: Adds the /CHGIDENT command
+#<module name="m_chgident.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# CHGNAME module: Adds the /CHGNAME command
+#<module name="m_chgname.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Cloaking module: Adds usermode +x and cloaking support.
+# Relies on the module m_md5.so being loaded before m_cloaking.so in
+# the configuration file.
+#<module name="m_cloaking.so">
+#
+#-#-#-#-#-#-#-#-#-#-#- CLOAKING  CONFIGURATION -#-#-#-#-#-#-#-#-#-#-#-#
+#                                                                     #
+# Optional - If you specify the m_cloaking.so module as above, you    #
+# must define cloak keys, and optionally a cloak prefix as shown      #
+# below. When using cloaking, the cloak keys are MANDITORY and must   #
+# be included. However, if prefix is not included, it will default    #
+# to your networks name from the <server> tag.                        #
+#                                                                     #
+# <cloak key1="0x2AF39F40"                                            #
+#        key2="0x78E10B32"                                            #
+#        key3="0x4F2D2E82"                                            #
+#        key4="0x043A4C81"                                            #
+#        prefix="mynet">                                              #
+#                                                                     #
+# Please note that the key values will accept any number, and should  #
+# be large numbers. Using small numbers such as "7" or "1924" will    #
+# seriously weaken the security of your cloak. It is recommended you  #
+# use hexdecimal numbers prefixed by "0x", as shown in this example,  #
+# with each key eight hex digits long.                                #
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Clones module: Adds an oper command /CLONES for detecting cloned
+# users. Warning: This module may be resource intensive when its
+# command is issued, use with care.
+#<module name="m_clones.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Conn-Join: Allows you to force users to join one or more channels
+# automatically upon connecting to the server.
+#<module name="m_conn_join.so">
+#
+#-#-#-#-#-#-#-#-#-#-#-#- CONNJOIN CONFIGURATION  -#-#-#-#-#-#-#-#-#-#-#
+#
+# If you have m_conn_join.so loaded, you can configure it using the
+# follow values:
+#
+#<autojoin channel="#one,#two,#three">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Conn-Usermodes: Set modes on users when they connect
+# When this module is loaded <connect:allow> tags may have an optional
+# modes="" value, which contains modes to add or remove from users
+# when they connect to the server.
+#<module name="m_conn_umodes.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Conn-Wait-for-Pong: Don't let a user connect until they PONG
+#<module name="m_conn_waitpong.so">
+#
+#-#-#-#-#-#-#-#-#-#-#-   WAITPONG CONFIGURATION  -#-#-#-#-#-#-#-#-#-#-#
+#                                                                     #
+# If you have the m_conn_waitpong.so module loaded, configure it with #
+# the <waitpong> tag:                                                 #
+#                                                                     #
+# sendsnotice    -   Whether to send a snotice on connect, like other #
+#                    older ircds                                      #
+#                                                                     #
+# killonbadreply -   Whether to kill the user if they send the wrong  #
+#                    PONG reply.                                      #
+#                                                                     #
+#<waitpong sendsnotice="yes" killonbadreply="yes">
+
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Channel cycle module. Server side /hop, with +ilk etc bypass.
+#<module name="m_cycle.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Connection throttle module. Configuration:
+#<module name="m_connflood.so">
+#
+#-#-#-#-#-#-#-#-#-#-#- CONTHROTTLE CONFIGURATION -#-#-#-#-#-#-#-#-#-#-#
+#  seconds, maxconns -  Amount of connections per <seconds>.
+#
+#  timeout           -  Time to wait after the throttle was activated
+#                       before deactivating it. Be aware that the time
+#                       is seconds + timeout.
+#
+#  quitmsg           -  The message that users get if they attempt to
+#                       connect while the throttle is active.
+#
+#  bootwait          -  Amount of time to wait before enforcing the
+#                       throttling when the server just booted.
+#
+#<connflood seconds="30" maxconns="3" timeout="30"
+#   quitmsg="Throttled" bootwait="10">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# DCCALLOW module: Adds the /DCCALLOW command
+#<module name="m_dccallow.so">
+#
+#-#-#-#-#-#-#-#-#-#-#-  DCCALLOW CONFIGURATION   -#-#-#-#-#-#-#-#-#-#-#
+#  blockchat         - Whether to block DCC CHAT as well as DCC SEND
+#  length            - Default duration of entries in DCCALLOW list
+#  action            - Default action to take if no action is specified
+#                      can be 'block' or 'allow'
+#
+# File configuration:
+#  pattern           - The glob pattern to match against
+#  action            - Action to take if a user attempts to send a file
+#                      that matches this pattern, can be 'block' or 'allow'
+#
+#<dccallow blockchat="yes" length="5m" action="block">
+#<banfile pattern="*.exe" action="block">
+#<banfile pattern="*.txt" action="allow">
+#
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Deaf module: adds support for ircu style usermode +d - deaf to
+# channel messages and channel notices.
+#<module name="m_deaf.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Deny Channels: Deny Channels from being used by users
+#<module name="m_denychans.so"> 
+#
+#-#-#-#-#-#-#-#-#-#-#-   DENYCHAN DEFINITIONS  -#-#-#-#-#-#-#-#-#-#-#-#
+#                                                                     #
+# If you have the m_denychans.so module loaded, you need to specify   #
+# the channels to deny:                                               #
+#                                                                     #
+# name        -      The channel name to deny.                        #
+#                                                                     #
+# allowopers  -      If operators are allowed to override the deny.   #
+#                                                                     #
+# reason      -      Reason given for the deny.                       #
+#                                                                     #
+#<badchan name="#gods" allowopers="yes" reason="Tortoises!">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Devoice Module: Let users devoice themselves.
+#<module name="m_devoice.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# DNS Blacklist Module: Provides support for looking up IPs on one or #
+# more blacklists.                                                    #
+#<module name="m_dnsbl.so">                                           #
+#                                                                     #
+# For configuration options please see the wiki page for m_dnsbl at   #
+# http://inspircd.org/wiki/DNS_Blacklist_Module                       #
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Filter module: Provides glob-based message filtering
+#<module name="m_filter.so">
+# OR
+# PCRE filter module: Filters messages using regular expressions
+#<module name="m_filter_pcre.so">
+#
+# You may only use one or the other with these modules, network-wide.
+#
+#-#-#-#-#-#-#-#-#-#-#-  FILTER  CONFIGURATION  -#-#-#-#-#-#-#-#-#-#-#-#
+#                                                                     #
+# Optional - If you specify to use the m_filter or m_filter_pcre      #
+# modules, then specfiy below the path to the filter.conf file,       #
+# or define some <filter> tags.                                       #
+#                                                                     #
+#<include file="filter.conf">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Foobar module: does nothing - historical relic
+#<module name="m_foobar.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Globops module: gives /GLOBOPS and usermode +g
+#<module name="m_globops.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Global load module: Allows loading and unloading of modules network-
+# wide (USE WITH EXTREME CAUTION!)
+#<module name="m_globalload.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# HELPOP module: Provides the /HELPOP command
+#<module name="m_helpop.so">
+#
+#-#-#-#-#-#-#-#-#-#-#-#-  HELPOP  CONFIGURATION  -#-#-#-#-#-#-#-#-#-#-#
+#                                                                     #
+# Optional - If you specify to use the m_helpop.so module, then       #
+# specify below the path to the helpop.conf file, or if you like to   #
+# make a mess, define your helpop tags in this conf.                  #
+#                                                                     #
+#<include file="helpop.conf">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# HIDECHANS module: Allows opers to hide their channels list from non-
+# opers by setting user mode +I on themselves.
+# <module name="m_hidechans.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# HIDEOPER module: Allows opers to hide their oper status from non-
+# opers by setting user mode +H on themselves.
+# <module name="m_hideoper.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Hostchange module: Allows a different style of cloaking
+#<module name="m_hostchange.so">
+#
+#-#-#-#-#-#-#-#-#-#-#-  HOSTCHANGE  CONFIGURATION  -#-#-#-#-#-#-#-#-#-#
+#                                                                     #
+# Optional - If you choose to use the m_hostchange.so module.         #
+# Config Help -  See http://www.inspircd.org/wiki/Host_Changer_Module #
+#                                                                     #
+#<host suffix="polarbears.org" separator="." prefix="">
+#<hostchange mask="*@fbi.gov" action="addnick">
+#<hostchange mask="*r00t@*" action="suffix">
+#<hostchange mask="a@b.com" action="set" value="blah.blah.blah">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# httpd module: Provides http server support for InspIRCd
+#<module name="m_httpd.so">
+#
+#-#-#-#-#-#-#-#-#-#-#-#-  HTTPD   CONFIGURATION  -#-#-#-#-#-#-#-#-#-#-#
+#
+# Optional - If you choose to use the m_httpd.so module,  then you must
+# specify the port number and other details of your http server:
+#
+#<http ip="192.168.1.10" host="brainwave" port="32006"
+#      index="/home/brain/inspircd/http/index.html">
+#
+# You may have as many of these tags as you wish, each with a different
+# IP, port, host or index file. Each one will act as an independent
+# HTTP server.
+#
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# http stats module: Provides basic stats pages over HTTP
+# Requires m_httpd.so to be loaded for it to function.
+#<module name="m_httpd_stats.so">
+#
+#-#-#-#-#-#-#-#-#-#-#-#- HTTPD STATS CONFIGURATION -#-#-#-#-#-#-#-#-#-#
+#
+#<httpstats stylesheet="http://remote.style/sheet.css">
+#
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Ident: Provides RFC 1413 ident lookup support
+#<module name="m_ident.so">
+#
+#-#-#-#-#-#-#-#-#-#-#-#-   IDENT CONFIGURATION   -#-#-#-#-#-#-#-#-#-#-#
+#                                                                     #
+# Optional - If you are using the m_ident.so module, then you can     #
+# specify the timeout for ident lookups here. If not defined, it will #
+# default to one second. This is a non-blocking timeout which holds   #
+# the user in a 'connecting' state until the lookup is complete.      #
+# The bind value indicates which IP to bind outbound requests to.     #
+#                                                                     #
+#<ident timeout="5" bind="">                                          #
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Invite except module: Adds support for channel invite exceptions (+I)
+#<module name="m_inviteexception.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Invisible module - Adds support for usermode +Q (quiet) which lets an
+# oper go 'invisible' similar to unrealircd 3.1's +I mode. Note that
+# opers are still able to see invisible users, and if an oper with +Q
+# deopers, they will become visible. 
+# 
+# IMPORTANT NOTE: To allow this mode to be used by a type of oper, you
+# must first add the value canquiet="yes" to that oper's type tag.
+#
+#<module name="m_invisible.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Join flood module: Adds support for join flood protection (+j)
+#<module name="m_joinflood.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Jump Server module: Adds support for the RPL_REDIR numeric
+#<module name="m_jumpserver.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Anti-Auto-Rejoin: Adds support for prevention of auto-rejoin (+J)
+#<module name="m_kicknorejoin.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Knock module: adds the /KNOCK command and +K channel mode
+#<module name="m_knock.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Lock server module: Adds /LOCKSERV and /UNLOCKSERV commands that is #
+# used to temporarily close/open for new connections to the server.   #
+# These commands require OPER status and that the LOCKSERV UNLOCKSERV #
+# are specified in a <class> tag that the oper is part of. This is so #
+# you can control who has access to this possible dangerous command.  #
+# If your server is locked and you got disconnected, do a REHASH from #
+# shell to open up again.
+#<module name="m_lockserv.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Msg flood module: Adds message/notice flood protection (+f)
+#<module name="m_messageflood.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# MySQL module: Allows other SQL modules to access MySQL databases
+# through a unified API. You must copy the source for this module
+# from the directory src/modules/extra, plus the file m_sqlv2.h
+#<module name="m_mysql.so">
+#
+#-#-#-#-#-#-#-#-#-#-#-#- SQL CONFIGURATION   -#-#-#-#-#-#-#-#-#-#-#-#-#
+#                                                                     #
+# m_mysql.so is more complex than described here, see the wiki for    #
+# more: http://www.inspircd.org/wiki/SQL_Service_Provider_Module      #
+#
+#<database name="mydb" username="myuser" password="mypass" hostname="localhost" id="my_database2">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# NAMESX module: Provides support for the NAMESX extension which allows
+# clients to see all the prefixes set on a user without getting confused.
+# This is supported by mIRC, x-chat, klient, and maybe more.
+#<module name="m_namesx.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Nicklock module: Let opers change a user's nick and then stop that
+# user from changing their nick again.
+#<module name="m_nicklock.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# No ctcp module: Adds the channel mode +C to block CTCPs
+#<module name="m_noctcp.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Noinvite module: Gives channel mode +V
+#<module name="m_noinvite.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# No kicks module: Adds the +Q channel mode
+#<module name="m_nokicks.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# No nicks module: Adds the +N channel mode
+#<module name="m_nonicks.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# No Notice module: adds the channel mode +T
+#<module name="m_nonotice.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Oper channels mode: Adds the +O channel mode
+#<module name="m_operchans.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Oper hash module: Allows hashed oper passwords
+# Relies on the module m_md5.so and/or m_sha256.so being loaded before
+# m_oper_hash.so in the configuration file.
+#<module name="m_oper_hash.so">
+#
+#-#-#-#-#-#-#-#-#-#-# OPER HASH CONFIGURATION #-#-#-#-#-#-#-#-#-#-#-#-#
+#
+# To use this module, you must define a hash type for each oper's
+# password you want to hash. For example:
+#
+#     <oper name="Brain"
+#           host="ident@dialup15.isp.com"
+#           hash="sha256"
+#           password="a41d730937a53b79f788c0ab13e9e1d5"
+#           type="NetAdmin">
+# 
+# The types of hashing available vary depending on which hashing modules
+# you load, but usually if you load m_sha256.so and m_md5.so, both md5
+# and sha256 type hashing will be available (the most secure of which
+# is SHA256).
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Oper Join module: Forces opers to join a channel on oper-up
+#<module name="m_operjoin.so">
+#
+#-#-#-#-#-#-#-#-#-#-#   OPERJOIN CONFIGURATION   -#-#-#-#-#-#-#-#-#-#-#
+#                                                                     #
+# If you are using the m_operjoin.so module, specify the channel here #
+#                                                                     #
+#<operjoin channel="#channel">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Oper MOTD module: Provides support for seperate message of the day
+# on oper-up
+#<module name="m_opermotd.so">
+#
+#-#-#-#-#-#-#-#-#-#-#   OPERMOTD CONFIGURATION   -#-#-#-#-#-#-#-#-#-#-#
+#                                                                     #
+# If you are using the m_opermotd.so module, specify the motd here    #
+#                                                                     #
+#<opermotd file="oper.motd">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Override module: Adds support for oper override
+#<module name="m_override.so">
+#
+#-#-#-#-#-#-#-#-#-#-#   OVERRIDE CONFIGURATION   -#-#-#-#-#-#-#-#-#-#-#
+#                                                                     #
+# m_override.so is too complex it describe here, see the wiki:        #
+# http://www.inspircd.org/wiki/Oper_Override_Module                   #
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Oper levels module: Gives each oper a level and prevents
+# actions being taken against higher level opers
+# Specify the level as the 'level' parameter of the <type> tag
+#<module name="m_operlevels.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Oper modes module: Allows you to specify modes to add/remove on oper
+# Specify the modes as the 'modes' parameter of the <type> tag
+#<module name="m_opermodes.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# PostgreSQL module: Allows other SQL modules to access PgSQL databases
+# through a unified API. You must copy the source for this module
+# from the directory src/modules/extra, plus the file m_sqlv2.h
+#<module name="m_pgsql.so">
+#
+#-#-#-#-#-#-#-#-#-#-#-#- SQL CONFIGURATION   -#-#-#-#-#-#-#-#-#-#-#-#-#
+#                                                                     #
+# m_pgsql.so is more complex than described here, see the wiki for    #
+# more: http://www.inspircd.org/wiki/SQL_Service_Provider_Module      #
+#
+#<database name="mydb" username="myuser" password="mypass" hostname="localhost" id="my_database" ssl="no">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Random Quote module: provides a random quote on connect.
+# NOTE: Some of these may mimic fatal errors and confuse users and 
+# opers alike! - BEWARE!
+#<module name="m_randquote.so">
+#
+#-#-#-#-#-#-#-#-#-#-  RANDOMQUOTES CONFIGURATION -#-#-#-#-#-#-#-#-#-#-#
+#                                                                     #
+# Optional - If you specify to use the m_randquote.so module, then    #
+# specify below the path to the randquotes.conf file.                 #
+#                                                                     #
+#<randquote file="randquotes.conf">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Redirect module: Adds channel redirection (mode +L)
+#<module name="m_redirect.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Registered users only channel creation
+# Allows only registered users and opers to create new channels.
+#<module name="m_regonlycreate.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Remove module: Adds the /REMOVE command which is a peaceful
+# alternative to /KICK
+#<module name="m_remove.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Restrict banned users module:
+# Disallows banned users on a channel from messaging the channel,
+# changing nick, or changing the topic, if loaded.
+#<module name="m_restrictbanned.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Restricted channels module: Allows only opers to create channels
+#<module name="m_restrictchans.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Restrict message module: Allows users to only message opers
+#<module name="m_restrictmsg.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Provide /LIST throttling (to prevent flooding) and /LIST safety to
+# prevent excess flood when the list is large.
+#<module name="m_safelist.so">
+#
+#-#-#-#-#-#-#-#-#-#-# SAFELIST CONFIGURATION -#-#-#-#-#-#-#-#-#-#-#-#-#
+#
+# When using Safelist, you may set the following values;
+#
+# The first value, 'throttle', sets the amount of time in seconds a user
+# must wait between LIST commands. For example, if this is set to 60
+# (the default) then the user may not /LIST more than once a minute.
+# If not defined, the default value is 60 seconds.
+#
+# The second value, 'maxlisters', indicates the maximum number of users
+# which may be retrieving a LIST at once. It is not recommended you raise
+# this value, as increasing it too high can make your network vulnerable
+# to floodbots which waste your bandwidth and CPU time with LIST requests.
+#
+#<safelist throttle="60" maxlisters="50">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# SAJOIN module: Adds the /SAJOIN command
+#<module name="m_sajoin.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# SAMODE module: Adds the oper /SAMODE command
+#<module name="m_samode.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# SANICK module: Allows opers to change user's nicks
+#<module name="m_sanick.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# SAPART module: Adds the oper /SAPART command
+#<module name="m_sapart.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# SAQUIT module: Adds the oper /SAQUIT command (abusable!!!)
+#<module name="m_saquit.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Secure list module: Prevent /LIST in the first minute of connection,
+# crippling most spambots and trojan spreader bots.
+#<module name="m_securelist.so">
+#
+#-#-#-#-#-#-#-#-#-# SECURELIST CONFIGURATION -#-#-#-#-#-#-#-#-#-#-#-#-#
+#                                                                     #
+# Securelist can be harmful to some irc search engines such as        #
+# netsplit.de and searchirc.com. To prevent securelist blocking these #
+# sites from listing, define exception tags as shown below:           #
+<securehost exception="*@*.searchirc.org">
+<securehost exception="*@*.netsplit.de">
+<securehost exception="*@echo940.server4you.de">
+#                                                                     #
+# Define the following variable to change how long a user must wait   #
+# before issuing a LIST. If not defined, defaults to 60 seconds.      #
+#                                                                     #
+#<securelist waittime="60">                                           #
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# See nicks module: Allow for SNOMASK +N which shows nick changes.
+#<module name="m_seenicks.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Set Idle module: Adds a command for opers to change their
+# idle time (mainly a toy)
+#<module name="m_setidle.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Services support module: Adds several usermodes such as +R and +M
+# this module implements the 'identified' state via user mode +r, which
+# is similar to the DALnet and dreamforge systems.
+#<module name="m_services.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Services support module: Adds several usermodes such as +R and +M
+# this module implements the 'identified' state via account names (AC)
+# and is similar in operation to the way asuka and ircu handle services.
+# it cannot be used at the same time as m_services, above.
+#<module name="m_services_account.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Sethost module: Adds the /SETHOST command
+# See m_chghost for how to customise valid chars for hostnames
+#<module name="m_sethost.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Setident module: Adds the /SETIDENT command
+#<module name="m_setident.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# SETNAME module: Adds the /SETNAME command
+#<module name="m_setname.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Show Whois module: Adds the +W usermode which allows opers
+# to see when they are whois'ed (can be annoying).
+#<module name="m_showwhois.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Spy module: Adds the commands SPYLIST and SPYNAMES that let opers
+# see who is in a +s channel, and list +s channels, show keys of keyed
+# channels the oper is not a member of etc. (standard 'abusive' features
+# of many other ircds, modulized here in InspIRCd).
+#<module name="m_spy.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# SSL channel mode module: Adds support for SSL-only channels (+z).
+# does not do anything useful without a working SSL module (see below)
+#<module name="m_sslmodes.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Dummy ssl module: If you have other servers on your network which
+# have SSL, but your server does not have ssl enabled, you should load
+# this module, which will handle SSL metadata (e.g. the "Is using ssl"
+# field in the WHOIS information).
+#<module name="m_ssl_dummy.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# GnuTLS ssl module: Adds support for client-server SSL using GnuTLS,
+# if enabled. You must copy the source for this module from the directory
+# src/modules/extra, or answer 'yes' in ./configure when asked if you
+# want to enable this, or it will not load.
+#<module name="m_ssl_gnutls.so">
+#
+#-#-#-#-#-#-#-#-#-#-#-  GNUTLS CONFIGURATION   -#-#-#-#-#-#-#-#-#-#-#-#
+#                                                                     #
+# m_ssl_gnutls.so is too complex it describe here, see the wiki:      #
+# http://www.inspircd.org/wiki/GnuTLS_SSL_Module                      #
+#                                                                     #
+# NOTE: If you want to use this module to encrypt and sign your       #
+# server to server traffic, you MUST load it before m_spanningtree in #
+# your configuration file!                                            #
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# SSL Info module: Allows users to retrieve information about other
+# user's peer SSL certificates and keys. This can be used by client
+# scripts to validate users. For this to work, one of m_ssl_gnutls.so
+# or m_ssl_openssl.so must be loaded. You must symlink the source for
+# this module from the directory src/modules/extra.
+#<module name="m_sslinfo.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# OpenSSL ssl module: Adds support for client-server SSL using OpenSSL,
+# if enabled. You must copy the source for this module from the directory
+# src/modules/extra, or answer 'yes' in ./configure when asked if you
+# want to enable this, or it will not load.
+#<module name="m_ssl_openssl.so">
+#
+#-#-#-#-#-#-#-#-#-#-#- OPENSSL CONFIGURATION   -#-#-#-#-#-#-#-#-#-#-#-#
+#                                                                     #
+# m_ssl_openssl.so is too complex it describe here, see the wiki:     #
+# http://www.inspircd.org/wiki/OpenSSL_SSL_Module                     #
+#                                                                     #
+# NOTE: If you want to use this module to encrypt and sign your       #
+# server to server traffic, you MUST load it before m_spanningtree in #
+# your configuration file!                                            #
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# SSL Cert Oper module: Allows opers to oper up using the key fingerprint
+# stored within their SSL certificate and key pair.
+# When using this module, one of m_ssl_gnutls.so or m_ssl_openssl.so must
+# be loaded. An extra value should be added to enabled opers, which
+# is in the following format: fingerprint="<hash>". For more information,
+# see the example in the oper blocks.
+#<module name="m_ssl_oper_cert.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Strip colour module: Adds the channel mode +S
+#<module name="m_stripcolor.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# SILENCE module: Adds support for /SILENCE
+#<module name="m_silence.so">
+#
+# Configuration tags:
+#
+#<silence maxentries="32">
+#
+# Sets the maximum number of entries on a users silence list.
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Extended SILENCE module: Adds support for /SILENCE with additional
+# features to silence based on invites, channel messages, etc.
+#<module name="m_silence_ext.so">
+#
+# The configuration tags for this module are identical to those of
+# m_silence, shown above.
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# SQLite3 module: Allows other SQL modules to access SQLite3          #
+# databases through a unified API. You must link the source for this  #
+# module from the directory src/modules/extra to src/modules, plus    #
+# the file m_sqlv2.h                                                  #
+#<module name="m_sqlite3.so">
+#
+#-#-#-#-#-#-#-#-#-#-#-#- SQL CONFIGURATION   -#-#-#-#-#-#-#-#-#-#-#-#-#
+#                                                                     #
+# m_sqlite.so is more complex than described here, see the wiki for   #
+# more: http://www.inspircd.org/wiki/SQLite3_Service_Provider_Module  #
+#
+#<database hostname="/full/path/to/database.db" id="anytext">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# SQLutils module: Provides some utilities to SQL client modules, such
+# as mapping queries to users and channels. You must copy the source
+# for this module from the directory src/modules/extra/m_sqlutils.cpp
+# and src/modules/extra/m_sqlutils.h into /src/modules
+# Needed for, and loaded before: SQLauth and SQLoper
+#<module name="m_sqlutils.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# SQL authentication module: Allows IRCd connections to be tied into
+# a database table (for example a forum). You must copy the source for
+# this module from the directory src/modules/extra
+# Depends on the SQLutils module being loaded first.
+#<module name="m_sqlauth.so">
+#
+#-#-#-#-#-#-#-#-#-#-#- SQLAUTH CONFIGURATION   -#-#-#-#-#-#-#-#-#-#-#-#
+#                                                                     #
+# m_sqlauth.so is too complex it describe here, see the wiki:         #
+# http://www.inspircd.org/wiki/SQL_Authentication_Module              #
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# SQL logging module: Allows you to log network-wide data for your
+# network in a fully normalized set of SQL tables. You must copy the
+# source for this module from the directory src/modules/extra
+#<module name="m_sqllog.so">
+#
+#-#-#-#-#-#-#-#-#-#-#-  SQLLOG CONFIGURATION   -#-#-#-#-#-#-#-#-#-#-#-#
+#                                                                     #
+# dbid       - Database ID to use (see m_sql)                         #
+#                                                                     #
+# See also: http://www.inspircd.org/wiki/SQL_Logging_Module           #
+#                                                                     #
+#<sqllog dbid="1">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# SQL oper module: Allows you to store oper credentials in an SQL table
+# You must copy the source for this module from the directory src/modules/extra
+# Depends on the SQLutils module being loaded first.
+#<module name="m_sqloper.so">
+#
+#-#-#-#-#-#-#-#-#-#-#- SQLOPER CONFIGURATION   -#-#-#-#-#-#-#-#-#-#-#-#
+#                                                                     #
+# dbid       - Database ID to use (see m_sql)                         #
+#                                                                     #
+# See also: http://www.inspircd.org/wiki/SQL_Oper_Storage_Module      #
+#                                                                     #
+#<sqloper dbid="1">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# SVSHold module: Implements SVSHOLD. Like Q:Lines, but can only be   #
+# added/removed by Services.                                          #
+#<module name="m_svshold.so">
+
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# SWHOIS module: Allows you to add arbitary lines to user WHOIS.
+#<module name="m_swhois.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Test command module: Does nothing significant. Read: pointless.
+#<module name="m_testcommand.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Timed bans module: Adds timed bans and the /TBAN command
+#<module name="m_timedbans.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Test line module: Adds the /TLINE command, used to test how many
+# users a /GLINE or /ZLINE etc would match.
+#<module name="m_tline.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# UHNAMES support module: Adds support for the IRCX style UHNAMES
+# extension, which displays ident and hostname in the names list for
+# each user, saving clients from doing a WHO on the channel. Note that
+# this module is not widely supported yet. If a client does not support
+# UHNAMES it will not enable it, this will not break incompatible
+# clients.
+#<module name="m_uhnames.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Uninvite module: Adds the /UNINVITE command which lets users remove
+# pending invites from channels without waiting for the user to join.
+#<module name="m_uninvite.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Userip module: Adds the /USERIP command
+#<module name="m_userip.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Vhost module: Adds the VHOST command which allows for adding virtual
+# hosts which are accessible using a username and password in the config.
+#<module name="m_vhost.so">
+#
+#-#-#-#-#-#-#-#-#-#-#- VHOST CONFIGURATION   -#-#-#-#-#-#-#-#-#-#-#-#-#
+#                                                                     #
+# user       - Username for the vhost.                                #
+#                                                                     #
+# pass       - Password for the vhost.                                #
+#                                                                     #
+# host       - Vhost to set.                                          #
+#
+#<vhost user="some_username" pass="some_password" host="some.host">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# Watch module: Adds the WATCH command, which is used by clients to 
+# maintain notify lists.
+#<module name="m_watch.so">
+#
+# Configuration tags:
+#
+#<watch maxentries="32">
+#
+# Sets the maximum number of entries on a user's watch list.
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# XMLSocket module: Adds support for connections using the shockwave
+# flash XMLSocket. Note that this does not work if the client you are
+# using has retarded ideas of the IRC protocol. Your client must still
+# send RFC-correct lines to the server, this module only changes the
+# line ending from newlines to null terminators.
+#
+#<module name="m_xmlsocket.so">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+# ZipLinks module: Adds support for zlib deflate on server to server
+# connections. Both ends of the connection must load this module.
+#
+#<module name="m_ziplink.so">
+#
+# To use this module, you must enable it as a transport type in your
+# <link> tags or <bind> tags using the transport name 'zip'.
+# See the documentation of <link> and <bind>, respectively.
+#
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-  BAN OPTIONS  -#-#-#-#-#-#-#-#-#-#-#-#-#-#
+#                                                                     #
+# The ban tags define nick masks, host masks and ip ranges which are  #
+# banned from your server. All details in these tags are local to     #
+# Your server.                                                        #
+#                                                                     #
+#                                                                     #
+# badip lines ban an ip range (same as a zline)                       #
+#                                                                     #
+# ipmask       -          The ip range to ban (wildcards possible)    #
+#                         CIDR is supported in the IP mask.           #
+# reason       -          Reason to display when disconnected         #
+#                                                                     #
+# badnick lines ban a nick mask (same as a qline)                     #
+#                                                                     #
+# nick         -          Nick mask to ban (wildcards possible)       #
+# reason       -          Reason to display on /NICK                  #
+#                                                                     #
+# badhost lines ban a user@host mask (same as a kline)                #
+#                                                                     #
+# host         -          ident@hostname (wildcards possible)         #
+#                         If you specify an IP, CIDR is supported.    #
+# reason       -          Reason to display on disconnection          #
+#                                                                     #
+# exception lines define a hostmask that is excempt from [kzg]lines   #
+#                                                                     #
+# host         -          ident@hostname (wildcards possible)         #
+#                         If you specify an IP, CIDR is supported.    #
+# reason       -          Reason, shown only in /stats e              #
+#                                                                     #
+
+<badip ipmask="69.69.69.69" reason="No porn here thanks.">
+
+<badnick nick="ChanServ" reason="Reserved For Services">
+<badnick nick="NickServ" reason="Reserved For Services">
+<badnick nick="OperServ" reason="Reserved For Services">
+<badnick nick="MemoServ" reason="Reserved For Services">
+
+<badhost host="*@hundredz.n.hundredz.o.1337.kiddies.com" reason="Too many 1337 kiddiots">
+<badhost host="*@localhost" reason="No irc from localhost!">
+<badhost host="*@172.32.0.0/16" reason="This subnet is bad.">
+
+<exception host="*@ircop.host.com" reason="Opers hostname">
+
+#-#-#-#-#-#-#-#-#-#-#- INSANE BAN OPTIONS  -#-#-#-#-#-#-#-#-#-#-#-#-#-#
+#                                                                     #
+# This optional tag allows you to specify how wide a gline, eline,    #
+# kline, zline or qline can be before it is forbidden from being      #
+# set. By setting hostmasks="yes", you can allow all G, K, E lines,   #
+# no matter how many users the ban would cover. This is not           #
+# recommended! By setting ipmasks="yes", you can allow all Z lines,   #
+# no matter how many users these cover too. Needless to say we        #
+# don't recommend you do this, or, set nickmasks="yes", which will    #
+# allow any qline.                                                    #
+#                                                                     #
+# The trigger value indicates how wide any mask will be before it is  #
+# prevented from being set. The default value is 95.5% if this tag is #
+# not defined in your configuration file, meaning that if your        #
+# network has 1000 users, a gline matching over 955 of them will be   #
+# prevented from being added.                                         #
+#                                                                     #
+# Please note that remote servers (and services) are exempt from      #
+# these restrictions and expected to enforce their own policies       #
+# locally!                                                            #
+#                                                                     #
+
+<insane hostmasks="no" ipmasks="no" nickmasks="no" trigger="95.5">
+
+#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#- YAWN  -#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
+#                                                                     #
+#   You should already know what to do here :)                        #
+
+<die value="User error. Insert new user and press any key. (you didn't edit your config properly.)">
+
+
+#########################################################################
+#                                                                       #
+#                     - InspIRCd Development Team -                     #
+#                        http://www.inspircd.org                        #
+#                                                                       #
+#########################################################################
index 007e3c028c8312314e471e0804666116ab937490..b1a9bf5a94b66e3e854bd1b51674d2f642587394 100644 (file)
@@ -1 +1,3077 @@
-Network Working Group                                     P. Mockapetris\rRequest for Comments: 1035                                           ISI\r                                                           November 1987\rObsoletes: RFCs 882, 883, 973\r\r            DOMAIN NAMES - IMPLEMENTATION AND SPECIFICATION\r\r\r1. STATUS OF THIS MEMO\r\rThis RFC describes the details of the domain system and protocol, and\rassumes that the reader is familiar with the concepts discussed in a\rcompanion RFC, "Domain Names - Concepts and Facilities" [RFC-1034].\r\rThe domain system is a mixture of functions and data types which are an\rofficial protocol and functions and data types which are still\rexperimental.  Since the domain system is intentionally extensible, new\rdata types and experimental behavior should always be expected in parts\rof the system beyond the official protocol.  The official protocol parts\rinclude standard queries, responses and the Internet class RR data\rformats (e.g., host addresses).  Since the previous RFC set, several\rdefinitions have changed, so some previous definitions are obsolete.\r\rExperimental or obsolete features are clearly marked in these RFCs, and\rsuch information should be used with caution.\r\rThe reader is especially cautioned not to depend on the values which\rappear in examples to be current or complete, since their purpose is\rprimarily pedagogical.  Distribution of this memo is unlimited.\r\r                           Table of Contents\r\r  1. STATUS OF THIS MEMO                                              1\r  2. INTRODUCTION                                                     3\r      2.1. Overview                                                   3\r      2.2. Common configurations                                      4\r      2.3. Conventions                                                7\r          2.3.1. Preferred name syntax                                7\r          2.3.2. Data Transmission Order                              8\r          2.3.3. Character Case                                       9\r          2.3.4. Size limits                                         10\r  3. DOMAIN NAME SPACE AND RR DEFINITIONS                            10\r      3.1. Name space definitions                                    10\r      3.2. RR definitions                                            11\r          3.2.1. Format                                              11\r          3.2.2. TYPE values                                         12\r          3.2.3. QTYPE values                                        12\r          3.2.4. CLASS values                                        13\r\r\r\rMockapetris                                                     [Page 1]\r\f\rRFC 1035        Domain Implementation and Specification    November 1987\r\r\r          3.2.5. QCLASS values                                       13\r      3.3. Standard RRs                                              13\r          3.3.1. CNAME RDATA format                                  14\r          3.3.2. HINFO RDATA format                                  14\r          3.3.3. MB RDATA format (EXPERIMENTAL)                      14\r          3.3.4. MD RDATA format (Obsolete)                          15\r          3.3.5. MF RDATA format (Obsolete)                          15\r          3.3.6. MG RDATA format (EXPERIMENTAL)                      16\r          3.3.7. MINFO RDATA format (EXPERIMENTAL)                   16\r          3.3.8. MR RDATA format (EXPERIMENTAL)                      17\r          3.3.9. MX RDATA format                                     17\r          3.3.10. NULL RDATA format (EXPERIMENTAL)                   17\r          3.3.11. NS RDATA format                                    18\r          3.3.12. PTR RDATA format                                   18\r          3.3.13. SOA RDATA format                                   19\r          3.3.14. TXT RDATA format                                   20\r      3.4. ARPA Internet specific RRs                                20\r          3.4.1. A RDATA format                                      20\r          3.4.2. WKS RDATA format                                    21\r      3.5. IN-ADDR.ARPA domain                                       22\r      3.6. Defining new types, classes, and special namespaces       24\r  4. MESSAGES                                                        25\r      4.1. Format                                                    25\r          4.1.1. Header section format                               26\r          4.1.2. Question section format                             28\r          4.1.3. Resource record format                              29\r          4.1.4. Message compression                                 30\r      4.2. Transport                                                 32\r          4.2.1. UDP usage                                           32\r          4.2.2. TCP usage                                           32\r  5. MASTER FILES                                                    33\r      5.1. Format                                                    33\r      5.2. Use of master files to define zones                       35\r      5.3. Master file example                                       36\r  6. NAME SERVER IMPLEMENTATION                                      37\r      6.1. Architecture                                              37\r          6.1.1. Control                                             37\r          6.1.2. Database                                            37\r          6.1.3. Time                                                39\r      6.2. Standard query processing                                 39\r      6.3. Zone refresh and reload processing                        39\r      6.4. Inverse queries (Optional)                                40\r          6.4.1. The contents of inverse queries and responses       40\r          6.4.2. Inverse query and response example                  41\r          6.4.3. Inverse query processing                            42\r\r\r\r\r\r\rMockapetris                                                     [Page 2]\r\f\rRFC 1035        Domain Implementation and Specification    November 1987\r\r\r      6.5. Completion queries and responses                          42\r  7. RESOLVER IMPLEMENTATION                                         43\r      7.1. Transforming a user request into a query                  43\r      7.2. Sending the queries                                       44\r      7.3. Processing responses                                      46\r      7.4. Using the cache                                           47\r  8. MAIL SUPPORT                                                    47\r      8.1. Mail exchange binding                                     48\r      8.2. Mailbox binding (Experimental)                            48\r  9. REFERENCES and BIBLIOGRAPHY                                     50\r  Index                                                              54\r\r2. INTRODUCTION\r\r2.1. Overview\r\rThe goal of domain names is to provide a mechanism for naming resources\rin such a way that the names are usable in different hosts, networks,\rprotocol families, internets, and administrative organizations.\r\rFrom the user's point of view, domain names are useful as arguments to a\rlocal agent, called a resolver, which retrieves information associated\rwith the domain name.  Thus a user might ask for the host address or\rmail information associated with a particular domain name.  To enable\rthe user to request a particular type of information, an appropriate\rquery type is passed to the resolver with the domain name.  To the user,\rthe domain tree is a single information space; the resolver is\rresponsible for hiding the distribution of data among name servers from\rthe user.\r\rFrom the resolver's point of view, the database that makes up the domain\rspace is distributed among various name servers.  Different parts of the\rdomain space are stored in different name servers, although a particular\rdata item will be stored redundantly in two or more name servers.  The\rresolver starts with knowledge of at least one name server.  When the\rresolver processes a user query it asks a known name server for the\rinformation; in return, the resolver either receives the desired\rinformation or a referral to another name server.  Using these\rreferrals, resolvers learn the identities and contents of other name\rservers.  Resolvers are responsible for dealing with the distribution of\rthe domain space and dealing with the effects of name server failure by\rconsulting redundant databases in other servers.\r\rName servers manage two kinds of data.  The first kind of data held in\rsets called zones; each zone is the complete database for a particular\r"pruned" subtree of the domain space.  This data is called\rauthoritative.  A name server periodically checks to make sure that its\rzones are up to date, and if not, obtains a new copy of updated zones\r\r\r\rMockapetris                                                     [Page 3]\r\f\rRFC 1035        Domain Implementation and Specification    November 1987\r\r\rfrom master files stored locally or in another name server.  The second\rkind of data is cached data which was acquired by a local resolver.\rThis data may be incomplete, but improves the performance of the\rretrieval process when non-local data is repeatedly accessed.  Cached\rdata is eventually discarded by a timeout mechanism.\r\rThis functional structure isolates the problems of user interface,\rfailure recovery, and distribution in the resolvers and isolates the\rdatabase update and refresh problems in the name servers.\r\r2.2. Common configurations\r\rA host can participate in the domain name system in a number of ways,\rdepending on whether the host runs programs that retrieve information\rfrom the domain system, name servers that answer queries from other\rhosts, or various combinations of both functions.  The simplest, and\rperhaps most typical, configuration is shown below:\r\r                 Local Host                        |  Foreign\r                                                   |\r    +---------+               +----------+         |  +--------+\r    |         | user queries  |          |queries  |  |        |\r    |  User   |-------------->|          |---------|->|Foreign |\r    | Program |               | Resolver |         |  |  Name  |\r    |         |<--------------|          |<--------|--| Server |\r    |         | user responses|          |responses|  |        |\r    +---------+               +----------+         |  +--------+\r                                |     A            |\r                cache additions |     | references |\r                                V     |            |\r                              +----------+         |\r                              |  cache   |         |\r                              +----------+         |\r\rUser programs interact with the domain name space through resolvers; the\rformat of user queries and user responses is specific to the host and\rits operating system.  User queries will typically be operating system\rcalls, and the resolver and its cache will be part of the host operating\rsystem.  Less capable hosts may choose to implement the resolver as a\rsubroutine to be linked in with every program that needs its services.\rResolvers answer user queries with information they acquire via queries\rto foreign name servers and the local cache.\r\rNote that the resolver may have to make several queries to several\rdifferent foreign name servers to answer a particular user query, and\rhence the resolution of a user query may involve several network\raccesses and an arbitrary amount of time.  The queries to foreign name\rservers and the corresponding responses have a standard format described\r\r\r\rMockapetris                                                     [Page 4]\r\f\rRFC 1035        Domain Implementation and Specification    November 1987\r\r\rin this memo, and may be datagrams.\r\rDepending on its capabilities, a name server could be a stand alone\rprogram on a dedicated machine or a process or processes on a large\rtimeshared host.  A simple configuration might be:\r\r                 Local Host                        |  Foreign\r                                                   |\r      +---------+                                  |\r     /         /|                                  |\r    +---------+ |             +----------+         |  +--------+\r    |         | |             |          |responses|  |        |\r    |         | |             |   Name   |---------|->|Foreign |\r    |  Master |-------------->|  Server  |         |  |Resolver|\r    |  files  | |             |          |<--------|--|        |\r    |         |/              |          | queries |  +--------+\r    +---------+               +----------+         |\r\rHere a primary name server acquires information about one or more zones\rby reading master files from its local file system, and answers queries\rabout those zones that arrive from foreign resolvers.\r\rThe DNS requires that all zones be redundantly supported by more than\rone name server.  Designated secondary servers can acquire zones and\rcheck for updates from the primary server using the zone transfer\rprotocol of the DNS.  This configuration is shown below:\r\r                 Local Host                        |  Foreign\r                                                   |\r      +---------+                                  |\r     /         /|                                  |\r    +---------+ |             +----------+         |  +--------+\r    |         | |             |          |responses|  |        |\r    |         | |             |   Name   |---------|->|Foreign |\r    |  Master |-------------->|  Server  |         |  |Resolver|\r    |  files  | |             |          |<--------|--|        |\r    |         |/              |          | queries |  +--------+\r    +---------+               +----------+         |\r                                A     |maintenance |  +--------+\r                                |     +------------|->|        |\r                                |      queries     |  |Foreign |\r                                |                  |  |  Name  |\r                                +------------------|--| Server |\r                             maintenance responses |  +--------+\r\rIn this configuration, the name server periodically establishes a\rvirtual circuit to a foreign name server to acquire a copy of a zone or\rto check that an existing copy has not changed.  The messages sent for\r\r\r\rMockapetris                                                     [Page 5]\r\f\rRFC 1035        Domain Implementation and Specification    November 1987\r\r\rthese maintenance activities follow the same form as queries and\rresponses, but the message sequences are somewhat different.\r\rThe information flow in a host that supports all aspects of the domain\rname system is shown below:\r\r                 Local Host                        |  Foreign\r                                                   |\r    +---------+               +----------+         |  +--------+\r    |         | user queries  |          |queries  |  |        |\r    |  User   |-------------->|          |---------|->|Foreign |\r    | Program |               | Resolver |         |  |  Name  |\r    |         |<--------------|          |<--------|--| Server |\r    |         | user responses|          |responses|  |        |\r    +---------+               +----------+         |  +--------+\r                                |     A            |\r                cache additions |     | references |\r                                V     |            |\r                              +----------+         |\r                              |  Shared  |         |\r                              | database |         |\r                              +----------+         |\r                                A     |            |\r      +---------+     refreshes |     | references |\r     /         /|               |     V            |\r    +---------+ |             +----------+         |  +--------+\r    |         | |             |          |responses|  |        |\r    |         | |             |   Name   |---------|->|Foreign |\r    |  Master |-------------->|  Server  |         |  |Resolver|\r    |  files  | |             |          |<--------|--|        |\r    |         |/              |          | queries |  +--------+\r    +---------+               +----------+         |\r                                A     |maintenance |  +--------+\r                                |     +------------|->|        |\r                                |      queries     |  |Foreign |\r                                |                  |  |  Name  |\r                                +------------------|--| Server |\r                             maintenance responses |  +--------+\r\rThe shared database holds domain space data for the local name server\rand resolver.  The contents of the shared database will typically be a\rmixture of authoritative data maintained by the periodic refresh\roperations of the name server and cached data from previous resolver\rrequests.  The structure of the domain data and the necessity for\rsynchronization between name servers and resolvers imply the general\rcharacteristics of this database, but the actual format is up to the\rlocal implementor.\r\r\r\r\rMockapetris                                                     [Page 6]\r\f\rRFC 1035        Domain Implementation and Specification    November 1987\r\r\rInformation flow can also be tailored so that a group of hosts act\rtogether to optimize activities.  Sometimes this is done to offload less\rcapable hosts so that they do not have to implement a full resolver.\rThis can be appropriate for PCs or hosts which want to minimize the\ramount of new network code which is required.  This scheme can also\rallow a group of hosts can share a small number of caches rather than\rmaintaining a large number of separate caches, on the premise that the\rcentralized caches will have a higher hit ratio.  In either case,\rresolvers are replaced with stub resolvers which act as front ends to\rresolvers located in a recursive server in one or more name servers\rknown to perform that service:\r\r                   Local Hosts                     |  Foreign\r                                                   |\r    +---------+                                    |\r    |         | responses                          |\r    | Stub    |<--------------------+              |\r    | Resolver|                     |              |\r    |         |----------------+    |              |\r    +---------+ recursive      |    |              |\r                queries        |    |              |\r                               V    |              |\r    +---------+ recursive     +----------+         |  +--------+\r    |         | queries       |          |queries  |  |        |\r    | Stub    |-------------->| Recursive|---------|->|Foreign |\r    | Resolver|               | Server   |         |  |  Name  |\r    |         |<--------------|          |<--------|--| Server |\r    +---------+ responses     |          |responses|  |        |\r                              +----------+         |  +--------+\r                              |  Central |         |\r                              |   cache  |         |\r                              +----------+         |\r\rIn any case, note that domain components are always replicated for\rreliability whenever possible.\r\r2.3. Conventions\r\rThe domain system has several conventions dealing with low-level, but\rfundamental, issues.  While the implementor is free to violate these\rconventions WITHIN HIS OWN SYSTEM, he must observe these conventions in\rALL behavior observed from other hosts.\r\r2.3.1. Preferred name syntax\r\rThe DNS specifications attempt to be as general as possible in the rules\rfor constructing domain names.  The idea is that the name of any\rexisting object can be expressed as a domain name with minimal changes.\r\r\r\rMockapetris                                                     [Page 7]\r\f\rRFC 1035        Domain Implementation and Specification    November 1987\r\r\rHowever, when assigning a domain name for an object, the prudent user\rwill select a name which satisfies both the rules of the domain system\rand any existing rules for the object, whether these rules are published\ror implied by existing programs.\r\rFor example, when naming a mail domain, the user should satisfy both the\rrules of this memo and those in RFC-822.  When creating a new host name,\rthe old rules for HOSTS.TXT should be followed.  This avoids problems\rwhen old software is converted to use domain names.\r\rThe following syntax will result in fewer problems with many\r\rapplications that use domain names (e.g., mail, TELNET).\r\r<domain> ::= <subdomain> | " "\r\r<subdomain> ::= <label> | <subdomain> "." <label>\r\r<label> ::= <letter> [ [ <ldh-str> ] <let-dig> ]\r\r<ldh-str> ::= <let-dig-hyp> | <let-dig-hyp> <ldh-str>\r\r<let-dig-hyp> ::= <let-dig> | "-"\r\r<let-dig> ::= <letter> | <digit>\r\r<letter> ::= any one of the 52 alphabetic characters A through Z in\rupper case and a through z in lower case\r\r<digit> ::= any one of the ten digits 0 through 9\r\rNote that while upper and lower case letters are allowed in domain\rnames, no significance is attached to the case.  That is, two names with\rthe same spelling but different case are to be treated as if identical.\r\rThe labels must follow the rules for ARPANET host names.  They must\rstart with a letter, end with a letter or digit, and have as interior\rcharacters only letters, digits, and hyphen.  There are also some\rrestrictions on the length.  Labels must be 63 characters or less.\r\rFor example, the following strings identify hosts in the Internet:\r\rA.ISI.EDU XX.LCS.MIT.EDU SRI-NIC.ARPA\r\r2.3.2. Data Transmission Order\r\rThe order of transmission of the header and data described in this\rdocument is resolved to the octet level.  Whenever a diagram shows a\r\r\r\rMockapetris                                                     [Page 8]\r\f\rRFC 1035        Domain Implementation and Specification    November 1987\r\r\rgroup of octets, the order of transmission of those octets is the normal\rorder in which they are read in English.  For example, in the following\rdiagram, the octets are transmitted in the order they are numbered.\r\r     0                   1\r     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5\r    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r    |       1       |       2       |\r    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r    |       3       |       4       |\r    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r    |       5       |       6       |\r    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r\rWhenever an octet represents a numeric quantity, the left most bit in\rthe diagram is the high order or most significant bit.  That is, the bit\rlabeled 0 is the most significant bit.  For example, the following\rdiagram represents the value 170 (decimal).\r\r     0 1 2 3 4 5 6 7\r    +-+-+-+-+-+-+-+-+\r    |1 0 1 0 1 0 1 0|\r    +-+-+-+-+-+-+-+-+\r\rSimilarly, whenever a multi-octet field represents a numeric quantity\rthe left most bit of the whole field is the most significant bit.  When\ra multi-octet quantity is transmitted the most significant octet is\rtransmitted first.\r\r2.3.3. Character Case\r\rFor all parts of the DNS that are part of the official protocol, all\rcomparisons between character strings (e.g., labels, domain names, etc.)\rare done in a case-insensitive manner.  At present, this rule is in\rforce throughout the domain system without exception.  However, future\radditions beyond current usage may need to use the full binary octet\rcapabilities in names, so attempts to store domain names in 7-bit ASCII\ror use of special bytes to terminate labels, etc., should be avoided.\r\rWhen data enters the domain system, its original case should be\rpreserved whenever possible.  In certain circumstances this cannot be\rdone.  For example, if two RRs are stored in a database, one at x.y and\rone at X.Y, they are actually stored at the same place in the database,\rand hence only one casing would be preserved.  The basic rule is that\rcase can be discarded only when data is used to define structure in a\rdatabase, and two names are identical when compared in a case\rinsensitive manner.\r\r\r\r\rMockapetris                                                     [Page 9]\r\f\rRFC 1035        Domain Implementation and Specification    November 1987\r\r\rLoss of case sensitive data must be minimized.  Thus while data for x.y\rand X.Y may both be stored under a single location x.y or X.Y, data for\ra.x and B.X would never be stored under A.x, A.X, b.x, or b.X.  In\rgeneral, this preserves the case of the first label of a domain name,\rbut forces standardization of interior node labels.\r\rSystems administrators who enter data into the domain database should\rtake care to represent the data they supply to the domain system in a\rcase-consistent manner if their system is case-sensitive.  The data\rdistribution system in the domain system will ensure that consistent\rrepresentations are preserved.\r\r2.3.4. Size limits\r\rVarious objects and parameters in the DNS have size limits.  They are\rlisted below.  Some could be easily changed, others are more\rfundamental.\r\rlabels          63 octets or less\r\rnames           255 octets or less\r\rTTL             positive values of a signed 32 bit number.\r\rUDP messages    512 octets or less\r\r3. DOMAIN NAME SPACE AND RR DEFINITIONS\r\r3.1. Name space definitions\r\rDomain names in messages are expressed in terms of a sequence of labels.\rEach label is represented as a one octet length field followed by that\rnumber of octets.  Since every domain name ends with the null label of\rthe root, a domain name is terminated by a length byte of zero.  The\rhigh order two bits of every length octet must be zero, and the\rremaining six bits of the length field limit the label to 63 octets or\rless.\r\rTo simplify implementations, the total length of a domain name (i.e.,\rlabel octets and label length octets) is restricted to 255 octets or\rless.\r\rAlthough labels can contain any 8 bit values in octets that make up a\rlabel, it is strongly recommended that labels follow the preferred\rsyntax described elsewhere in this memo, which is compatible with\rexisting host naming conventions.  Name servers and resolvers must\rcompare labels in a case-insensitive manner (i.e., A=a), assuming ASCII\rwith zero parity.  Non-alphabetic codes must match exactly.\r\r\r\rMockapetris                                                    [Page 10]\r\f\rRFC 1035        Domain Implementation and Specification    November 1987\r\r\r3.2. RR definitions\r\r3.2.1. Format\r\rAll RRs have the same top level format shown below:\r\r                                    1  1  1  1  1  1\r      0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5\r    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r    |                                               |\r    /                                               /\r    /                      NAME                     /\r    |                                               |\r    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r    |                      TYPE                     |\r    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r    |                     CLASS                     |\r    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r    |                      TTL                      |\r    |                                               |\r    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r    |                   RDLENGTH                    |\r    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|\r    /                     RDATA                     /\r    /                                               /\r    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r\r\rwhere:\r\rNAME            an owner name, i.e., the name of the node to which this\r                resource record pertains.\r\rTYPE            two octets containing one of the RR TYPE codes.\r\rCLASS           two octets containing one of the RR CLASS codes.\r\rTTL             a 32 bit signed integer that specifies the time interval\r                that the resource record may be cached before the source\r                of the information should again be consulted.  Zero\r                values are interpreted to mean that the RR can only be\r                used for the transaction in progress, and should not be\r                cached.  For example, SOA records are always distributed\r                with a zero TTL to prohibit caching.  Zero values can\r                also be used for extremely volatile data.\r\rRDLENGTH        an unsigned 16 bit integer that specifies the length in\r                octets of the RDATA field.\r\r\r\rMockapetris                                                    [Page 11]\r\f\rRFC 1035        Domain Implementation and Specification    November 1987\r\r\rRDATA           a variable length string of octets that describes the\r                resource.  The format of this information varies\r                according to the TYPE and CLASS of the resource record.\r\r3.2.2. TYPE values\r\rTYPE fields are used in resource records.  Note that these types are a\rsubset of QTYPEs.\r\rTYPE            value and meaning\r\rA               1 a host address\r\rNS              2 an authoritative name server\r\rMD              3 a mail destination (Obsolete - use MX)\r\rMF              4 a mail forwarder (Obsolete - use MX)\r\rCNAME           5 the canonical name for an alias\r\rSOA             6 marks the start of a zone of authority\r\rMB              7 a mailbox domain name (EXPERIMENTAL)\r\rMG              8 a mail group member (EXPERIMENTAL)\r\rMR              9 a mail rename domain name (EXPERIMENTAL)\r\rNULL            10 a null RR (EXPERIMENTAL)\r\rWKS             11 a well known service description\r\rPTR             12 a domain name pointer\r\rHINFO           13 host information\r\rMINFO           14 mailbox or mail list information\r\rMX              15 mail exchange\r\rTXT             16 text strings\r\r3.2.3. QTYPE values\r\rQTYPE fields appear in the question part of a query.  QTYPES are a\rsuperset of TYPEs, hence all TYPEs are valid QTYPEs.  In addition, the\rfollowing QTYPEs are defined:\r\r\r\rMockapetris                                                    [Page 12]\r\f\rRFC 1035        Domain Implementation and Specification    November 1987\r\r\rAXFR            252 A request for a transfer of an entire zone\r\rMAILB           253 A request for mailbox-related records (MB, MG or MR)\r\rMAILA           254 A request for mail agent RRs (Obsolete - see MX)\r\r*               255 A request for all records\r\r3.2.4. CLASS values\r\rCLASS fields appear in resource records.  The following CLASS mnemonics\rand values are defined:\r\rIN              1 the Internet\r\rCS              2 the CSNET class (Obsolete - used only for examples in\r                some obsolete RFCs)\r\rCH              3 the CHAOS class\r\rHS              4 Hesiod [Dyer 87]\r\r3.2.5. QCLASS values\r\rQCLASS fields appear in the question section of a query.  QCLASS values\rare a superset of CLASS values; every CLASS is a valid QCLASS.  In\raddition to CLASS values, the following QCLASSes are defined:\r\r*               255 any class\r\r3.3. Standard RRs\r\rThe following RR definitions are expected to occur, at least\rpotentially, in all classes.  In particular, NS, SOA, CNAME, and PTR\rwill be used in all classes, and have the same format in all classes.\rBecause their RDATA format is known, all domain names in the RDATA\rsection of these RRs may be compressed.\r\r<domain-name> is a domain name represented as a series of labels, and\rterminated by a label with zero length.  <character-string> is a single\rlength octet followed by that number of characters.  <character-string>\ris treated as binary information, and can be up to 256 characters in\rlength (including the length octet).\r\r\r\r\r\r\r\r\rMockapetris                                                    [Page 13]\r\f\rRFC 1035        Domain Implementation and Specification    November 1987\r\r\r3.3.1. CNAME RDATA format\r\r    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r    /                     CNAME                     /\r    /                                               /\r    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r\rwhere:\r\rCNAME           A <domain-name> which specifies the canonical or primary\r                name for the owner.  The owner name is an alias.\r\rCNAME RRs cause no additional section processing, but name servers may\rchoose to restart the query at the canonical name in certain cases.  See\rthe description of name server logic in [RFC-1034] for details.\r\r3.3.2. HINFO RDATA format\r\r    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r    /                      CPU                      /\r    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r    /                       OS                      /\r    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r\rwhere:\r\rCPU             A <character-string> which specifies the CPU type.\r\rOS              A <character-string> which specifies the operating\r                system type.\r\rStandard values for CPU and OS can be found in [RFC-1010].\r\rHINFO records are used to acquire general information about a host.  The\rmain use is for protocols such as FTP that can use special procedures\rwhen talking between machines or operating systems of the same type.\r\r3.3.3. MB RDATA format (EXPERIMENTAL)\r\r    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r    /                   MADNAME                     /\r    /                                               /\r    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r\rwhere:\r\rMADNAME         A <domain-name> which specifies a host which has the\r                specified mailbox.\r\r\r\rMockapetris                                                    [Page 14]\r\f\rRFC 1035        Domain Implementation and Specification    November 1987\r\r\rMB records cause additional section processing which looks up an A type\rRRs corresponding to MADNAME.\r\r3.3.4. MD RDATA format (Obsolete)\r\r    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r    /                   MADNAME                     /\r    /                                               /\r    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r\rwhere:\r\rMADNAME         A <domain-name> which specifies a host which has a mail\r                agent for the domain which should be able to deliver\r                mail for the domain.\r\rMD records cause additional section processing which looks up an A type\rrecord corresponding to MADNAME.\r\rMD is obsolete.  See the definition of MX and [RFC-974] for details of\rthe new scheme.  The recommended policy for dealing with MD RRs found in\ra master file is to reject them, or to convert them to MX RRs with a\rpreference of 0.\r\r3.3.5. MF RDATA format (Obsolete)\r\r    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r    /                   MADNAME                     /\r    /                                               /\r    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r\rwhere:\r\rMADNAME         A <domain-name> which specifies a host which has a mail\r                agent for the domain which will accept mail for\r                forwarding to the domain.\r\rMF records cause additional section processing which looks up an A type\rrecord corresponding to MADNAME.\r\rMF is obsolete.  See the definition of MX and [RFC-974] for details ofw\rthe new scheme.  The recommended policy for dealing with MD RRs found in\ra master file is to reject them, or to convert them to MX RRs with a\rpreference of 10.\r\r\r\r\r\r\r\rMockapetris                                                    [Page 15]\r\f\rRFC 1035        Domain Implementation and Specification    November 1987\r\r\r3.3.6. MG RDATA format (EXPERIMENTAL)\r\r    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r    /                   MGMNAME                     /\r    /                                               /\r    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r\rwhere:\r\rMGMNAME         A <domain-name> which specifies a mailbox which is a\r                member of the mail group specified by the domain name.\r\rMG records cause no additional section processing.\r\r3.3.7. MINFO RDATA format (EXPERIMENTAL)\r\r    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r    /                    RMAILBX                    /\r    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r    /                    EMAILBX                    /\r    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r\rwhere:\r\rRMAILBX         A <domain-name> which specifies a mailbox which is\r                responsible for the mailing list or mailbox.  If this\r                domain name names the root, the owner of the MINFO RR is\r                responsible for itself.  Note that many existing mailing\r                lists use a mailbox X-request for the RMAILBX field of\r                mailing list X, e.g., Msgroup-request for Msgroup.  This\r                field provides a more general mechanism.\r\r\rEMAILBX         A <domain-name> which specifies a mailbox which is to\r                receive error messages related to the mailing list or\r                mailbox specified by the owner of the MINFO RR (similar\r                to the ERRORS-TO: field which has been proposed).  If\r                this domain name names the root, errors should be\r                returned to the sender of the message.\r\rMINFO records cause no additional section processing.  Although these\rrecords can be associated with a simple mailbox, they are usually used\rwith a mailing list.\r\r\r\r\r\r\r\r\rMockapetris                                                    [Page 16]\r\f\rRFC 1035        Domain Implementation and Specification    November 1987\r\r\r3.3.8. MR RDATA format (EXPERIMENTAL)\r\r    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r    /                   NEWNAME                     /\r    /                                               /\r    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r\rwhere:\r\rNEWNAME         A <domain-name> which specifies a mailbox which is the\r                proper rename of the specified mailbox.\r\rMR records cause no additional section processing.  The main use for MR\ris as a forwarding entry for a user who has moved to a different\rmailbox.\r\r3.3.9. MX RDATA format\r\r    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r    |                  PREFERENCE                   |\r    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r    /                   EXCHANGE                    /\r    /                                               /\r    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r\rwhere:\r\rPREFERENCE      A 16 bit integer which specifies the preference given to\r                this RR among others at the same owner.  Lower values\r                are preferred.\r\rEXCHANGE        A <domain-name> which specifies a host willing to act as\r                a mail exchange for the owner name.\r\rMX records cause type A additional section processing for the host\rspecified by EXCHANGE.  The use of MX RRs is explained in detail in\r[RFC-974].\r\r3.3.10. NULL RDATA format (EXPERIMENTAL)\r\r    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r    /                  <anything>                   /\r    /                                               /\r    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r\rAnything at all may be in the RDATA field so long as it is 65535 octets\ror less.\r\r\r\r\rMockapetris                                                    [Page 17]\r\f\rRFC 1035        Domain Implementation and Specification    November 1987\r\r\rNULL records cause no additional section processing.  NULL RRs are not\rallowed in master files.  NULLs are used as placeholders in some\rexperimental extensions of the DNS.\r\r3.3.11. NS RDATA format\r\r    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r    /                   NSDNAME                     /\r    /                                               /\r    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r\rwhere:\r\rNSDNAME         A <domain-name> which specifies a host which should be\r                authoritative for the specified class and domain.\r\rNS records cause both the usual additional section processing to locate\ra type A record, and, when used in a referral, a special search of the\rzone in which they reside for glue information.\r\rThe NS RR states that the named host should be expected to have a zone\rstarting at owner name of the specified class.  Note that the class may\rnot indicate the protocol family which should be used to communicate\rwith the host, although it is typically a strong hint.  For example,\rhosts which are name servers for either Internet (IN) or Hesiod (HS)\rclass information are normally queried using IN class protocols.\r\r3.3.12. PTR RDATA format\r\r    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r    /                   PTRDNAME                    /\r    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r\rwhere:\r\rPTRDNAME        A <domain-name> which points to some location in the\r                domain name space.\r\rPTR records cause no additional section processing.  These RRs are used\rin special domains to point to some other location in the domain space.\rThese records are simple data, and don't imply any special processing\rsimilar to that performed by CNAME, which identifies aliases.  See the\rdescription of the IN-ADDR.ARPA domain for an example.\r\r\r\r\r\r\r\r\rMockapetris                                                    [Page 18]\r\f\rRFC 1035        Domain Implementation and Specification    November 1987\r\r\r3.3.13. SOA RDATA format\r\r    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r    /                     MNAME                     /\r    /                                               /\r    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r    /                     RNAME                     /\r    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r    |                    SERIAL                     |\r    |                                               |\r    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r    |                    REFRESH                    |\r    |                                               |\r    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r    |                     RETRY                     |\r    |                                               |\r    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r    |                    EXPIRE                     |\r    |                                               |\r    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r    |                    MINIMUM                    |\r    |                                               |\r    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r\rwhere:\r\rMNAME           The <domain-name> of the name server that was the\r                original or primary source of data for this zone.\r\rRNAME           A <domain-name> which specifies the mailbox of the\r                person responsible for this zone.\r\rSERIAL          The unsigned 32 bit version number of the original copy\r                of the zone.  Zone transfers preserve this value.  This\r                value wraps and should be compared using sequence space\r                arithmetic.\r\rREFRESH         A 32 bit time interval before the zone should be\r                refreshed.\r\rRETRY           A 32 bit time interval that should elapse before a\r                failed refresh should be retried.\r\rEXPIRE          A 32 bit time value that specifies the upper limit on\r                the time interval that can elapse before the zone is no\r                longer authoritative.\r\r\r\r\r\rMockapetris                                                    [Page 19]\r\f\rRFC 1035        Domain Implementation and Specification    November 1987\r\r\rMINIMUM         The unsigned 32 bit minimum TTL field that should be\r                exported with any RR from this zone.\r\rSOA records cause no additional section processing.\r\rAll times are in units of seconds.\r\rMost of these fields are pertinent only for name server maintenance\roperations.  However, MINIMUM is used in all query operations that\rretrieve RRs from a zone.  Whenever a RR is sent in a response to a\rquery, the TTL field is set to the maximum of the TTL field from the RR\rand the MINIMUM field in the appropriate SOA.  Thus MINIMUM is a lower\rbound on the TTL field for all RRs in a zone.  Note that this use of\rMINIMUM should occur when the RRs are copied into the response and not\rwhen the zone is loaded from a master file or via a zone transfer.  The\rreason for this provison is to allow future dynamic update facilities to\rchange the SOA RR with known semantics.\r\r\r3.3.14. TXT RDATA format\r\r    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r    /                   TXT-DATA                    /\r    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r\rwhere:\r\rTXT-DATA        One or more <character-string>s.\r\rTXT RRs are used to hold descriptive text.  The semantics of the text\rdepends on the domain where it is found.\r\r3.4. Internet specific RRs\r\r3.4.1. A RDATA format\r\r    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r    |                    ADDRESS                    |\r    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r\rwhere:\r\rADDRESS         A 32 bit Internet address.\r\rHosts that have multiple Internet addresses will have multiple A\rrecords.\r\r\r\r\r\rMockapetris                                                    [Page 20]\r\f\rRFC 1035        Domain Implementation and Specification    November 1987\r\r\rA records cause no additional section processing.  The RDATA section of\ran A line in a master file is an Internet address expressed as four\rdecimal numbers separated by dots without any imbedded spaces (e.g.,\r"10.2.0.52" or "192.0.5.6").\r\r3.4.2. WKS RDATA format\r\r    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r    |                    ADDRESS                    |\r    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r    |       PROTOCOL        |                       |\r    +--+--+--+--+--+--+--+--+                       |\r    |                                               |\r    /                   <BIT MAP>                   /\r    /                                               /\r    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r\rwhere:\r\rADDRESS         An 32 bit Internet address\r\rPROTOCOL        An 8 bit IP protocol number\r\r<BIT MAP>       A variable length bit map.  The bit map must be a\r                multiple of 8 bits long.\r\rThe WKS record is used to describe the well known services supported by\ra particular protocol on a particular internet address.  The PROTOCOL\rfield specifies an IP protocol number, and the bit map has one bit per\rport of the specified protocol.  The first bit corresponds to port 0,\rthe second to port 1, etc.  If the bit map does not include a bit for a\rprotocol of interest, that bit is assumed zero.  The appropriate values\rand mnemonics for ports and protocols are specified in [RFC-1010].\r\rFor example, if PROTOCOL=TCP (6), the 26th bit corresponds to TCP port\r25 (SMTP).  If this bit is set, a SMTP server should be listening on TCP\rport 25; if zero, SMTP service is not supported on the specified\raddress.\r\rThe purpose of WKS RRs is to provide availability information for\rservers for TCP and UDP.  If a server supports both TCP and UDP, or has\rmultiple Internet addresses, then multiple WKS RRs are used.\r\rWKS RRs cause no additional section processing.\r\rIn master files, both ports and protocols are expressed using mnemonics\ror decimal numbers.\r\r\r\r\rMockapetris                                                    [Page 21]\r\f\rRFC 1035        Domain Implementation and Specification    November 1987\r\r\r3.5. IN-ADDR.ARPA domain\r\rThe Internet uses a special domain to support gateway location and\rInternet address to host mapping.  Other classes may employ a similar\rstrategy in other domains.  The intent of this domain is to provide a\rguaranteed method to perform host address to host name mapping, and to\rfacilitate queries to locate all gateways on a particular network in the\rInternet.\r\rNote that both of these services are similar to functions that could be\rperformed by inverse queries; the difference is that this part of the\rdomain name space is structured according to address, and hence can\rguarantee that the appropriate data can be located without an exhaustive\rsearch of the domain space.\r\rThe domain begins at IN-ADDR.ARPA and has a substructure which follows\rthe Internet addressing structure.\r\rDomain names in the IN-ADDR.ARPA domain are defined to have up to four\rlabels in addition to the IN-ADDR.ARPA suffix.  Each label represents\rone octet of an Internet address, and is expressed as a character string\rfor a decimal value in the range 0-255 (with leading zeros omitted\rexcept in the case of a zero octet which is represented by a single\rzero).\r\rHost addresses are represented by domain names that have all four labels\rspecified.  Thus data for Internet address 10.2.0.52 is located at\rdomain name 52.0.2.10.IN-ADDR.ARPA.  The reversal, though awkward to\rread, allows zones to be delegated which are exactly one network of\raddress space.  For example, 10.IN-ADDR.ARPA can be a zone containing\rdata for the ARPANET, while 26.IN-ADDR.ARPA can be a separate zone for\rMILNET.  Address nodes are used to hold pointers to primary host names\rin the normal domain space.\r\rNetwork numbers correspond to some non-terminal nodes at various depths\rin the IN-ADDR.ARPA domain, since Internet network numbers are either 1,\r2, or 3 octets.  Network nodes are used to hold pointers to the primary\rhost names of gateways attached to that network.  Since a gateway is, by\rdefinition, on more than one network, it will typically have two or more\rnetwork nodes which point at it.  Gateways will also have host level\rpointers at their fully qualified addresses.\r\rBoth the gateway pointers at network nodes and the normal host pointers\rat full address nodes use the PTR RR to point back to the primary domain\rnames of the corresponding hosts.\r\rFor example, the IN-ADDR.ARPA domain will contain information about the\rISI gateway between net 10 and 26, an MIT gateway from net 10 to MIT's\r\r\r\rMockapetris                                                    [Page 22]\r\f\rRFC 1035        Domain Implementation and Specification    November 1987\r\r\rnet 18, and hosts A.ISI.EDU and MULTICS.MIT.EDU.  Assuming that ISI\rgateway has addresses 10.2.0.22 and 26.0.0.103, and a name MILNET-\rGW.ISI.EDU, and the MIT gateway has addresses 10.0.0.77 and 18.10.0.4\rand a name GW.LCS.MIT.EDU, the domain database would contain:\r\r    10.IN-ADDR.ARPA.           PTR MILNET-GW.ISI.EDU.\r    10.IN-ADDR.ARPA.           PTR GW.LCS.MIT.EDU.\r    18.IN-ADDR.ARPA.           PTR GW.LCS.MIT.EDU.\r    26.IN-ADDR.ARPA.           PTR MILNET-GW.ISI.EDU.\r    22.0.2.10.IN-ADDR.ARPA.    PTR MILNET-GW.ISI.EDU.\r    103.0.0.26.IN-ADDR.ARPA.   PTR MILNET-GW.ISI.EDU.\r    77.0.0.10.IN-ADDR.ARPA.    PTR GW.LCS.MIT.EDU.\r    4.0.10.18.IN-ADDR.ARPA.    PTR GW.LCS.MIT.EDU.\r    103.0.3.26.IN-ADDR.ARPA.   PTR A.ISI.EDU.\r    6.0.0.10.IN-ADDR.ARPA.     PTR MULTICS.MIT.EDU.\r\rThus a program which wanted to locate gateways on net 10 would originate\ra query of the form QTYPE=PTR, QCLASS=IN, QNAME=10.IN-ADDR.ARPA.  It\rwould receive two RRs in response:\r\r    10.IN-ADDR.ARPA.           PTR MILNET-GW.ISI.EDU.\r    10.IN-ADDR.ARPA.           PTR GW.LCS.MIT.EDU.\r\rThe program could then originate QTYPE=A, QCLASS=IN queries for MILNET-\rGW.ISI.EDU. and GW.LCS.MIT.EDU. to discover the Internet addresses of\rthese gateways.\r\rA resolver which wanted to find the host name corresponding to Internet\rhost address 10.0.0.6 would pursue a query of the form QTYPE=PTR,\rQCLASS=IN, QNAME=6.0.0.10.IN-ADDR.ARPA, and would receive:\r\r    6.0.0.10.IN-ADDR.ARPA.     PTR MULTICS.MIT.EDU.\r\rSeveral cautions apply to the use of these services:\r   - Since the IN-ADDR.ARPA special domain and the normal domain\r     for a particular host or gateway will be in different zones,\r     the possibility exists that that the data may be inconsistent.\r\r   - Gateways will often have two names in separate domains, only\r     one of which can be primary.\r\r   - Systems that use the domain database to initialize their\r     routing tables must start with enough gateway information to\r     guarantee that they can access the appropriate name server.\r\r   - The gateway data only reflects the existence of a gateway in a\r     manner equivalent to the current HOSTS.TXT file.  It doesn't\r     replace the dynamic availability information from GGP or EGP.\r\r\r\rMockapetris                                                    [Page 23]\r\f\rRFC 1035        Domain Implementation and Specification    November 1987\r\r\r3.6. Defining new types, classes, and special namespaces\r\rThe previously defined types and classes are the ones in use as of the\rdate of this memo.  New definitions should be expected.  This section\rmakes some recommendations to designers considering additions to the\rexisting facilities.  The mailing list NAMEDROPPERS@SRI-NIC.ARPA is the\rforum where general discussion of design issues takes place.\r\rIn general, a new type is appropriate when new information is to be\radded to the database about an existing object, or we need new data\rformats for some totally new object.  Designers should attempt to define\rtypes and their RDATA formats that are generally applicable to all\rclasses, and which avoid duplication of information.  New classes are\rappropriate when the DNS is to be used for a new protocol, etc which\rrequires new class-specific data formats, or when a copy of the existing\rname space is desired, but a separate management domain is necessary.\r\rNew types and classes need mnemonics for master files; the format of the\rmaster files requires that the mnemonics for type and class be disjoint.\r\rTYPE and CLASS values must be a proper subset of QTYPEs and QCLASSes\rrespectively.\r\rThe present system uses multiple RRs to represent multiple values of a\rtype rather than storing multiple values in the RDATA section of a\rsingle RR.  This is less efficient for most applications, but does keep\rRRs shorter.  The multiple RRs assumption is incorporated in some\rexperimental work on dynamic update methods.\r\rThe present system attempts to minimize the duplication of data in the\rdatabase in order to insure consistency.  Thus, in order to find the\raddress of the host for a mail exchange, you map the mail domain name to\ra host name, then the host name to addresses, rather than a direct\rmapping to host address.  This approach is preferred because it avoids\rthe opportunity for inconsistency.\r\rIn defining a new type of data, multiple RR types should not be used to\rcreate an ordering between entries or express different formats for\requivalent bindings, instead this information should be carried in the\rbody of the RR and a single type used.  This policy avoids problems with\rcaching multiple types and defining QTYPEs to match multiple types.\r\rFor example, the original form of mail exchange binding used two RR\rtypes one to represent a "closer" exchange (MD) and one to represent a\r"less close" exchange (MF).  The difficulty is that the presence of one\rRR type in a cache doesn't convey any information about the other\rbecause the query which acquired the cached information might have used\ra QTYPE of MF, MD, or MAILA (which matched both).  The redesigned\r\r\r\rMockapetris                                                    [Page 24]\r\f\rRFC 1035        Domain Implementation and Specification    November 1987\r\r\rservice used a single type (MX) with a "preference" value in the RDATA\rsection which can order different RRs.  However, if any MX RRs are found\rin the cache, then all should be there.\r\r4. MESSAGES\r\r4.1. Format\r\rAll communications inside of the domain protocol are carried in a single\rformat called a message.  The top level format of message is divided\rinto 5 sections (some of which are empty in certain cases) shown below:\r\r    +---------------------+\r    |        Header       |\r    +---------------------+\r    |       Question      | the question for the name server\r    +---------------------+\r    |        Answer       | RRs answering the question\r    +---------------------+\r    |      Authority      | RRs pointing toward an authority\r    +---------------------+\r    |      Additional     | RRs holding additional information\r    +---------------------+\r\rThe header section is always present.  The header includes fields that\rspecify which of the remaining sections are present, and also specify\rwhether the message is a query or a response, a standard query or some\rother opcode, etc.\r\rThe names of the sections after the header are derived from their use in\rstandard queries.  The question section contains fields that describe a\rquestion to a name server.  These fields are a query type (QTYPE), a\rquery class (QCLASS), and a query domain name (QNAME).  The last three\rsections have the same format: a possibly empty list of concatenated\rresource records (RRs).  The answer section contains RRs that answer the\rquestion; the authority section contains RRs that point toward an\rauthoritative name server; the additional records section contains RRs\rwhich relate to the query, but are not strictly answers for the\rquestion.\r\r\r\r\r\r\r\r\r\r\r\r\rMockapetris                                                    [Page 25]\r\f\rRFC 1035        Domain Implementation and Specification    November 1987\r\r\r4.1.1. Header section format\r\rThe header contains the following fields:\r\r                                    1  1  1  1  1  1\r      0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5\r    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r    |                      ID                       |\r    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r    |QR|   Opcode  |AA|TC|RD|RA|   Z    |   RCODE   |\r    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r    |                    QDCOUNT                    |\r    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r    |                    ANCOUNT                    |\r    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r    |                    NSCOUNT                    |\r    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r    |                    ARCOUNT                    |\r    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r\rwhere:\r\rID              A 16 bit identifier assigned by the program that\r                generates any kind of query.  This identifier is copied\r                the corresponding reply and can be used by the requester\r                to match up replies to outstanding queries.\r\rQR              A one bit field that specifies whether this message is a\r                query (0), or a response (1).\r\rOPCODE          A four bit field that specifies kind of query in this\r                message.  This value is set by the originator of a query\r                and copied into the response.  The values are:\r\r                0               a standard query (QUERY)\r\r                1               an inverse query (IQUERY)\r\r                2               a server status request (STATUS)\r\r                3-15            reserved for future use\r\rAA              Authoritative Answer - this bit is valid in responses,\r                and specifies that the responding name server is an\r                authority for the domain name in question section.\r\r                Note that the contents of the answer section may have\r                multiple owner names because of aliases.  The AA bit\r\r\r\rMockapetris                                                    [Page 26]\r\f\rRFC 1035        Domain Implementation and Specification    November 1987\r\r\r                corresponds to the name which matches the query name, or\r                the first owner name in the answer section.\r\rTC              TrunCation - specifies that this message was truncated\r                due to length greater than that permitted on the\r                transmission channel.\r\rRD              Recursion Desired - this bit may be set in a query and\r                is copied into the response.  If RD is set, it directs\r                the name server to pursue the query recursively.\r                Recursive query support is optional.\r\rRA              Recursion Available - this be is set or cleared in a\r                response, and denotes whether recursive query support is\r                available in the name server.\r\rZ               Reserved for future use.  Must be zero in all queries\r                and responses.\r\rRCODE           Response code - this 4 bit field is set as part of\r                responses.  The values have the following\r                interpretation:\r\r                0               No error condition\r\r                1               Format error - The name server was\r                                unable to interpret the query.\r\r                2               Server failure - The name server was\r                                unable to process this query due to a\r                                problem with the name server.\r\r                3               Name Error - Meaningful only for\r                                responses from an authoritative name\r                                server, this code signifies that the\r                                domain name referenced in the query does\r                                not exist.\r\r                4               Not Implemented - The name server does\r                                not support the requested kind of query.\r\r                5               Refused - The name server refuses to\r                                perform the specified operation for\r                                policy reasons.  For example, a name\r                                server may not wish to provide the\r                                information to the particular requester,\r                                or a name server may not wish to perform\r                                a particular operation (e.g., zone\r\r\r\rMockapetris                                                    [Page 27]\r\f\rRFC 1035        Domain Implementation and Specification    November 1987\r\r\r                                transfer) for particular data.\r\r                6-15            Reserved for future use.\r\rQDCOUNT         an unsigned 16 bit integer specifying the number of\r                entries in the question section.\r\rANCOUNT         an unsigned 16 bit integer specifying the number of\r                resource records in the answer section.\r\rNSCOUNT         an unsigned 16 bit integer specifying the number of name\r                server resource records in the authority records\r                section.\r\rARCOUNT         an unsigned 16 bit integer specifying the number of\r                resource records in the additional records section.\r\r4.1.2. Question section format\r\rThe question section is used to carry the "question" in most queries,\ri.e., the parameters that define what is being asked.  The section\rcontains QDCOUNT (usually 1) entries, each of the following format:\r\r                                    1  1  1  1  1  1\r      0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5\r    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r    |                                               |\r    /                     QNAME                     /\r    /                                               /\r    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r    |                     QTYPE                     |\r    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r    |                     QCLASS                    |\r    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r\rwhere:\r\rQNAME           a domain name represented as a sequence of labels, where\r                each label consists of a length octet followed by that\r                number of octets.  The domain name terminates with the\r                zero length octet for the null label of the root.  Note\r                that this field may be an odd number of octets; no\r                padding is used.\r\rQTYPE           a two octet code which specifies the type of the query.\r                The values for this field include all codes valid for a\r                TYPE field, together with some more general codes which\r                can match more than one type of RR.\r\r\r\rMockapetris                                                    [Page 28]\r\f\rRFC 1035        Domain Implementation and Specification    November 1987\r\r\rQCLASS          a two octet code that specifies the class of the query.\r                For example, the QCLASS field is IN for the Internet.\r\r4.1.3. Resource record format\r\rThe answer, authority, and additional sections all share the same\rformat: a variable number of resource records, where the number of\rrecords is specified in the corresponding count field in the header.\rEach resource record has the following format:\r                                    1  1  1  1  1  1\r      0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5\r    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r    |                                               |\r    /                                               /\r    /                      NAME                     /\r    |                                               |\r    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r    |                      TYPE                     |\r    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r    |                     CLASS                     |\r    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r    |                      TTL                      |\r    |                                               |\r    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r    |                   RDLENGTH                    |\r    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|\r    /                     RDATA                     /\r    /                                               /\r    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r\rwhere:\r\rNAME            a domain name to which this resource record pertains.\r\rTYPE            two octets containing one of the RR type codes.  This\r                field specifies the meaning of the data in the RDATA\r                field.\r\rCLASS           two octets which specify the class of the data in the\r                RDATA field.\r\rTTL             a 32 bit unsigned integer that specifies the time\r                interval (in seconds) that the resource record may be\r                cached before it should be discarded.  Zero values are\r                interpreted to mean that the RR can only be used for the\r                transaction in progress, and should not be cached.\r\r\r\r\r\rMockapetris                                                    [Page 29]\r\f\rRFC 1035        Domain Implementation and Specification    November 1987\r\r\rRDLENGTH        an unsigned 16 bit integer that specifies the length in\r                octets of the RDATA field.\r\rRDATA           a variable length string of octets that describes the\r                resource.  The format of this information varies\r                according to the TYPE and CLASS of the resource record.\r                For example, the if the TYPE is A and the CLASS is IN,\r                the RDATA field is a 4 octet ARPA Internet address.\r\r4.1.4. Message compression\r\rIn order to reduce the size of messages, the domain system utilizes a\rcompression scheme which eliminates the repetition of domain names in a\rmessage.  In this scheme, an entire domain name or a list of labels at\rthe end of a domain name is replaced with a pointer to a prior occurance\rof the same name.\r\rThe pointer takes the form of a two octet sequence:\r\r    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r    | 1  1|                OFFSET                   |\r    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r\rThe first two bits are ones.  This allows a pointer to be distinguished\rfrom a label, since the label must begin with two zero bits because\rlabels are restricted to 63 octets or less.  (The 10 and 01 combinations\rare reserved for future use.)  The OFFSET field specifies an offset from\rthe start of the message (i.e., the first octet of the ID field in the\rdomain header).  A zero offset specifies the first byte of the ID field,\retc.\r\rThe compression scheme allows a domain name in a message to be\rrepresented as either:\r\r   - a sequence of labels ending in a zero octet\r\r   - a pointer\r\r   - a sequence of labels ending with a pointer\r\rPointers can only be used for occurances of a domain name where the\rformat is not class specific.  If this were not the case, a name server\ror resolver would be required to know the format of all RRs it handled.\rAs yet, there are no such cases, but they may occur in future RDATA\rformats.\r\rIf a domain name is contained in a part of the message subject to a\rlength field (such as the RDATA section of an RR), and compression is\r\r\r\rMockapetris                                                    [Page 30]\r\f\rRFC 1035        Domain Implementation and Specification    November 1987\r\r\rused, the length of the compressed name is used in the length\rcalculation, rather than the length of the expanded name.\r\rPrograms are free to avoid using pointers in messages they generate,\ralthough this will reduce datagram capacity, and may cause truncation.\rHowever all programs are required to understand arriving messages that\rcontain pointers.\r\rFor example, a datagram might need to use the domain names F.ISI.ARPA,\rFOO.F.ISI.ARPA, ARPA, and the root.  Ignoring the other fields of the\rmessage, these domain names might be represented as:\r\r       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r    20 |           1           |           F           |\r       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r    22 |           3           |           I           |\r       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r    24 |           S           |           I           |\r       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r    26 |           4           |           A           |\r       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r    28 |           R           |           P           |\r       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r    30 |           A           |           0           |\r       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r\r       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r    40 |           3           |           F           |\r       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r    42 |           O           |           O           |\r       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r    44 | 1  1|                20                       |\r       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r\r       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r    64 | 1  1|                26                       |\r       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r\r       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r    92 |           0           |                       |\r       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\r\rThe domain name for F.ISI.ARPA is shown at offset 20.  The domain name\rFOO.F.ISI.ARPA is shown at offset 40; this definition uses a pointer to\rconcatenate a label for FOO to the previously defined F.ISI.ARPA.  The\rdomain name ARPA is defined at offset 64 using a pointer to the ARPA\rcomponent of the name F.ISI.ARPA at 20; note that this pointer relies on\rARPA being the last label in the string at 20.  The root domain name is\r\r\r\rMockapetris                                                    [Page 31]\r\f\rRFC 1035        Domain Implementation and Specification    November 1987\r\r\rdefined by a single octet of zeros at 92; the root domain name has no\rlabels.\r\r4.2. Transport\r\rThe DNS assumes that messages will be transmitted as datagrams or in a\rbyte stream carried by a virtual circuit.  While virtual circuits can be\rused for any DNS activity, datagrams are preferred for queries due to\rtheir lower overhead and better performance.  Zone refresh activities\rmust use virtual circuits because of the need for reliable transfer.\r\rThe Internet supports name server access using TCP [RFC-793] on server\rport 53 (decimal) as well as datagram access using UDP [RFC-768] on UDP\rport 53 (decimal).\r\r4.2.1. UDP usage\r\rMessages sent using UDP user server port 53 (decimal).\r\rMessages carried by UDP are restricted to 512 bytes (not counting the IP\ror UDP headers).  Longer messages are truncated and the TC bit is set in\rthe header.\r\rUDP is not acceptable for zone transfers, but is the recommended method\rfor standard queries in the Internet.  Queries sent using UDP may be\rlost, and hence a retransmission strategy is required.  Queries or their\rresponses may be reordered by the network, or by processing in name\rservers, so resolvers should not depend on them being returned in order.\r\rThe optimal UDP retransmission policy will vary with performance of the\rInternet and the needs of the client, but the following are recommended:\r\r   - The client should try other servers and server addresses\r     before repeating a query to a specific address of a server.\r\r   - The retransmission interval should be based on prior\r     statistics if possible.  Too aggressive retransmission can\r     easily slow responses for the community at large.  Depending\r     on how well connected the client is to its expected servers,\r     the minimum retransmission interval should be 2-5 seconds.\r\rMore suggestions on server selection and retransmission policy can be\rfound in the resolver section of this memo.\r\r4.2.2. TCP usage\r\rMessages sent over TCP connections use server port 53 (decimal).  The\rmessage is prefixed with a two byte length field which gives the message\r\r\r\rMockapetris                                                    [Page 32]\r\f\rRFC 1035        Domain Implementation and Specification    November 1987\r\r\rlength, excluding the two byte length field.  This length field allows\rthe low-level processing to assemble a complete message before beginning\rto parse it.\r\rSeveral connection management policies are recommended:\r\r   - The server should not block other activities waiting for TCP\r     data.\r\r   - The server should support multiple connections.\r\r   - The server should assume that the client will initiate\r     connection closing, and should delay closing its end of the\r     connection until all outstanding client requests have been\r     satisfied.\r\r   - If the server needs to close a dormant connection to reclaim\r     resources, it should wait until the connection has been idle\r     for a period on the order of two minutes.  In particular, the\r     server should allow the SOA and AXFR request sequence (which\r     begins a refresh operation) to be made on a single connection.\r     Since the server would be unable to answer queries anyway, a\r     unilateral close or reset may be used instead of a graceful\r     close.\r\r5. MASTER FILES\r\rMaster files are text files that contain RRs in text form.  Since the\rcontents of a zone can be expressed in the form of a list of RRs a\rmaster file is most often used to define a zone, though it can be used\rto list a cache's contents.  Hence, this section first discusses the\rformat of RRs in a master file, and then the special considerations when\ra master file is used to create a zone in some name server.\r\r5.1. Format\r\rThe format of these files is a sequence of entries.  Entries are\rpredominantly line-oriented, though parentheses can be used to continue\ra list of items across a line boundary, and text literals can contain\rCRLF within the text.  Any combination of tabs and spaces act as a\rdelimiter between the separate items that make up an entry.  The end of\rany line in the master file can end with a comment.  The comment starts\rwith a ";" (semicolon).\r\rThe following entries are defined:\r\r    <blank>[<comment>]\r\r\r\r\rMockapetris                                                    [Page 33]\r\f\rRFC 1035        Domain Implementation and Specification    November 1987\r\r\r    $ORIGIN <domain-name> [<comment>]\r\r    $INCLUDE <file-name> [<domain-name>] [<comment>]\r\r    <domain-name><rr> [<comment>]\r\r    <blank><rr> [<comment>]\r\rBlank lines, with or without comments, are allowed anywhere in the file.\r\rTwo control entries are defined: $ORIGIN and $INCLUDE.  $ORIGIN is\rfollowed by a domain name, and resets the current origin for relative\rdomain names to the stated name.  $INCLUDE inserts the named file into\rthe current file, and may optionally specify a domain name that sets the\rrelative domain name origin for the included file.  $INCLUDE may also\rhave a comment.  Note that a $INCLUDE entry never changes the relative\rorigin of the parent file, regardless of changes to the relative origin\rmade within the included file.\r\rThe last two forms represent RRs.  If an entry for an RR begins with a\rblank, then the RR is assumed to be owned by the last stated owner.  If\ran RR entry begins with a <domain-name>, then the owner name is reset.\r\r<rr> contents take one of the following forms:\r\r    [<TTL>] [<class>] <type> <RDATA>\r\r    [<class>] [<TTL>] <type> <RDATA>\r\rThe RR begins with optional TTL and class fields, followed by a type and\rRDATA field appropriate to the type and class.  Class and type use the\rstandard mnemonics, TTL is a decimal integer.  Omitted class and TTL\rvalues are default to the last explicitly stated values.  Since type and\rclass mnemonics are disjoint, the parse is unique.  (Note that this\rorder is different from the order used in examples and the order used in\rthe actual RRs; the given order allows easier parsing and defaulting.)\r\r<domain-name>s make up a large share of the data in the master file.\rThe labels in the domain name are expressed as character strings and\rseparated by dots.  Quoting conventions allow arbitrary characters to be\rstored in domain names.  Domain names that end in a dot are called\rabsolute, and are taken as complete.  Domain names which do not end in a\rdot are called relative; the actual domain name is the concatenation of\rthe relative part with an origin specified in a $ORIGIN, $INCLUDE, or as\ran argument to the master file loading routine.  A relative name is an\rerror when no origin is available.\r\r\r\r\r\rMockapetris                                                    [Page 34]\r\f\rRFC 1035        Domain Implementation and Specification    November 1987\r\r\r<character-string> is expressed in one or two ways: as a contiguous set\rof characters without interior spaces, or as a string beginning with a "\rand ending with a ".  Inside a " delimited string any character can\roccur, except for a " itself, which must be quoted using \ (back slash).\r\rBecause these files are text files several special encodings are\rnecessary to allow arbitrary data to be loaded.  In particular:\r\r                of the root.\r\r@               A free standing @ is used to denote the current origin.\r\r\X              where X is any character other than a digit (0-9), is\r                used to quote that character so that its special meaning\r                does not apply.  For example, "\." can be used to place\r                a dot character in a label.\r\r\DDD            where each D is a digit is the octet corresponding to\r                the decimal number described by DDD.  The resulting\r                octet is assumed to be text and is not checked for\r                special meaning.\r\r( )             Parentheses are used to group data that crosses a line\r                boundary.  In effect, line terminations are not\r                recognized within parentheses.\r\r;               Semicolon is used to start a comment; the remainder of\r                the line is ignored.\r\r5.2. Use of master files to define zones\r\rWhen a master file is used to load a zone, the operation should be\rsuppressed if any errors are encountered in the master file.  The\rrationale for this is that a single error can have widespread\rconsequences.  For example, suppose that the RRs defining a delegation\rhave syntax errors; then the server will return authoritative name\rerrors for all names in the subzone (except in the case where the\rsubzone is also present on the server).\r\rSeveral other validity checks that should be performed in addition to\rinsuring that the file is syntactically correct:\r\r   1. All RRs in the file should have the same class.\r\r   2. Exactly one SOA RR should be present at the top of the zone.\r\r   3. If delegations are present and glue information is required,\r      it should be present.\r\r\r\rMockapetris                                                    [Page 35]\r\f\rRFC 1035        Domain Implementation and Specification    November 1987\r\r\r   4. Information present outside of the authoritative nodes in the\r      zone should be glue information, rather than the result of an\r      origin or similar error.\r\r5.3. Master file example\r\rThe following is an example file which might be used to define the\rISI.EDU zone.and is loaded with an origin of ISI.EDU:\r\r@   IN  SOA     VENERA      Action\.domains (\r                                 20     ; SERIAL\r                                 7200   ; REFRESH\r                                 600    ; RETRY\r                                 3600000; EXPIRE\r                                 60)    ; MINIMUM\r\r        NS      A.ISI.EDU.\r        NS      VENERA\r        NS      VAXA\r        MX      10      VENERA\r        MX      20      VAXA\r\rA       A       26.3.0.103\r\rVENERA  A       10.1.0.52\r        A       128.9.0.32\r\rVAXA    A       10.2.0.27\r        A       128.9.0.33\r\r\r$INCLUDE <SUBSYS>ISI-MAILBOXES.TXT\r\rWhere the file <SUBSYS>ISI-MAILBOXES.TXT is:\r\r    MOE     MB      A.ISI.EDU.\r    LARRY   MB      A.ISI.EDU.\r    CURLEY  MB      A.ISI.EDU.\r    STOOGES MG      MOE\r            MG      LARRY\r            MG      CURLEY\r\rNote the use of the \ character in the SOA RR to specify the responsible\rperson mailbox "Action.domains@E.ISI.EDU".\r\r\r\r\r\r\r\rMockapetris                                                    [Page 36]\r\f\rRFC 1035        Domain Implementation and Specification    November 1987\r\r\r6. NAME SERVER IMPLEMENTATION\r\r6.1. Architecture\r\rThe optimal structure for the name server will depend on the host\roperating system and whether the name server is integrated with resolver\roperations, either by supporting recursive service, or by sharing its\rdatabase with a resolver.  This section discusses implementation\rconsiderations for a name server which shares a database with a\rresolver, but most of these concerns are present in any name server.\r\r6.1.1. Control\r\rA name server must employ multiple concurrent activities, whether they\rare implemented as separate tasks in the host's OS or multiplexing\rinside a single name server program.  It is simply not acceptable for a\rname server to block the service of UDP requests while it waits for TCP\rdata for refreshing or query activities.  Similarly, a name server\rshould not attempt to provide recursive service without processing such\rrequests in parallel, though it may choose to serialize requests from a\rsingle client, or to regard identical requests from the same client as\rduplicates.  A name server should not substantially delay requests while\rit reloads a zone from master files or while it incorporates a newly\rrefreshed zone into its database.\r\r6.1.2. Database\r\rWhile name server implementations are free to use any internal data\rstructures they choose, the suggested structure consists of three major\rparts:\r\r   - A "catalog" data structure which lists the zones available to\r     this server, and a "pointer" to the zone data structure.  The\r     main purpose of this structure is to find the nearest ancestor\r     zone, if any, for arriving standard queries.\r\r   - Separate data structures for each of the zones held by the\r     name server.\r\r   - A data structure for cached data. (or perhaps separate caches\r     for different classes)\r\rAll of these data structures can be implemented an identical tree\rstructure format, with different data chained off the nodes in different\rparts: in the catalog the data is pointers to zones, while in the zone\rand cache data structures, the data will be RRs.  In designing the tree\rframework the designer should recognize that query processing will need\rto traverse the tree using case-insensitive label comparisons; and that\r\r\r\rMockapetris                                                    [Page 37]\r\f\rRFC 1035        Domain Implementation and Specification    November 1987\r\r\rin real data, a few nodes have a very high branching factor (100-1000 or\rmore), but the vast majority have a very low branching factor (0-1).\r\rOne way to solve the case problem is to store the labels for each node\rin two pieces: a standardized-case representation of the label where all\rASCII characters are in a single case, together with a bit mask that\rdenotes which characters are actually of a different case.  The\rbranching factor diversity can be handled using a simple linked list for\ra node until the branching factor exceeds some threshold, and\rtransitioning to a hash structure after the threshold is exceeded.  In\rany case, hash structures used to store tree sections must insure that\rhash functions and procedures preserve the casing conventions of the\rDNS.\r\rThe use of separate structures for the different parts of the database\ris motivated by several factors:\r\r   - The catalog structure can be an almost static structure that\r     need change only when the system administrator changes the\r     zones supported by the server.  This structure can also be\r     used to store parameters used to control refreshing\r     activities.\r\r   - The individual data structures for zones allow a zone to be\r     replaced simply by changing a pointer in the catalog.  Zone\r     refresh operations can build a new structure and, when\r     complete, splice it into the database via a simple pointer\r     replacement.  It is very important that when a zone is\r     refreshed, queries should not use old and new data\r     simultaneously.\r\r   - With the proper search procedures, authoritative data in zones\r     will always "hide", and hence take precedence over, cached\r     data.\r\r   - Errors in zone definitions that cause overlapping zones, etc.,\r     may cause erroneous responses to queries, but problem\r     determination is simplified, and the contents of one "bad"\r     zone can't corrupt another.\r\r   - Since the cache is most frequently updated, it is most\r     vulnerable to corruption during system restarts.  It can also\r     become full of expired RR data.  In either case, it can easily\r     be discarded without disturbing zone data.\r\rA major aspect of database design is selecting a structure which allows\rthe name server to deal with crashes of the name server's host.  State\rinformation which a name server should save across system crashes\r\r\r\rMockapetris                                                    [Page 38]\r\f\rRFC 1035        Domain Implementation and Specification    November 1987\r\r\rincludes the catalog structure (including the state of refreshing for\reach zone) and the zone data itself.\r\r6.1.3. Time\r\rBoth the TTL data for RRs and the timing data for refreshing activities\rdepends on 32 bit timers in units of seconds.  Inside the database,\rrefresh timers and TTLs for cached data conceptually "count down", while\rdata in the zone stays with constant TTLs.\r\rA recommended implementation strategy is to store time in two ways:  as\ra relative increment and as an absolute time.  One way to do this is to\ruse positive 32 bit numbers for one type and negative numbers for the\rother.  The RRs in zones use relative times; the refresh timers and\rcache data use absolute times.  Absolute numbers are taken with respect\rto some known origin and converted to relative values when placed in the\rresponse to a query.  When an absolute TTL is negative after conversion\rto relative, then the data is expired and should be ignored.\r\r6.2. Standard query processing\r\rThe major algorithm for standard query processing is presented in\r[RFC-1034].\r\rWhen processing queries with QCLASS=*, or some other QCLASS which\rmatches multiple classes, the response should never be authoritative\runless the server can guarantee that the response covers all classes.\r\rWhen composing a response, RRs which are to be inserted in the\radditional section, but duplicate RRs in the answer or authority\rsections, may be omitted from the additional section.\r\rWhen a response is so long that truncation is required, the truncation\rshould start at the end of the response and work forward in the\rdatagram.  Thus if there is any data for the authority section, the\ranswer section is guaranteed to be unique.\r\rThe MINIMUM value in the SOA should be used to set a floor on the TTL of\rdata distributed from a zone.  This floor function should be done when\rthe data is copied into a response.  This will allow future dynamic\rupdate protocols to change the SOA MINIMUM field without ambiguous\rsemantics.\r\r6.3. Zone refresh and reload processing\r\rIn spite of a server's best efforts, it may be unable to load zone data\rfrom a master file due to syntax errors, etc., or be unable to refresh a\rzone within the its expiration parameter.  In this case, the name server\r\r\r\rMockapetris                                                    [Page 39]\r\f\rRFC 1035        Domain Implementation and Specification    November 1987\r\r\rshould answer queries as if it were not supposed to possess the zone.\r\rIf a master is sending a zone out via AXFR, and a new version is created\rduring the transfer, the master should continue to send the old version\rif possible.  In any case, it should never send part of one version and\rpart of another.  If completion is not possible, the master should reset\rthe connection on which the zone transfer is taking place.\r\r6.4. Inverse queries (Optional)\r\rInverse queries are an optional part of the DNS.  Name servers are not\rrequired to support any form of inverse queries.  If a name server\rreceives an inverse query that it does not support, it returns an error\rresponse with the "Not Implemented" error set in the header.  While\rinverse query support is optional, all name servers must be at least\rable to return the error response.\r\r6.4.1. The contents of inverse queries and responses          Inverse\rqueries reverse the mappings performed by standard query operations;\rwhile a standard query maps a domain name to a resource, an inverse\rquery maps a resource to a domain name.  For example, a standard query\rmight bind a domain name to a host address; the corresponding inverse\rquery binds the host address to a domain name.\r\rInverse queries take the form of a single RR in the answer section of\rthe message, with an empty question section.  The owner name of the\rquery RR and its TTL are not significant.  The response carries\rquestions in the question section which identify all names possessing\rthe query RR WHICH THE NAME SERVER KNOWS.  Since no name server knows\rabout all of the domain name space, the response can never be assumed to\rbe complete.  Thus inverse queries are primarily useful for database\rmanagement and debugging activities.  Inverse queries are NOT an\racceptable method of mapping host addresses to host names; use the IN-\rADDR.ARPA domain instead.\r\rWhere possible, name servers should provide case-insensitive comparisons\rfor inverse queries.  Thus an inverse query asking for an MX RR of\r"Venera.isi.edu" should get the same response as a query for\r"VENERA.ISI.EDU"; an inverse query for HINFO RR "IBM-PC UNIX" should\rproduce the same result as an inverse query for "IBM-pc unix".  However,\rthis cannot be guaranteed because name servers may possess RRs that\rcontain character strings but the name server does not know that the\rdata is character.\r\rWhen a name server processes an inverse query, it either returns:\r\r   1. zero, one, or multiple domain names for the specified\r      resource as QNAMEs in the question section\r\r\r\rMockapetris                                                    [Page 40]\r\f\rRFC 1035        Domain Implementation and Specification    November 1987\r\r\r   2. an error code indicating that the name server doesn't support\r      inverse mapping of the specified resource type.\r\rWhen the response to an inverse query contains one or more QNAMEs, the\rowner name and TTL of the RR in the answer section which defines the\rinverse query is modified to exactly match an RR found at the first\rQNAME.\r\rRRs returned in the inverse queries cannot be cached using the same\rmechanism as is used for the replies to standard queries.  One reason\rfor this is that a name might have multiple RRs of the same type, and\ronly one would appear.  For example, an inverse query for a single\raddress of a multiply homed host might create the impression that only\rone address existed.\r\r6.4.2. Inverse query and response example          The overall structure\rof an inverse query for retrieving the domain name that corresponds to\rInternet address 10.1.0.52 is shown below:\r\r                         +-----------------------------------------+\r           Header        |          OPCODE=IQUERY, ID=997          |\r                         +-----------------------------------------+\r          Question       |                 <empty>                 |\r                         +-----------------------------------------+\r           Answer        |        <anyname> A IN 10.1.0.52         |\r                         +-----------------------------------------+\r          Authority      |                 <empty>                 |\r                         +-----------------------------------------+\r         Additional      |                 <empty>                 |\r                         +-----------------------------------------+\r\rThis query asks for a question whose answer is the Internet style\raddress 10.1.0.52.  Since the owner name is not known, any domain name\rcan be used as a placeholder (and is ignored).  A single octet of zero,\rsignifying the root, is usually used because it minimizes the length of\rthe message.  The TTL of the RR is not significant.  The response to\rthis query might be:\r\r\r\r\r\r\r\r\r\r\r\r\r\r\rMockapetris                                                    [Page 41]\r\f\rRFC 1035        Domain Implementation and Specification    November 1987\r\r\r                         +-----------------------------------------+\r           Header        |         OPCODE=RESPONSE, ID=997         |\r                         +-----------------------------------------+\r          Question       |QTYPE=A, QCLASS=IN, QNAME=VENERA.ISI.EDU |\r                         +-----------------------------------------+\r           Answer        |  VENERA.ISI.EDU  A IN 10.1.0.52         |\r                         +-----------------------------------------+\r          Authority      |                 <empty>                 |\r                         +-----------------------------------------+\r         Additional      |                 <empty>                 |\r                         +-----------------------------------------+\r\rNote that the QTYPE in a response to an inverse query is the same as the\rTYPE field in the answer section of the inverse query.  Responses to\rinverse queries may contain multiple questions when the inverse is not\runique.  If the question section in the response is not empty, then the\rRR in the answer section is modified to correspond to be an exact copy\rof an RR at the first QNAME.\r\r6.4.3. Inverse query processing\r\rName servers that support inverse queries can support these operations\rthrough exhaustive searches of their databases, but this becomes\rimpractical as the size of the database increases.  An alternative\rapproach is to invert the database according to the search key.\r\rFor name servers that support multiple zones and a large amount of data,\rthe recommended approach is separate inversions for each zone.  When a\rparticular zone is changed during a refresh, only its inversions need to\rbe redone.\r\rSupport for transfer of this type of inversion may be included in future\rversions of the domain system, but is not supported in this version.\r\r6.5. Completion queries and responses\r\rThe optional completion services described in RFC-882 and RFC-883 have\rbeen deleted.  Redesigned services may become available in the future.\r\r\r\r\r\r\r\r\r\r\r\r\r\rMockapetris                                                    [Page 42]\r\f\rRFC 1035        Domain Implementation and Specification    November 1987\r\r\r7. RESOLVER IMPLEMENTATION\r\rThe top levels of the recommended resolver algorithm are discussed in\r[RFC-1034].  This section discusses implementation details assuming the\rdatabase structure suggested in the name server implementation section\rof this memo.\r\r7.1. Transforming a user request into a query\r\rThe first step a resolver takes is to transform the client's request,\rstated in a format suitable to the local OS, into a search specification\rfor RRs at a specific name which match a specific QTYPE and QCLASS.\rWhere possible, the QTYPE and QCLASS should correspond to a single type\rand a single class, because this makes the use of cached data much\rsimpler.  The reason for this is that the presence of data of one type\rin a cache doesn't confirm the existence or non-existence of data of\rother types, hence the only way to be sure is to consult an\rauthoritative source.  If QCLASS=* is used, then authoritative answers\rwon't be available.\r\rSince a resolver must be able to multiplex multiple requests if it is to\rperform its function efficiently, each pending request is usually\rrepresented in some block of state information.  This state block will\rtypically contain:\r\r   - A timestamp indicating the time the request began.\r     The timestamp is used to decide whether RRs in the database\r     can be used or are out of date.  This timestamp uses the\r     absolute time format previously discussed for RR storage in\r     zones and caches.  Note that when an RRs TTL indicates a\r     relative time, the RR must be timely, since it is part of a\r     zone.  When the RR has an absolute time, it is part of a\r     cache, and the TTL of the RR is compared against the timestamp\r     for the start of the request.\r\r     Note that using the timestamp is superior to using a current\r     time, since it allows RRs with TTLs of zero to be entered in\r     the cache in the usual manner, but still used by the current\r     request, even after intervals of many seconds due to system\r     load, query retransmission timeouts, etc.\r\r   - Some sort of parameters to limit the amount of work which will\r     be performed for this request.\r\r     The amount of work which a resolver will do in response to a\r     client request must be limited to guard against errors in the\r     database, such as circular CNAME references, and operational\r     problems, such as network partition which prevents the\r\r\r\rMockapetris                                                    [Page 43]\r\f\rRFC 1035        Domain Implementation and Specification    November 1987\r\r\r     resolver from accessing the name servers it needs.  While\r     local limits on the number of times a resolver will retransmit\r     a particular query to a particular name server address are\r     essential, the resolver should have a global per-request\r     counter to limit work on a single request.  The counter should\r     be set to some initial value and decremented whenever the\r     resolver performs any action (retransmission timeout,\r     retransmission, etc.)  If the counter passes zero, the request\r     is terminated with a temporary error.\r\r     Note that if the resolver structure allows one request to\r     start others in parallel, such as when the need to access a\r     name server for one request causes a parallel resolve for the\r     name server's addresses, the spawned request should be started\r     with a lower counter.  This prevents circular references in\r     the database from starting a chain reaction of resolver\r     activity.\r\r   - The SLIST data structure discussed in [RFC-1034].\r\r     This structure keeps track of the state of a request if it\r     must wait for answers from foreign name servers.\r\r7.2. Sending the queries\r\rAs described in [RFC-1034], the basic task of the resolver is to\rformulate a query which will answer the client's request and direct that\rquery to name servers which can provide the information.  The resolver\rwill usually only have very strong hints about which servers to ask, in\rthe form of NS RRs, and may have to revise the query, in response to\rCNAMEs, or revise the set of name servers the resolver is asking, in\rresponse to delegation responses which point the resolver to name\rservers closer to the desired information.  In addition to the\rinformation requested by the client, the resolver may have to call upon\rits own services to determine the address of name servers it wishes to\rcontact.\r\rIn any case, the model used in this memo assumes that the resolver is\rmultiplexing attention between multiple requests, some from the client,\rand some internally generated.  Each request is represented by some\rstate information, and the desired behavior is that the resolver\rtransmit queries to name servers in a way that maximizes the probability\rthat the request is answered, minimizes the time that the request takes,\rand avoids excessive transmissions.  The key algorithm uses the state\rinformation of the request to select the next name server address to\rquery, and also computes a timeout which will cause the next action\rshould a response not arrive.  The next action will usually be a\rtransmission to some other server, but may be a temporary error to the\r\r\r\rMockapetris                                                    [Page 44]\r\f\rRFC 1035        Domain Implementation and Specification    November 1987\r\r\rclient.\r\rThe resolver always starts with a list of server names to query (SLIST).\rThis list will be all NS RRs which correspond to the nearest ancestor\rzone that the resolver knows about.  To avoid startup problems, the\rresolver should have a set of default servers which it will ask should\rit have no current NS RRs which are appropriate.  The resolver then adds\rto SLIST all of the known addresses for the name servers, and may start\rparallel requests to acquire the addresses of the servers when the\rresolver has the name, but no addresses, for the name servers.\r\rTo complete initialization of SLIST, the resolver attaches whatever\rhistory information it has to the each address in SLIST.  This will\rusually consist of some sort of weighted averages for the response time\rof the address, and the batting average of the address (i.e., how often\rthe address responded at all to the request).  Note that this\rinformation should be kept on a per address basis, rather than on a per\rname server basis, because the response time and batting average of a\rparticular server may vary considerably from address to address.  Note\ralso that this information is actually specific to a resolver address /\rserver address pair, so a resolver with multiple addresses may wish to\rkeep separate histories for each of its addresses.  Part of this step\rmust deal with addresses which have no such history; in this case an\rexpected round trip time of 5-10 seconds should be the worst case, with\rlower estimates for the same local network, etc.\r\rNote that whenever a delegation is followed, the resolver algorithm\rreinitializes SLIST.\r\rThe information establishes a partial ranking of the available name\rserver addresses.  Each time an address is chosen and the state should\rbe altered to prevent its selection again until all other addresses have\rbeen tried.  The timeout for each transmission should be 50-100% greater\rthan the average predicted value to allow for variance in response.\r\rSome fine points:\r\r   - The resolver may encounter a situation where no addresses are\r     available for any of the name servers named in SLIST, and\r     where the servers in the list are precisely those which would\r     normally be used to look up their own addresses.  This\r     situation typically occurs when the glue address RRs have a\r     smaller TTL than the NS RRs marking delegation, or when the\r     resolver caches the result of a NS search.  The resolver\r     should detect this condition and restart the search at the\r     next ancestor zone, or alternatively at the root.\r\r\r\r\r\rMockapetris                                                    [Page 45]\r\f\rRFC 1035        Domain Implementation and Specification    November 1987\r\r\r   - If a resolver gets a server error or other bizarre response\r     from a name server, it should remove it from SLIST, and may\r     wish to schedule an immediate transmission to the next\r     candidate server address.\r\r7.3. Processing responses\r\rThe first step in processing arriving response datagrams is to parse the\rresponse.  This procedure should include:\r\r   - Check the header for reasonableness.  Discard datagrams which\r     are queries when responses are expected.\r\r   - Parse the sections of the message, and insure that all RRs are\r     correctly formatted.\r\r   - As an optional step, check the TTLs of arriving data looking\r     for RRs with excessively long TTLs.  If a RR has an\r     excessively long TTL, say greater than 1 week, either discard\r     the whole response, or limit all TTLs in the response to 1\r     week.\r\rThe next step is to match the response to a current resolver request.\rThe recommended strategy is to do a preliminary matching using the ID\rfield in the domain header, and then to verify that the question section\rcorresponds to the information currently desired.  This requires that\rthe transmission algorithm devote several bits of the domain ID field to\ra request identifier of some sort.  This step has several fine points:\r\r   - Some name servers send their responses from different\r     addresses than the one used to receive the query.  That is, a\r     resolver cannot rely that a response will come from the same\r     address which it sent the corresponding query to.  This name\r     server bug is typically encountered in UNIX systems.\r\r   - If the resolver retransmits a particular request to a name\r     server it should be able to use a response from any of the\r     transmissions.  However, if it is using the response to sample\r     the round trip time to access the name server, it must be able\r     to determine which transmission matches the response (and keep\r     transmission times for each outgoing message), or only\r     calculate round trip times based on initial transmissions.\r\r   - A name server will occasionally not have a current copy of a\r     zone which it should have according to some NS RRs.  The\r     resolver should simply remove the name server from the current\r     SLIST, and continue.\r\r\r\r\rMockapetris                                                    [Page 46]\r\f\rRFC 1035        Domain Implementation and Specification    November 1987\r\r\r7.4. Using the cache\r\rIn general, we expect a resolver to cache all data which it receives in\rresponses since it may be useful in answering future client requests.\rHowever, there are several types of data which should not be cached:\r\r   - When several RRs of the same type are available for a\r     particular owner name, the resolver should either cache them\r     all or none at all.  When a response is truncated, and a\r     resolver doesn't know whether it has a complete set, it should\r     not cache a possibly partial set of RRs.\r\r   - Cached data should never be used in preference to\r     authoritative data, so if caching would cause this to happen\r     the data should not be cached.\r\r   - The results of an inverse query should not be cached.\r\r   - The results of standard queries where the QNAME contains "*"\r     labels if the data might be used to construct wildcards.  The\r     reason is that the cache does not necessarily contain existing\r     RRs or zone boundary information which is necessary to\r     restrict the application of the wildcard RRs.\r\r   - RR data in responses of dubious reliability.  When a resolver\r     receives unsolicited responses or RR data other than that\r     requested, it should discard it without caching it.  The basic\r     implication is that all sanity checks on a packet should be\r     performed before any of it is cached.\r\rIn a similar vein, when a resolver has a set of RRs for some name in a\rresponse, and wants to cache the RRs, it should check its cache for\ralready existing RRs.  Depending on the circumstances, either the data\rin the response or the cache is preferred, but the two should never be\rcombined.  If the data in the response is from authoritative data in the\ranswer section, it is always preferred.\r\r8. MAIL SUPPORT\r\rThe domain system defines a standard for mapping mailboxes into domain\rnames, and two methods for using the mailbox information to derive mail\rrouting information.  The first method is called mail exchange binding\rand the other method is mailbox binding.  The mailbox encoding standard\rand mail exchange binding are part of the DNS official protocol, and are\rthe recommended method for mail routing in the Internet.  Mailbox\rbinding is an experimental feature which is still under development and\rsubject to change.\r\r\r\r\rMockapetris                                                    [Page 47]\r\f\rRFC 1035        Domain Implementation and Specification    November 1987\r\r\rThe mailbox encoding standard assumes a mailbox name of the form\r"<local-part>@<mail-domain>".  While the syntax allowed in each of these\rsections varies substantially between the various mail internets, the\rpreferred syntax for the ARPA Internet is given in [RFC-822].\r\rThe DNS encodes the <local-part> as a single label, and encodes the\r<mail-domain> as a domain name.  The single label from the <local-part>\ris prefaced to the domain name from <mail-domain> to form the domain\rname corresponding to the mailbox.  Thus the mailbox HOSTMASTER@SRI-\rNIC.ARPA is mapped into the domain name HOSTMASTER.SRI-NIC.ARPA.  If the\r<local-part> contains dots or other special characters, its\rrepresentation in a master file will require the use of backslash\rquoting to ensure that the domain name is properly encoded.  For\rexample, the mailbox Action.domains@ISI.EDU would be represented as\rAction\.domains.ISI.EDU.\r\r8.1. Mail exchange binding\r\rMail exchange binding uses the <mail-domain> part of a mailbox\rspecification to determine where mail should be sent.  The <local-part>\ris not even consulted.  [RFC-974] specifies this method in detail, and\rshould be consulted before attempting to use mail exchange support.\r\rOne of the advantages of this method is that it decouples mail\rdestination naming from the hosts used to support mail service, at the\rcost of another layer of indirection in the lookup function.  However,\rthe addition layer should eliminate the need for complicated "%", "!",\retc encodings in <local-part>.\r\rThe essence of the method is that the <mail-domain> is used as a domain\rname to locate type MX RRs which list hosts willing to accept mail for\r<mail-domain>, together with preference values which rank the hosts\raccording to an order specified by the administrators for <mail-domain>.\r\rIn this memo, the <mail-domain> ISI.EDU is used in examples, together\rwith the hosts VENERA.ISI.EDU and VAXA.ISI.EDU as mail exchanges for\rISI.EDU.  If a mailer had a message for Mockapetris@ISI.EDU, it would\rroute it by looking up MX RRs for ISI.EDU.  The MX RRs at ISI.EDU name\rVENERA.ISI.EDU and VAXA.ISI.EDU, and type A queries can find the host\raddresses.\r\r8.2. Mailbox binding (Experimental)\r\rIn mailbox binding, the mailer uses the entire mail destination\rspecification to construct a domain name.  The encoded domain name for\rthe mailbox is used as the QNAME field in a QTYPE=MAILB query.\r\rSeveral outcomes are possible for this query:\r\r\r\rMockapetris                                                    [Page 48]\r\f\rRFC 1035        Domain Implementation and Specification    November 1987\r\r\r   1. The query can return a name error indicating that the mailbox\r      does not exist as a domain name.\r\r      In the long term, this would indicate that the specified\r      mailbox doesn't exist.  However, until the use of mailbox\r      binding is universal, this error condition should be\r      interpreted to mean that the organization identified by the\r      global part does not support mailbox binding.  The\r      appropriate procedure is to revert to exchange binding at\r      this point.\r\r   2. The query can return a Mail Rename (MR) RR.\r\r      The MR RR carries new mailbox specification in its RDATA\r      field.  The mailer should replace the old mailbox with the\r      new one and retry the operation.\r\r   3. The query can return a MB RR.\r\r      The MB RR carries a domain name for a host in its RDATA\r      field.  The mailer should deliver the message to that host\r      via whatever protocol is applicable, e.g., b,SMTP.\r\r   4. The query can return one or more Mail Group (MG) RRs.\r\r      This condition means that the mailbox was actually a mailing\r      list or mail group, rather than a single mailbox.  Each MG RR\r      has a RDATA field that identifies a mailbox that is a member\r      of the group.  The mailer should deliver a copy of the\r      message to each member.\r\r   5. The query can return a MB RR as well as one or more MG RRs.\r\r      This condition means the the mailbox was actually a mailing\r      list.  The mailer can either deliver the message to the host\r      specified by the MB RR, which will in turn do the delivery to\r      all members, or the mailer can use the MG RRs to do the\r      expansion itself.\r\rIn any of these cases, the response may include a Mail Information\r(MINFO) RR.  This RR is usually associated with a mail group, but is\rlegal with a MB.  The MINFO RR identifies two mailboxes.  One of these\ridentifies a responsible person for the original mailbox name.  This\rmailbox should be used for requests to be added to a mail group, etc.\rThe second mailbox name in the MINFO RR identifies a mailbox that should\rreceive error messages for mail failures.  This is particularly\rappropriate for mailing lists when errors in member names should be\rreported to a person other than the one who sends a message to the list.\r\r\r\rMockapetris                                                    [Page 49]\r\f\rRFC 1035        Domain Implementation and Specification    November 1987\r\r\rNew fields may be added to this RR in the future.\r\r\r9. REFERENCES and BIBLIOGRAPHY\r\r[Dyer 87]       S. Dyer, F. Hsu, "Hesiod", Project Athena\r                Technical Plan - Name Service, April 1987, version 1.9.\r\r                Describes the fundamentals of the Hesiod name service.\r\r[IEN-116]       J. Postel, "Internet Name Server", IEN-116,\r                USC/Information Sciences Institute, August 1979.\r\r                A name service obsoleted by the Domain Name System, but\r                still in use.\r\r[Quarterman 86] J. Quarterman, and J. Hoskins, "Notable Computer Networks",\r                Communications of the ACM, October 1986, volume 29, number\r                10.\r\r[RFC-742]       K. Harrenstien, "NAME/FINGER", RFC-742, Network\r                Information Center, SRI International, December 1977.\r\r[RFC-768]       J. Postel, "User Datagram Protocol", RFC-768,\r                USC/Information Sciences Institute, August 1980.\r\r[RFC-793]       J. Postel, "Transmission Control Protocol", RFC-793,\r                USC/Information Sciences Institute, September 1981.\r\r[RFC-799]       D. Mills, "Internet Name Domains", RFC-799, COMSAT,\r                September 1981.\r\r                Suggests introduction of a hierarchy in place of a flat\r                name space for the Internet.\r\r[RFC-805]       J. Postel, "Computer Mail Meeting Notes", RFC-805,\r                USC/Information Sciences Institute, February 1982.\r\r[RFC-810]       E. Feinler, K. Harrenstien, Z. Su, and V. White, "DOD\r                Internet Host Table Specification", RFC-810, Network\r                Information Center, SRI International, March 1982.\r\r                Obsolete.  See RFC-952.\r\r[RFC-811]       K. Harrenstien, V. White, and E. Feinler, "Hostnames\r                Server", RFC-811, Network Information Center, SRI\r                International, March 1982.\r\r\r\r\rMockapetris                                                    [Page 50]\r\f\rRFC 1035        Domain Implementation and Specification    November 1987\r\r\r                Obsolete.  See RFC-953.\r\r[RFC-812]       K. Harrenstien, and V. White, "NICNAME/WHOIS", RFC-812,\r                Network Information Center, SRI International, March\r                1982.\r\r[RFC-819]       Z. Su, and J. Postel, "The Domain Naming Convention for\r                Internet User Applications", RFC-819, Network\r                Information Center, SRI International, August 1982.\r\r                Early thoughts on the design of the domain system.\r                Current implementation is completely different.\r\r[RFC-821]       J. Postel, "Simple Mail Transfer Protocol", RFC-821,\r                USC/Information Sciences Institute, August 1980.\r\r[RFC-830]       Z. Su, "A Distributed System for Internet Name Service",\r                RFC-830, Network Information Center, SRI International,\r                October 1982.\r\r                Early thoughts on the design of the domain system.\r                Current implementation is completely different.\r\r[RFC-882]       P. Mockapetris, "Domain names - Concepts and\r                Facilities," RFC-882, USC/Information Sciences\r                Institute, November 1983.\r\r                Superceeded by this memo.\r\r[RFC-883]       P. Mockapetris, "Domain names - Implementation and\r                Specification," RFC-883, USC/Information Sciences\r                Institute, November 1983.\r\r                Superceeded by this memo.\r\r[RFC-920]       J. Postel and J. Reynolds, "Domain Requirements",\r                RFC-920, USC/Information Sciences Institute,\r                October 1984.\r\r                Explains the naming scheme for top level domains.\r\r[RFC-952]       K. Harrenstien, M. Stahl, E. Feinler, "DoD Internet Host\r                Table Specification", RFC-952, SRI, October 1985.\r\r                Specifies the format of HOSTS.TXT, the host/address\r                table replaced by the DNS.\r\r\r\r\r\rMockapetris                                                    [Page 51]\r\f\rRFC 1035        Domain Implementation and Specification    November 1987\r\r\r[RFC-953]       K. Harrenstien, M. Stahl, E. Feinler, "HOSTNAME Server",\r                RFC-953, SRI, October 1985.\r\r                This RFC contains the official specification of the\r                hostname server protocol, which is obsoleted by the DNS.\r                This TCP based protocol accesses information stored in\r                the RFC-952 format, and is used to obtain copies of the\r                host table.\r\r[RFC-973]       P. Mockapetris, "Domain System Changes and\r                Observations", RFC-973, USC/Information Sciences\r                Institute, January 1986.\r\r                Describes changes to RFC-882 and RFC-883 and reasons for\r                them.\r\r[RFC-974]       C. Partridge, "Mail routing and the domain system",\r                RFC-974, CSNET CIC BBN Labs, January 1986.\r\r                Describes the transition from HOSTS.TXT based mail\r                addressing to the more powerful MX system used with the\r                domain system.\r\r[RFC-1001]      NetBIOS Working Group, "Protocol standard for a NetBIOS\r                service on a TCP/UDP transport: Concepts and Methods",\r                RFC-1001, March 1987.\r\r                This RFC and RFC-1002 are a preliminary design for\r                NETBIOS on top of TCP/IP which proposes to base NetBIOS\r                name service on top of the DNS.\r\r[RFC-1002]      NetBIOS Working Group, "Protocol standard for a NetBIOS\r                service on a TCP/UDP transport: Detailed\r                Specifications", RFC-1002, March 1987.\r\r[RFC-1010]      J. Reynolds, and J. Postel, "Assigned Numbers", RFC-1010,\r                USC/Information Sciences Institute, May 1987.\r\r                Contains socket numbers and mnemonics for host names,\r                operating systems, etc.\r\r[RFC-1031]      W. Lazear, "MILNET Name Domain Transition", RFC-1031,\r                November 1987.\r\r                Describes a plan for converting the MILNET to the DNS.\r\r[RFC-1032]      M. Stahl, "Establishing a Domain - Guidelines for\r                Administrators", RFC-1032, November 1987.\r\r\r\rMockapetris                                                    [Page 52]\r\f\rRFC 1035        Domain Implementation and Specification    November 1987\r\r\r                Describes the registration policies used by the NIC to\r                administer the top level domains and delegate subzones.\r\r[RFC-1033]      M. Lottor, "Domain Administrators Operations Guide",\r                RFC-1033, November 1987.\r\r                A cookbook for domain administrators.\r\r[Solomon 82]    M. Solomon, L. Landweber, and D. Neuhengen, "The CSNET\r                Name Server", Computer Networks, vol 6, nr 3, July 1982.\r\r                Describes a name service for CSNET which is independent\r                from the DNS and DNS use in the CSNET.\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\rMockapetris                                                    [Page 53]\r\f\rRFC 1035        Domain Implementation and Specification    November 1987\r\r\rIndex\r\r          *   13\r\r          ;   33, 35\r\r          <character-string>   35\r          <domain-name>   34\r\r          @   35\r\r          \   35\r\r          A   12\r\r          Byte order   8\r\r          CH   13\r          Character case   9\r          CLASS   11\r          CNAME   12\r          Completion   42\r          CS   13\r\r          Hesiod   13\r          HINFO   12\r          HS   13\r\r          IN   13\r          IN-ADDR.ARPA domain   22\r          Inverse queries   40\r\r          Mailbox names   47\r          MB   12\r          MD   12\r          MF   12\r          MG   12\r          MINFO   12\r          MINIMUM   20\r          MR   12\r          MX   12\r\r          NS   12\r          NULL   12\r\r          Port numbers   32\r          Primary server   5\r          PTR   12, 18\r\r\r\rMockapetris                                                    [Page 54]\r\f\rRFC 1035        Domain Implementation and Specification    November 1987\r\r\r          QCLASS   13\r          QTYPE   12\r\r          RDATA   12\r          RDLENGTH  11\r\r          Secondary server   5\r          SOA   12\r          Stub resolvers   7\r\r          TCP   32\r          TXT   12\r          TYPE   11\r\r          UDP   32\r\r          WKS   12\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\rMockapetris                                                    [Page 55]\r\f\r
\ No newline at end of file
+Network Working Group                                     P. Mockapetris
+Request for Comments: 1035                                           ISI
+                                                           November 1987
+Obsoletes: RFCs 882, 883, 973
+
+            DOMAIN NAMES - IMPLEMENTATION AND SPECIFICATION
+
+
+1. STATUS OF THIS MEMO
+
+This RFC describes the details of the domain system and protocol, and
+assumes that the reader is familiar with the concepts discussed in a
+companion RFC, "Domain Names - Concepts and Facilities" [RFC-1034].
+
+The domain system is a mixture of functions and data types which are an
+official protocol and functions and data types which are still
+experimental.  Since the domain system is intentionally extensible, new
+data types and experimental behavior should always be expected in parts
+of the system beyond the official protocol.  The official protocol parts
+include standard queries, responses and the Internet class RR data
+formats (e.g., host addresses).  Since the previous RFC set, several
+definitions have changed, so some previous definitions are obsolete.
+
+Experimental or obsolete features are clearly marked in these RFCs, and
+such information should be used with caution.
+
+The reader is especially cautioned not to depend on the values which
+appear in examples to be current or complete, since their purpose is
+primarily pedagogical.  Distribution of this memo is unlimited.
+
+                           Table of Contents
+
+  1. STATUS OF THIS MEMO                                              1
+  2. INTRODUCTION                                                     3
+      2.1. Overview                                                   3
+      2.2. Common configurations                                      4
+      2.3. Conventions                                                7
+          2.3.1. Preferred name syntax                                7
+          2.3.2. Data Transmission Order                              8
+          2.3.3. Character Case                                       9
+          2.3.4. Size limits                                         10
+  3. DOMAIN NAME SPACE AND RR DEFINITIONS                            10
+      3.1. Name space definitions                                    10
+      3.2. RR definitions                                            11
+          3.2.1. Format                                              11
+          3.2.2. TYPE values                                         12
+          3.2.3. QTYPE values                                        12
+          3.2.4. CLASS values                                        13
+
+
+
+Mockapetris                                                     [Page 1]
+\f
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+          3.2.5. QCLASS values                                       13
+      3.3. Standard RRs                                              13
+          3.3.1. CNAME RDATA format                                  14
+          3.3.2. HINFO RDATA format                                  14
+          3.3.3. MB RDATA format (EXPERIMENTAL)                      14
+          3.3.4. MD RDATA format (Obsolete)                          15
+          3.3.5. MF RDATA format (Obsolete)                          15
+          3.3.6. MG RDATA format (EXPERIMENTAL)                      16
+          3.3.7. MINFO RDATA format (EXPERIMENTAL)                   16
+          3.3.8. MR RDATA format (EXPERIMENTAL)                      17
+          3.3.9. MX RDATA format                                     17
+          3.3.10. NULL RDATA format (EXPERIMENTAL)                   17
+          3.3.11. NS RDATA format                                    18
+          3.3.12. PTR RDATA format                                   18
+          3.3.13. SOA RDATA format                                   19
+          3.3.14. TXT RDATA format                                   20
+      3.4. ARPA Internet specific RRs                                20
+          3.4.1. A RDATA format                                      20
+          3.4.2. WKS RDATA format                                    21
+      3.5. IN-ADDR.ARPA domain                                       22
+      3.6. Defining new types, classes, and special namespaces       24
+  4. MESSAGES                                                        25
+      4.1. Format                                                    25
+          4.1.1. Header section format                               26
+          4.1.2. Question section format                             28
+          4.1.3. Resource record format                              29
+          4.1.4. Message compression                                 30
+      4.2. Transport                                                 32
+          4.2.1. UDP usage                                           32
+          4.2.2. TCP usage                                           32
+  5. MASTER FILES                                                    33
+      5.1. Format                                                    33
+      5.2. Use of master files to define zones                       35
+      5.3. Master file example                                       36
+  6. NAME SERVER IMPLEMENTATION                                      37
+      6.1. Architecture                                              37
+          6.1.1. Control                                             37
+          6.1.2. Database                                            37
+          6.1.3. Time                                                39
+      6.2. Standard query processing                                 39
+      6.3. Zone refresh and reload processing                        39
+      6.4. Inverse queries (Optional)                                40
+          6.4.1. The contents of inverse queries and responses       40
+          6.4.2. Inverse query and response example                  41
+          6.4.3. Inverse query processing                            42
+
+
+
+
+
+
+Mockapetris                                                     [Page 2]
+\f
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+      6.5. Completion queries and responses                          42
+  7. RESOLVER IMPLEMENTATION                                         43
+      7.1. Transforming a user request into a query                  43
+      7.2. Sending the queries                                       44
+      7.3. Processing responses                                      46
+      7.4. Using the cache                                           47
+  8. MAIL SUPPORT                                                    47
+      8.1. Mail exchange binding                                     48
+      8.2. Mailbox binding (Experimental)                            48
+  9. REFERENCES and BIBLIOGRAPHY                                     50
+  Index                                                              54
+
+2. INTRODUCTION
+
+2.1. Overview
+
+The goal of domain names is to provide a mechanism for naming resources
+in such a way that the names are usable in different hosts, networks,
+protocol families, internets, and administrative organizations.
+
+From the user's point of view, domain names are useful as arguments to a
+local agent, called a resolver, which retrieves information associated
+with the domain name.  Thus a user might ask for the host address or
+mail information associated with a particular domain name.  To enable
+the user to request a particular type of information, an appropriate
+query type is passed to the resolver with the domain name.  To the user,
+the domain tree is a single information space; the resolver is
+responsible for hiding the distribution of data among name servers from
+the user.
+
+From the resolver's point of view, the database that makes up the domain
+space is distributed among various name servers.  Different parts of the
+domain space are stored in different name servers, although a particular
+data item will be stored redundantly in two or more name servers.  The
+resolver starts with knowledge of at least one name server.  When the
+resolver processes a user query it asks a known name server for the
+information; in return, the resolver either receives the desired
+information or a referral to another name server.  Using these
+referrals, resolvers learn the identities and contents of other name
+servers.  Resolvers are responsible for dealing with the distribution of
+the domain space and dealing with the effects of name server failure by
+consulting redundant databases in other servers.
+
+Name servers manage two kinds of data.  The first kind of data held in
+sets called zones; each zone is the complete database for a particular
+"pruned" subtree of the domain space.  This data is called
+authoritative.  A name server periodically checks to make sure that its
+zones are up to date, and if not, obtains a new copy of updated zones
+
+
+
+Mockapetris                                                     [Page 3]
+\f
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+from master files stored locally or in another name server.  The second
+kind of data is cached data which was acquired by a local resolver.
+This data may be incomplete, but improves the performance of the
+retrieval process when non-local data is repeatedly accessed.  Cached
+data is eventually discarded by a timeout mechanism.
+
+This functional structure isolates the problems of user interface,
+failure recovery, and distribution in the resolvers and isolates the
+database update and refresh problems in the name servers.
+
+2.2. Common configurations
+
+A host can participate in the domain name system in a number of ways,
+depending on whether the host runs programs that retrieve information
+from the domain system, name servers that answer queries from other
+hosts, or various combinations of both functions.  The simplest, and
+perhaps most typical, configuration is shown below:
+
+                 Local Host                        |  Foreign
+                                                   |
+    +---------+               +----------+         |  +--------+
+    |         | user queries  |          |queries  |  |        |
+    |  User   |-------------->|          |---------|->|Foreign |
+    | Program |               | Resolver |         |  |  Name  |
+    |         |<--------------|          |<--------|--| Server |
+    |         | user responses|          |responses|  |        |
+    +---------+               +----------+         |  +--------+
+                                |     A            |
+                cache additions |     | references |
+                                V     |            |
+                              +----------+         |
+                              |  cache   |         |
+                              +----------+         |
+
+User programs interact with the domain name space through resolvers; the
+format of user queries and user responses is specific to the host and
+its operating system.  User queries will typically be operating system
+calls, and the resolver and its cache will be part of the host operating
+system.  Less capable hosts may choose to implement the resolver as a
+subroutine to be linked in with every program that needs its services.
+Resolvers answer user queries with information they acquire via queries
+to foreign name servers and the local cache.
+
+Note that the resolver may have to make several queries to several
+different foreign name servers to answer a particular user query, and
+hence the resolution of a user query may involve several network
+accesses and an arbitrary amount of time.  The queries to foreign name
+servers and the corresponding responses have a standard format described
+
+
+
+Mockapetris                                                     [Page 4]
+\f
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+in this memo, and may be datagrams.
+
+Depending on its capabilities, a name server could be a stand alone
+program on a dedicated machine or a process or processes on a large
+timeshared host.  A simple configuration might be:
+
+                 Local Host                        |  Foreign
+                                                   |
+      +---------+                                  |
+     /         /|                                  |
+    +---------+ |             +----------+         |  +--------+
+    |         | |             |          |responses|  |        |
+    |         | |             |   Name   |---------|->|Foreign |
+    |  Master |-------------->|  Server  |         |  |Resolver|
+    |  files  | |             |          |<--------|--|        |
+    |         |/              |          | queries |  +--------+
+    +---------+               +----------+         |
+
+Here a primary name server acquires information about one or more zones
+by reading master files from its local file system, and answers queries
+about those zones that arrive from foreign resolvers.
+
+The DNS requires that all zones be redundantly supported by more than
+one name server.  Designated secondary servers can acquire zones and
+check for updates from the primary server using the zone transfer
+protocol of the DNS.  This configuration is shown below:
+
+                 Local Host                        |  Foreign
+                                                   |
+      +---------+                                  |
+     /         /|                                  |
+    +---------+ |             +----------+         |  +--------+
+    |         | |             |          |responses|  |        |
+    |         | |             |   Name   |---------|->|Foreign |
+    |  Master |-------------->|  Server  |         |  |Resolver|
+    |  files  | |             |          |<--------|--|        |
+    |         |/              |          | queries |  +--------+
+    +---------+               +----------+         |
+                                A     |maintenance |  +--------+
+                                |     +------------|->|        |
+                                |      queries     |  |Foreign |
+                                |                  |  |  Name  |
+                                +------------------|--| Server |
+                             maintenance responses |  +--------+
+
+In this configuration, the name server periodically establishes a
+virtual circuit to a foreign name server to acquire a copy of a zone or
+to check that an existing copy has not changed.  The messages sent for
+
+
+
+Mockapetris                                                     [Page 5]
+\f
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+these maintenance activities follow the same form as queries and
+responses, but the message sequences are somewhat different.
+
+The information flow in a host that supports all aspects of the domain
+name system is shown below:
+
+                 Local Host                        |  Foreign
+                                                   |
+    +---------+               +----------+         |  +--------+
+    |         | user queries  |          |queries  |  |        |
+    |  User   |-------------->|          |---------|->|Foreign |
+    | Program |               | Resolver |         |  |  Name  |
+    |         |<--------------|          |<--------|--| Server |
+    |         | user responses|          |responses|  |        |
+    +---------+               +----------+         |  +--------+
+                                |     A            |
+                cache additions |     | references |
+                                V     |            |
+                              +----------+         |
+                              |  Shared  |         |
+                              | database |         |
+                              +----------+         |
+                                A     |            |
+      +---------+     refreshes |     | references |
+     /         /|               |     V            |
+    +---------+ |             +----------+         |  +--------+
+    |         | |             |          |responses|  |        |
+    |         | |             |   Name   |---------|->|Foreign |
+    |  Master |-------------->|  Server  |         |  |Resolver|
+    |  files  | |             |          |<--------|--|        |
+    |         |/              |          | queries |  +--------+
+    +---------+               +----------+         |
+                                A     |maintenance |  +--------+
+                                |     +------------|->|        |
+                                |      queries     |  |Foreign |
+                                |                  |  |  Name  |
+                                +------------------|--| Server |
+                             maintenance responses |  +--------+
+
+The shared database holds domain space data for the local name server
+and resolver.  The contents of the shared database will typically be a
+mixture of authoritative data maintained by the periodic refresh
+operations of the name server and cached data from previous resolver
+requests.  The structure of the domain data and the necessity for
+synchronization between name servers and resolvers imply the general
+characteristics of this database, but the actual format is up to the
+local implementor.
+
+
+
+
+Mockapetris                                                     [Page 6]
+\f
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+Information flow can also be tailored so that a group of hosts act
+together to optimize activities.  Sometimes this is done to offload less
+capable hosts so that they do not have to implement a full resolver.
+This can be appropriate for PCs or hosts which want to minimize the
+amount of new network code which is required.  This scheme can also
+allow a group of hosts can share a small number of caches rather than
+maintaining a large number of separate caches, on the premise that the
+centralized caches will have a higher hit ratio.  In either case,
+resolvers are replaced with stub resolvers which act as front ends to
+resolvers located in a recursive server in one or more name servers
+known to perform that service:
+
+                   Local Hosts                     |  Foreign
+                                                   |
+    +---------+                                    |
+    |         | responses                          |
+    | Stub    |<--------------------+              |
+    | Resolver|                     |              |
+    |         |----------------+    |              |
+    +---------+ recursive      |    |              |
+                queries        |    |              |
+                               V    |              |
+    +---------+ recursive     +----------+         |  +--------+
+    |         | queries       |          |queries  |  |        |
+    | Stub    |-------------->| Recursive|---------|->|Foreign |
+    | Resolver|               | Server   |         |  |  Name  |
+    |         |<--------------|          |<--------|--| Server |
+    +---------+ responses     |          |responses|  |        |
+                              +----------+         |  +--------+
+                              |  Central |         |
+                              |   cache  |         |
+                              +----------+         |
+
+In any case, note that domain components are always replicated for
+reliability whenever possible.
+
+2.3. Conventions
+
+The domain system has several conventions dealing with low-level, but
+fundamental, issues.  While the implementor is free to violate these
+conventions WITHIN HIS OWN SYSTEM, he must observe these conventions in
+ALL behavior observed from other hosts.
+
+2.3.1. Preferred name syntax
+
+The DNS specifications attempt to be as general as possible in the rules
+for constructing domain names.  The idea is that the name of any
+existing object can be expressed as a domain name with minimal changes.
+
+
+
+Mockapetris                                                     [Page 7]
+\f
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+However, when assigning a domain name for an object, the prudent user
+will select a name which satisfies both the rules of the domain system
+and any existing rules for the object, whether these rules are published
+or implied by existing programs.
+
+For example, when naming a mail domain, the user should satisfy both the
+rules of this memo and those in RFC-822.  When creating a new host name,
+the old rules for HOSTS.TXT should be followed.  This avoids problems
+when old software is converted to use domain names.
+
+The following syntax will result in fewer problems with many
+
+applications that use domain names (e.g., mail, TELNET).
+
+<domain> ::= <subdomain> | " "
+
+<subdomain> ::= <label> | <subdomain> "." <label>
+
+<label> ::= <letter> [ [ <ldh-str> ] <let-dig> ]
+
+<ldh-str> ::= <let-dig-hyp> | <let-dig-hyp> <ldh-str>
+
+<let-dig-hyp> ::= <let-dig> | "-"
+
+<let-dig> ::= <letter> | <digit>
+
+<letter> ::= any one of the 52 alphabetic characters A through Z in
+upper case and a through z in lower case
+
+<digit> ::= any one of the ten digits 0 through 9
+
+Note that while upper and lower case letters are allowed in domain
+names, no significance is attached to the case.  That is, two names with
+the same spelling but different case are to be treated as if identical.
+
+The labels must follow the rules for ARPANET host names.  They must
+start with a letter, end with a letter or digit, and have as interior
+characters only letters, digits, and hyphen.  There are also some
+restrictions on the length.  Labels must be 63 characters or less.
+
+For example, the following strings identify hosts in the Internet:
+
+A.ISI.EDU XX.LCS.MIT.EDU SRI-NIC.ARPA
+
+2.3.2. Data Transmission Order
+
+The order of transmission of the header and data described in this
+document is resolved to the octet level.  Whenever a diagram shows a
+
+
+
+Mockapetris                                                     [Page 8]
+\f
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+group of octets, the order of transmission of those octets is the normal
+order in which they are read in English.  For example, in the following
+diagram, the octets are transmitted in the order they are numbered.
+
+     0                   1
+     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    |       1       |       2       |
+    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    |       3       |       4       |
+    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    |       5       |       6       |
+    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+Whenever an octet represents a numeric quantity, the left most bit in
+the diagram is the high order or most significant bit.  That is, the bit
+labeled 0 is the most significant bit.  For example, the following
+diagram represents the value 170 (decimal).
+
+     0 1 2 3 4 5 6 7
+    +-+-+-+-+-+-+-+-+
+    |1 0 1 0 1 0 1 0|
+    +-+-+-+-+-+-+-+-+
+
+Similarly, whenever a multi-octet field represents a numeric quantity
+the left most bit of the whole field is the most significant bit.  When
+a multi-octet quantity is transmitted the most significant octet is
+transmitted first.
+
+2.3.3. Character Case
+
+For all parts of the DNS that are part of the official protocol, all
+comparisons between character strings (e.g., labels, domain names, etc.)
+are done in a case-insensitive manner.  At present, this rule is in
+force throughout the domain system without exception.  However, future
+additions beyond current usage may need to use the full binary octet
+capabilities in names, so attempts to store domain names in 7-bit ASCII
+or use of special bytes to terminate labels, etc., should be avoided.
+
+When data enters the domain system, its original case should be
+preserved whenever possible.  In certain circumstances this cannot be
+done.  For example, if two RRs are stored in a database, one at x.y and
+one at X.Y, they are actually stored at the same place in the database,
+and hence only one casing would be preserved.  The basic rule is that
+case can be discarded only when data is used to define structure in a
+database, and two names are identical when compared in a case
+insensitive manner.
+
+
+
+
+Mockapetris                                                     [Page 9]
+\f
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+Loss of case sensitive data must be minimized.  Thus while data for x.y
+and X.Y may both be stored under a single location x.y or X.Y, data for
+a.x and B.X would never be stored under A.x, A.X, b.x, or b.X.  In
+general, this preserves the case of the first label of a domain name,
+but forces standardization of interior node labels.
+
+Systems administrators who enter data into the domain database should
+take care to represent the data they supply to the domain system in a
+case-consistent manner if their system is case-sensitive.  The data
+distribution system in the domain system will ensure that consistent
+representations are preserved.
+
+2.3.4. Size limits
+
+Various objects and parameters in the DNS have size limits.  They are
+listed below.  Some could be easily changed, others are more
+fundamental.
+
+labels          63 octets or less
+
+names           255 octets or less
+
+TTL             positive values of a signed 32 bit number.
+
+UDP messages    512 octets or less
+
+3. DOMAIN NAME SPACE AND RR DEFINITIONS
+
+3.1. Name space definitions
+
+Domain names in messages are expressed in terms of a sequence of labels.
+Each label is represented as a one octet length field followed by that
+number of octets.  Since every domain name ends with the null label of
+the root, a domain name is terminated by a length byte of zero.  The
+high order two bits of every length octet must be zero, and the
+remaining six bits of the length field limit the label to 63 octets or
+less.
+
+To simplify implementations, the total length of a domain name (i.e.,
+label octets and label length octets) is restricted to 255 octets or
+less.
+
+Although labels can contain any 8 bit values in octets that make up a
+label, it is strongly recommended that labels follow the preferred
+syntax described elsewhere in this memo, which is compatible with
+existing host naming conventions.  Name servers and resolvers must
+compare labels in a case-insensitive manner (i.e., A=a), assuming ASCII
+with zero parity.  Non-alphabetic codes must match exactly.
+
+
+
+Mockapetris                                                    [Page 10]
+\f
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+3.2. RR definitions
+
+3.2.1. Format
+
+All RRs have the same top level format shown below:
+
+                                    1  1  1  1  1  1
+      0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    |                                               |
+    /                                               /
+    /                      NAME                     /
+    |                                               |
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    |                      TYPE                     |
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    |                     CLASS                     |
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    |                      TTL                      |
+    |                                               |
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    |                   RDLENGTH                    |
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
+    /                     RDATA                     /
+    /                                               /
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+
+where:
+
+NAME            an owner name, i.e., the name of the node to which this
+                resource record pertains.
+
+TYPE            two octets containing one of the RR TYPE codes.
+
+CLASS           two octets containing one of the RR CLASS codes.
+
+TTL             a 32 bit signed integer that specifies the time interval
+                that the resource record may be cached before the source
+                of the information should again be consulted.  Zero
+                values are interpreted to mean that the RR can only be
+                used for the transaction in progress, and should not be
+                cached.  For example, SOA records are always distributed
+                with a zero TTL to prohibit caching.  Zero values can
+                also be used for extremely volatile data.
+
+RDLENGTH        an unsigned 16 bit integer that specifies the length in
+                octets of the RDATA field.
+
+
+
+Mockapetris                                                    [Page 11]
+\f
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+RDATA           a variable length string of octets that describes the
+                resource.  The format of this information varies
+                according to the TYPE and CLASS of the resource record.
+
+3.2.2. TYPE values
+
+TYPE fields are used in resource records.  Note that these types are a
+subset of QTYPEs.
+
+TYPE            value and meaning
+
+A               1 a host address
+
+NS              2 an authoritative name server
+
+MD              3 a mail destination (Obsolete - use MX)
+
+MF              4 a mail forwarder (Obsolete - use MX)
+
+CNAME           5 the canonical name for an alias
+
+SOA             6 marks the start of a zone of authority
+
+MB              7 a mailbox domain name (EXPERIMENTAL)
+
+MG              8 a mail group member (EXPERIMENTAL)
+
+MR              9 a mail rename domain name (EXPERIMENTAL)
+
+NULL            10 a null RR (EXPERIMENTAL)
+
+WKS             11 a well known service description
+
+PTR             12 a domain name pointer
+
+HINFO           13 host information
+
+MINFO           14 mailbox or mail list information
+
+MX              15 mail exchange
+
+TXT             16 text strings
+
+3.2.3. QTYPE values
+
+QTYPE fields appear in the question part of a query.  QTYPES are a
+superset of TYPEs, hence all TYPEs are valid QTYPEs.  In addition, the
+following QTYPEs are defined:
+
+
+
+Mockapetris                                                    [Page 12]
+\f
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+AXFR            252 A request for a transfer of an entire zone
+
+MAILB           253 A request for mailbox-related records (MB, MG or MR)
+
+MAILA           254 A request for mail agent RRs (Obsolete - see MX)
+
+*               255 A request for all records
+
+3.2.4. CLASS values
+
+CLASS fields appear in resource records.  The following CLASS mnemonics
+and values are defined:
+
+IN              1 the Internet
+
+CS              2 the CSNET class (Obsolete - used only for examples in
+                some obsolete RFCs)
+
+CH              3 the CHAOS class
+
+HS              4 Hesiod [Dyer 87]
+
+3.2.5. QCLASS values
+
+QCLASS fields appear in the question section of a query.  QCLASS values
+are a superset of CLASS values; every CLASS is a valid QCLASS.  In
+addition to CLASS values, the following QCLASSes are defined:
+
+*               255 any class
+
+3.3. Standard RRs
+
+The following RR definitions are expected to occur, at least
+potentially, in all classes.  In particular, NS, SOA, CNAME, and PTR
+will be used in all classes, and have the same format in all classes.
+Because their RDATA format is known, all domain names in the RDATA
+section of these RRs may be compressed.
+
+<domain-name> is a domain name represented as a series of labels, and
+terminated by a label with zero length.  <character-string> is a single
+length octet followed by that number of characters.  <character-string>
+is treated as binary information, and can be up to 256 characters in
+length (including the length octet).
+
+
+
+
+
+
+
+
+Mockapetris                                                    [Page 13]
+\f
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+3.3.1. CNAME RDATA format
+
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    /                     CNAME                     /
+    /                                               /
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+CNAME           A <domain-name> which specifies the canonical or primary
+                name for the owner.  The owner name is an alias.
+
+CNAME RRs cause no additional section processing, but name servers may
+choose to restart the query at the canonical name in certain cases.  See
+the description of name server logic in [RFC-1034] for details.
+
+3.3.2. HINFO RDATA format
+
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    /                      CPU                      /
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    /                       OS                      /
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+CPU             A <character-string> which specifies the CPU type.
+
+OS              A <character-string> which specifies the operating
+                system type.
+
+Standard values for CPU and OS can be found in [RFC-1010].
+
+HINFO records are used to acquire general information about a host.  The
+main use is for protocols such as FTP that can use special procedures
+when talking between machines or operating systems of the same type.
+
+3.3.3. MB RDATA format (EXPERIMENTAL)
+
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    /                   MADNAME                     /
+    /                                               /
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+MADNAME         A <domain-name> which specifies a host which has the
+                specified mailbox.
+
+
+
+Mockapetris                                                    [Page 14]
+\f
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+MB records cause additional section processing which looks up an A type
+RRs corresponding to MADNAME.
+
+3.3.4. MD RDATA format (Obsolete)
+
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    /                   MADNAME                     /
+    /                                               /
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+MADNAME         A <domain-name> which specifies a host which has a mail
+                agent for the domain which should be able to deliver
+                mail for the domain.
+
+MD records cause additional section processing which looks up an A type
+record corresponding to MADNAME.
+
+MD is obsolete.  See the definition of MX and [RFC-974] for details of
+the new scheme.  The recommended policy for dealing with MD RRs found in
+a master file is to reject them, or to convert them to MX RRs with a
+preference of 0.
+
+3.3.5. MF RDATA format (Obsolete)
+
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    /                   MADNAME                     /
+    /                                               /
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+MADNAME         A <domain-name> which specifies a host which has a mail
+                agent for the domain which will accept mail for
+                forwarding to the domain.
+
+MF records cause additional section processing which looks up an A type
+record corresponding to MADNAME.
+
+MF is obsolete.  See the definition of MX and [RFC-974] for details ofw
+the new scheme.  The recommended policy for dealing with MD RRs found in
+a master file is to reject them, or to convert them to MX RRs with a
+preference of 10.
+
+
+
+
+
+
+
+Mockapetris                                                    [Page 15]
+\f
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+3.3.6. MG RDATA format (EXPERIMENTAL)
+
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    /                   MGMNAME                     /
+    /                                               /
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+MGMNAME         A <domain-name> which specifies a mailbox which is a
+                member of the mail group specified by the domain name.
+
+MG records cause no additional section processing.
+
+3.3.7. MINFO RDATA format (EXPERIMENTAL)
+
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    /                    RMAILBX                    /
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    /                    EMAILBX                    /
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+RMAILBX         A <domain-name> which specifies a mailbox which is
+                responsible for the mailing list or mailbox.  If this
+                domain name names the root, the owner of the MINFO RR is
+                responsible for itself.  Note that many existing mailing
+                lists use a mailbox X-request for the RMAILBX field of
+                mailing list X, e.g., Msgroup-request for Msgroup.  This
+                field provides a more general mechanism.
+
+
+EMAILBX         A <domain-name> which specifies a mailbox which is to
+                receive error messages related to the mailing list or
+                mailbox specified by the owner of the MINFO RR (similar
+                to the ERRORS-TO: field which has been proposed).  If
+                this domain name names the root, errors should be
+                returned to the sender of the message.
+
+MINFO records cause no additional section processing.  Although these
+records can be associated with a simple mailbox, they are usually used
+with a mailing list.
+
+
+
+
+
+
+
+
+Mockapetris                                                    [Page 16]
+\f
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+3.3.8. MR RDATA format (EXPERIMENTAL)
+
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    /                   NEWNAME                     /
+    /                                               /
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+NEWNAME         A <domain-name> which specifies a mailbox which is the
+                proper rename of the specified mailbox.
+
+MR records cause no additional section processing.  The main use for MR
+is as a forwarding entry for a user who has moved to a different
+mailbox.
+
+3.3.9. MX RDATA format
+
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    |                  PREFERENCE                   |
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    /                   EXCHANGE                    /
+    /                                               /
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+PREFERENCE      A 16 bit integer which specifies the preference given to
+                this RR among others at the same owner.  Lower values
+                are preferred.
+
+EXCHANGE        A <domain-name> which specifies a host willing to act as
+                a mail exchange for the owner name.
+
+MX records cause type A additional section processing for the host
+specified by EXCHANGE.  The use of MX RRs is explained in detail in
+[RFC-974].
+
+3.3.10. NULL RDATA format (EXPERIMENTAL)
+
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    /                  <anything>                   /
+    /                                               /
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+Anything at all may be in the RDATA field so long as it is 65535 octets
+or less.
+
+
+
+
+Mockapetris                                                    [Page 17]
+\f
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+NULL records cause no additional section processing.  NULL RRs are not
+allowed in master files.  NULLs are used as placeholders in some
+experimental extensions of the DNS.
+
+3.3.11. NS RDATA format
+
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    /                   NSDNAME                     /
+    /                                               /
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+NSDNAME         A <domain-name> which specifies a host which should be
+                authoritative for the specified class and domain.
+
+NS records cause both the usual additional section processing to locate
+a type A record, and, when used in a referral, a special search of the
+zone in which they reside for glue information.
+
+The NS RR states that the named host should be expected to have a zone
+starting at owner name of the specified class.  Note that the class may
+not indicate the protocol family which should be used to communicate
+with the host, although it is typically a strong hint.  For example,
+hosts which are name servers for either Internet (IN) or Hesiod (HS)
+class information are normally queried using IN class protocols.
+
+3.3.12. PTR RDATA format
+
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    /                   PTRDNAME                    /
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+PTRDNAME        A <domain-name> which points to some location in the
+                domain name space.
+
+PTR records cause no additional section processing.  These RRs are used
+in special domains to point to some other location in the domain space.
+These records are simple data, and don't imply any special processing
+similar to that performed by CNAME, which identifies aliases.  See the
+description of the IN-ADDR.ARPA domain for an example.
+
+
+
+
+
+
+
+
+Mockapetris                                                    [Page 18]
+\f
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+3.3.13. SOA RDATA format
+
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    /                     MNAME                     /
+    /                                               /
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    /                     RNAME                     /
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    |                    SERIAL                     |
+    |                                               |
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    |                    REFRESH                    |
+    |                                               |
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    |                     RETRY                     |
+    |                                               |
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    |                    EXPIRE                     |
+    |                                               |
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    |                    MINIMUM                    |
+    |                                               |
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+MNAME           The <domain-name> of the name server that was the
+                original or primary source of data for this zone.
+
+RNAME           A <domain-name> which specifies the mailbox of the
+                person responsible for this zone.
+
+SERIAL          The unsigned 32 bit version number of the original copy
+                of the zone.  Zone transfers preserve this value.  This
+                value wraps and should be compared using sequence space
+                arithmetic.
+
+REFRESH         A 32 bit time interval before the zone should be
+                refreshed.
+
+RETRY           A 32 bit time interval that should elapse before a
+                failed refresh should be retried.
+
+EXPIRE          A 32 bit time value that specifies the upper limit on
+                the time interval that can elapse before the zone is no
+                longer authoritative.
+
+
+
+
+
+Mockapetris                                                    [Page 19]
+\f
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+MINIMUM         The unsigned 32 bit minimum TTL field that should be
+                exported with any RR from this zone.
+
+SOA records cause no additional section processing.
+
+All times are in units of seconds.
+
+Most of these fields are pertinent only for name server maintenance
+operations.  However, MINIMUM is used in all query operations that
+retrieve RRs from a zone.  Whenever a RR is sent in a response to a
+query, the TTL field is set to the maximum of the TTL field from the RR
+and the MINIMUM field in the appropriate SOA.  Thus MINIMUM is a lower
+bound on the TTL field for all RRs in a zone.  Note that this use of
+MINIMUM should occur when the RRs are copied into the response and not
+when the zone is loaded from a master file or via a zone transfer.  The
+reason for this provison is to allow future dynamic update facilities to
+change the SOA RR with known semantics.
+
+
+3.3.14. TXT RDATA format
+
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    /                   TXT-DATA                    /
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+TXT-DATA        One or more <character-string>s.
+
+TXT RRs are used to hold descriptive text.  The semantics of the text
+depends on the domain where it is found.
+
+3.4. Internet specific RRs
+
+3.4.1. A RDATA format
+
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    |                    ADDRESS                    |
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+ADDRESS         A 32 bit Internet address.
+
+Hosts that have multiple Internet addresses will have multiple A
+records.
+
+
+
+
+
+Mockapetris                                                    [Page 20]
+\f
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+A records cause no additional section processing.  The RDATA section of
+an A line in a master file is an Internet address expressed as four
+decimal numbers separated by dots without any imbedded spaces (e.g.,
+"10.2.0.52" or "192.0.5.6").
+
+3.4.2. WKS RDATA format
+
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    |                    ADDRESS                    |
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    |       PROTOCOL        |                       |
+    +--+--+--+--+--+--+--+--+                       |
+    |                                               |
+    /                   <BIT MAP>                   /
+    /                                               /
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+ADDRESS         An 32 bit Internet address
+
+PROTOCOL        An 8 bit IP protocol number
+
+<BIT MAP>       A variable length bit map.  The bit map must be a
+                multiple of 8 bits long.
+
+The WKS record is used to describe the well known services supported by
+a particular protocol on a particular internet address.  The PROTOCOL
+field specifies an IP protocol number, and the bit map has one bit per
+port of the specified protocol.  The first bit corresponds to port 0,
+the second to port 1, etc.  If the bit map does not include a bit for a
+protocol of interest, that bit is assumed zero.  The appropriate values
+and mnemonics for ports and protocols are specified in [RFC-1010].
+
+For example, if PROTOCOL=TCP (6), the 26th bit corresponds to TCP port
+25 (SMTP).  If this bit is set, a SMTP server should be listening on TCP
+port 25; if zero, SMTP service is not supported on the specified
+address.
+
+The purpose of WKS RRs is to provide availability information for
+servers for TCP and UDP.  If a server supports both TCP and UDP, or has
+multiple Internet addresses, then multiple WKS RRs are used.
+
+WKS RRs cause no additional section processing.
+
+In master files, both ports and protocols are expressed using mnemonics
+or decimal numbers.
+
+
+
+
+Mockapetris                                                    [Page 21]
+\f
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+3.5. IN-ADDR.ARPA domain
+
+The Internet uses a special domain to support gateway location and
+Internet address to host mapping.  Other classes may employ a similar
+strategy in other domains.  The intent of this domain is to provide a
+guaranteed method to perform host address to host name mapping, and to
+facilitate queries to locate all gateways on a particular network in the
+Internet.
+
+Note that both of these services are similar to functions that could be
+performed by inverse queries; the difference is that this part of the
+domain name space is structured according to address, and hence can
+guarantee that the appropriate data can be located without an exhaustive
+search of the domain space.
+
+The domain begins at IN-ADDR.ARPA and has a substructure which follows
+the Internet addressing structure.
+
+Domain names in the IN-ADDR.ARPA domain are defined to have up to four
+labels in addition to the IN-ADDR.ARPA suffix.  Each label represents
+one octet of an Internet address, and is expressed as a character string
+for a decimal value in the range 0-255 (with leading zeros omitted
+except in the case of a zero octet which is represented by a single
+zero).
+
+Host addresses are represented by domain names that have all four labels
+specified.  Thus data for Internet address 10.2.0.52 is located at
+domain name 52.0.2.10.IN-ADDR.ARPA.  The reversal, though awkward to
+read, allows zones to be delegated which are exactly one network of
+address space.  For example, 10.IN-ADDR.ARPA can be a zone containing
+data for the ARPANET, while 26.IN-ADDR.ARPA can be a separate zone for
+MILNET.  Address nodes are used to hold pointers to primary host names
+in the normal domain space.
+
+Network numbers correspond to some non-terminal nodes at various depths
+in the IN-ADDR.ARPA domain, since Internet network numbers are either 1,
+2, or 3 octets.  Network nodes are used to hold pointers to the primary
+host names of gateways attached to that network.  Since a gateway is, by
+definition, on more than one network, it will typically have two or more
+network nodes which point at it.  Gateways will also have host level
+pointers at their fully qualified addresses.
+
+Both the gateway pointers at network nodes and the normal host pointers
+at full address nodes use the PTR RR to point back to the primary domain
+names of the corresponding hosts.
+
+For example, the IN-ADDR.ARPA domain will contain information about the
+ISI gateway between net 10 and 26, an MIT gateway from net 10 to MIT's
+
+
+
+Mockapetris                                                    [Page 22]
+\f
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+net 18, and hosts A.ISI.EDU and MULTICS.MIT.EDU.  Assuming that ISI
+gateway has addresses 10.2.0.22 and 26.0.0.103, and a name MILNET-
+GW.ISI.EDU, and the MIT gateway has addresses 10.0.0.77 and 18.10.0.4
+and a name GW.LCS.MIT.EDU, the domain database would contain:
+
+    10.IN-ADDR.ARPA.           PTR MILNET-GW.ISI.EDU.
+    10.IN-ADDR.ARPA.           PTR GW.LCS.MIT.EDU.
+    18.IN-ADDR.ARPA.           PTR GW.LCS.MIT.EDU.
+    26.IN-ADDR.ARPA.           PTR MILNET-GW.ISI.EDU.
+    22.0.2.10.IN-ADDR.ARPA.    PTR MILNET-GW.ISI.EDU.
+    103.0.0.26.IN-ADDR.ARPA.   PTR MILNET-GW.ISI.EDU.
+    77.0.0.10.IN-ADDR.ARPA.    PTR GW.LCS.MIT.EDU.
+    4.0.10.18.IN-ADDR.ARPA.    PTR GW.LCS.MIT.EDU.
+    103.0.3.26.IN-ADDR.ARPA.   PTR A.ISI.EDU.
+    6.0.0.10.IN-ADDR.ARPA.     PTR MULTICS.MIT.EDU.
+
+Thus a program which wanted to locate gateways on net 10 would originate
+a query of the form QTYPE=PTR, QCLASS=IN, QNAME=10.IN-ADDR.ARPA.  It
+would receive two RRs in response:
+
+    10.IN-ADDR.ARPA.           PTR MILNET-GW.ISI.EDU.
+    10.IN-ADDR.ARPA.           PTR GW.LCS.MIT.EDU.
+
+The program could then originate QTYPE=A, QCLASS=IN queries for MILNET-
+GW.ISI.EDU. and GW.LCS.MIT.EDU. to discover the Internet addresses of
+these gateways.
+
+A resolver which wanted to find the host name corresponding to Internet
+host address 10.0.0.6 would pursue a query of the form QTYPE=PTR,
+QCLASS=IN, QNAME=6.0.0.10.IN-ADDR.ARPA, and would receive:
+
+    6.0.0.10.IN-ADDR.ARPA.     PTR MULTICS.MIT.EDU.
+
+Several cautions apply to the use of these services:
+   - Since the IN-ADDR.ARPA special domain and the normal domain
+     for a particular host or gateway will be in different zones,
+     the possibility exists that that the data may be inconsistent.
+
+   - Gateways will often have two names in separate domains, only
+     one of which can be primary.
+
+   - Systems that use the domain database to initialize their
+     routing tables must start with enough gateway information to
+     guarantee that they can access the appropriate name server.
+
+   - The gateway data only reflects the existence of a gateway in a
+     manner equivalent to the current HOSTS.TXT file.  It doesn't
+     replace the dynamic availability information from GGP or EGP.
+
+
+
+Mockapetris                                                    [Page 23]
+\f
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+3.6. Defining new types, classes, and special namespaces
+
+The previously defined types and classes are the ones in use as of the
+date of this memo.  New definitions should be expected.  This section
+makes some recommendations to designers considering additions to the
+existing facilities.  The mailing list NAMEDROPPERS@SRI-NIC.ARPA is the
+forum where general discussion of design issues takes place.
+
+In general, a new type is appropriate when new information is to be
+added to the database about an existing object, or we need new data
+formats for some totally new object.  Designers should attempt to define
+types and their RDATA formats that are generally applicable to all
+classes, and which avoid duplication of information.  New classes are
+appropriate when the DNS is to be used for a new protocol, etc which
+requires new class-specific data formats, or when a copy of the existing
+name space is desired, but a separate management domain is necessary.
+
+New types and classes need mnemonics for master files; the format of the
+master files requires that the mnemonics for type and class be disjoint.
+
+TYPE and CLASS values must be a proper subset of QTYPEs and QCLASSes
+respectively.
+
+The present system uses multiple RRs to represent multiple values of a
+type rather than storing multiple values in the RDATA section of a
+single RR.  This is less efficient for most applications, but does keep
+RRs shorter.  The multiple RRs assumption is incorporated in some
+experimental work on dynamic update methods.
+
+The present system attempts to minimize the duplication of data in the
+database in order to insure consistency.  Thus, in order to find the
+address of the host for a mail exchange, you map the mail domain name to
+a host name, then the host name to addresses, rather than a direct
+mapping to host address.  This approach is preferred because it avoids
+the opportunity for inconsistency.
+
+In defining a new type of data, multiple RR types should not be used to
+create an ordering between entries or express different formats for
+equivalent bindings, instead this information should be carried in the
+body of the RR and a single type used.  This policy avoids problems with
+caching multiple types and defining QTYPEs to match multiple types.
+
+For example, the original form of mail exchange binding used two RR
+types one to represent a "closer" exchange (MD) and one to represent a
+"less close" exchange (MF).  The difficulty is that the presence of one
+RR type in a cache doesn't convey any information about the other
+because the query which acquired the cached information might have used
+a QTYPE of MF, MD, or MAILA (which matched both).  The redesigned
+
+
+
+Mockapetris                                                    [Page 24]
+\f
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+service used a single type (MX) with a "preference" value in the RDATA
+section which can order different RRs.  However, if any MX RRs are found
+in the cache, then all should be there.
+
+4. MESSAGES
+
+4.1. Format
+
+All communications inside of the domain protocol are carried in a single
+format called a message.  The top level format of message is divided
+into 5 sections (some of which are empty in certain cases) shown below:
+
+    +---------------------+
+    |        Header       |
+    +---------------------+
+    |       Question      | the question for the name server
+    +---------------------+
+    |        Answer       | RRs answering the question
+    +---------------------+
+    |      Authority      | RRs pointing toward an authority
+    +---------------------+
+    |      Additional     | RRs holding additional information
+    +---------------------+
+
+The header section is always present.  The header includes fields that
+specify which of the remaining sections are present, and also specify
+whether the message is a query or a response, a standard query or some
+other opcode, etc.
+
+The names of the sections after the header are derived from their use in
+standard queries.  The question section contains fields that describe a
+question to a name server.  These fields are a query type (QTYPE), a
+query class (QCLASS), and a query domain name (QNAME).  The last three
+sections have the same format: a possibly empty list of concatenated
+resource records (RRs).  The answer section contains RRs that answer the
+question; the authority section contains RRs that point toward an
+authoritative name server; the additional records section contains RRs
+which relate to the query, but are not strictly answers for the
+question.
+
+
+
+
+
+
+
+
+
+
+
+
+Mockapetris                                                    [Page 25]
+\f
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+4.1.1. Header section format
+
+The header contains the following fields:
+
+                                    1  1  1  1  1  1
+      0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    |                      ID                       |
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    |QR|   Opcode  |AA|TC|RD|RA|   Z    |   RCODE   |
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    |                    QDCOUNT                    |
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    |                    ANCOUNT                    |
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    |                    NSCOUNT                    |
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    |                    ARCOUNT                    |
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+ID              A 16 bit identifier assigned by the program that
+                generates any kind of query.  This identifier is copied
+                the corresponding reply and can be used by the requester
+                to match up replies to outstanding queries.
+
+QR              A one bit field that specifies whether this message is a
+                query (0), or a response (1).
+
+OPCODE          A four bit field that specifies kind of query in this
+                message.  This value is set by the originator of a query
+                and copied into the response.  The values are:
+
+                0               a standard query (QUERY)
+
+                1               an inverse query (IQUERY)
+
+                2               a server status request (STATUS)
+
+                3-15            reserved for future use
+
+AA              Authoritative Answer - this bit is valid in responses,
+                and specifies that the responding name server is an
+                authority for the domain name in question section.
+
+                Note that the contents of the answer section may have
+                multiple owner names because of aliases.  The AA bit
+
+
+
+Mockapetris                                                    [Page 26]
+\f
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+                corresponds to the name which matches the query name, or
+                the first owner name in the answer section.
+
+TC              TrunCation - specifies that this message was truncated
+                due to length greater than that permitted on the
+                transmission channel.
+
+RD              Recursion Desired - this bit may be set in a query and
+                is copied into the response.  If RD is set, it directs
+                the name server to pursue the query recursively.
+                Recursive query support is optional.
+
+RA              Recursion Available - this be is set or cleared in a
+                response, and denotes whether recursive query support is
+                available in the name server.
+
+Z               Reserved for future use.  Must be zero in all queries
+                and responses.
+
+RCODE           Response code - this 4 bit field is set as part of
+                responses.  The values have the following
+                interpretation:
+
+                0               No error condition
+
+                1               Format error - The name server was
+                                unable to interpret the query.
+
+                2               Server failure - The name server was
+                                unable to process this query due to a
+                                problem with the name server.
+
+                3               Name Error - Meaningful only for
+                                responses from an authoritative name
+                                server, this code signifies that the
+                                domain name referenced in the query does
+                                not exist.
+
+                4               Not Implemented - The name server does
+                                not support the requested kind of query.
+
+                5               Refused - The name server refuses to
+                                perform the specified operation for
+                                policy reasons.  For example, a name
+                                server may not wish to provide the
+                                information to the particular requester,
+                                or a name server may not wish to perform
+                                a particular operation (e.g., zone
+
+
+
+Mockapetris                                                    [Page 27]
+\f
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+                                transfer) for particular data.
+
+                6-15            Reserved for future use.
+
+QDCOUNT         an unsigned 16 bit integer specifying the number of
+                entries in the question section.
+
+ANCOUNT         an unsigned 16 bit integer specifying the number of
+                resource records in the answer section.
+
+NSCOUNT         an unsigned 16 bit integer specifying the number of name
+                server resource records in the authority records
+                section.
+
+ARCOUNT         an unsigned 16 bit integer specifying the number of
+                resource records in the additional records section.
+
+4.1.2. Question section format
+
+The question section is used to carry the "question" in most queries,
+i.e., the parameters that define what is being asked.  The section
+contains QDCOUNT (usually 1) entries, each of the following format:
+
+                                    1  1  1  1  1  1
+      0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    |                                               |
+    /                     QNAME                     /
+    /                                               /
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    |                     QTYPE                     |
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    |                     QCLASS                    |
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+QNAME           a domain name represented as a sequence of labels, where
+                each label consists of a length octet followed by that
+                number of octets.  The domain name terminates with the
+                zero length octet for the null label of the root.  Note
+                that this field may be an odd number of octets; no
+                padding is used.
+
+QTYPE           a two octet code which specifies the type of the query.
+                The values for this field include all codes valid for a
+                TYPE field, together with some more general codes which
+                can match more than one type of RR.
+
+
+
+Mockapetris                                                    [Page 28]
+\f
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+QCLASS          a two octet code that specifies the class of the query.
+                For example, the QCLASS field is IN for the Internet.
+
+4.1.3. Resource record format
+
+The answer, authority, and additional sections all share the same
+format: a variable number of resource records, where the number of
+records is specified in the corresponding count field in the header.
+Each resource record has the following format:
+                                    1  1  1  1  1  1
+      0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    |                                               |
+    /                                               /
+    /                      NAME                     /
+    |                                               |
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    |                      TYPE                     |
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    |                     CLASS                     |
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    |                      TTL                      |
+    |                                               |
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    |                   RDLENGTH                    |
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
+    /                     RDATA                     /
+    /                                               /
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+where:
+
+NAME            a domain name to which this resource record pertains.
+
+TYPE            two octets containing one of the RR type codes.  This
+                field specifies the meaning of the data in the RDATA
+                field.
+
+CLASS           two octets which specify the class of the data in the
+                RDATA field.
+
+TTL             a 32 bit unsigned integer that specifies the time
+                interval (in seconds) that the resource record may be
+                cached before it should be discarded.  Zero values are
+                interpreted to mean that the RR can only be used for the
+                transaction in progress, and should not be cached.
+
+
+
+
+
+Mockapetris                                                    [Page 29]
+\f
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+RDLENGTH        an unsigned 16 bit integer that specifies the length in
+                octets of the RDATA field.
+
+RDATA           a variable length string of octets that describes the
+                resource.  The format of this information varies
+                according to the TYPE and CLASS of the resource record.
+                For example, the if the TYPE is A and the CLASS is IN,
+                the RDATA field is a 4 octet ARPA Internet address.
+
+4.1.4. Message compression
+
+In order to reduce the size of messages, the domain system utilizes a
+compression scheme which eliminates the repetition of domain names in a
+message.  In this scheme, an entire domain name or a list of labels at
+the end of a domain name is replaced with a pointer to a prior occurance
+of the same name.
+
+The pointer takes the form of a two octet sequence:
+
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    | 1  1|                OFFSET                   |
+    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+The first two bits are ones.  This allows a pointer to be distinguished
+from a label, since the label must begin with two zero bits because
+labels are restricted to 63 octets or less.  (The 10 and 01 combinations
+are reserved for future use.)  The OFFSET field specifies an offset from
+the start of the message (i.e., the first octet of the ID field in the
+domain header).  A zero offset specifies the first byte of the ID field,
+etc.
+
+The compression scheme allows a domain name in a message to be
+represented as either:
+
+   - a sequence of labels ending in a zero octet
+
+   - a pointer
+
+   - a sequence of labels ending with a pointer
+
+Pointers can only be used for occurances of a domain name where the
+format is not class specific.  If this were not the case, a name server
+or resolver would be required to know the format of all RRs it handled.
+As yet, there are no such cases, but they may occur in future RDATA
+formats.
+
+If a domain name is contained in a part of the message subject to a
+length field (such as the RDATA section of an RR), and compression is
+
+
+
+Mockapetris                                                    [Page 30]
+\f
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+used, the length of the compressed name is used in the length
+calculation, rather than the length of the expanded name.
+
+Programs are free to avoid using pointers in messages they generate,
+although this will reduce datagram capacity, and may cause truncation.
+However all programs are required to understand arriving messages that
+contain pointers.
+
+For example, a datagram might need to use the domain names F.ISI.ARPA,
+FOO.F.ISI.ARPA, ARPA, and the root.  Ignoring the other fields of the
+message, these domain names might be represented as:
+
+       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    20 |           1           |           F           |
+       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    22 |           3           |           I           |
+       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    24 |           S           |           I           |
+       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    26 |           4           |           A           |
+       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    28 |           R           |           P           |
+       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    30 |           A           |           0           |
+       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    40 |           3           |           F           |
+       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    42 |           O           |           O           |
+       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    44 | 1  1|                20                       |
+       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    64 | 1  1|                26                       |
+       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+    92 |           0           |                       |
+       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+The domain name for F.ISI.ARPA is shown at offset 20.  The domain name
+FOO.F.ISI.ARPA is shown at offset 40; this definition uses a pointer to
+concatenate a label for FOO to the previously defined F.ISI.ARPA.  The
+domain name ARPA is defined at offset 64 using a pointer to the ARPA
+component of the name F.ISI.ARPA at 20; note that this pointer relies on
+ARPA being the last label in the string at 20.  The root domain name is
+
+
+
+Mockapetris                                                    [Page 31]
+\f
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+defined by a single octet of zeros at 92; the root domain name has no
+labels.
+
+4.2. Transport
+
+The DNS assumes that messages will be transmitted as datagrams or in a
+byte stream carried by a virtual circuit.  While virtual circuits can be
+used for any DNS activity, datagrams are preferred for queries due to
+their lower overhead and better performance.  Zone refresh activities
+must use virtual circuits because of the need for reliable transfer.
+
+The Internet supports name server access using TCP [RFC-793] on server
+port 53 (decimal) as well as datagram access using UDP [RFC-768] on UDP
+port 53 (decimal).
+
+4.2.1. UDP usage
+
+Messages sent using UDP user server port 53 (decimal).
+
+Messages carried by UDP are restricted to 512 bytes (not counting the IP
+or UDP headers).  Longer messages are truncated and the TC bit is set in
+the header.
+
+UDP is not acceptable for zone transfers, but is the recommended method
+for standard queries in the Internet.  Queries sent using UDP may be
+lost, and hence a retransmission strategy is required.  Queries or their
+responses may be reordered by the network, or by processing in name
+servers, so resolvers should not depend on them being returned in order.
+
+The optimal UDP retransmission policy will vary with performance of the
+Internet and the needs of the client, but the following are recommended:
+
+   - The client should try other servers and server addresses
+     before repeating a query to a specific address of a server.
+
+   - The retransmission interval should be based on prior
+     statistics if possible.  Too aggressive retransmission can
+     easily slow responses for the community at large.  Depending
+     on how well connected the client is to its expected servers,
+     the minimum retransmission interval should be 2-5 seconds.
+
+More suggestions on server selection and retransmission policy can be
+found in the resolver section of this memo.
+
+4.2.2. TCP usage
+
+Messages sent over TCP connections use server port 53 (decimal).  The
+message is prefixed with a two byte length field which gives the message
+
+
+
+Mockapetris                                                    [Page 32]
+\f
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+length, excluding the two byte length field.  This length field allows
+the low-level processing to assemble a complete message before beginning
+to parse it.
+
+Several connection management policies are recommended:
+
+   - The server should not block other activities waiting for TCP
+     data.
+
+   - The server should support multiple connections.
+
+   - The server should assume that the client will initiate
+     connection closing, and should delay closing its end of the
+     connection until all outstanding client requests have been
+     satisfied.
+
+   - If the server needs to close a dormant connection to reclaim
+     resources, it should wait until the connection has been idle
+     for a period on the order of two minutes.  In particular, the
+     server should allow the SOA and AXFR request sequence (which
+     begins a refresh operation) to be made on a single connection.
+     Since the server would be unable to answer queries anyway, a
+     unilateral close or reset may be used instead of a graceful
+     close.
+
+5. MASTER FILES
+
+Master files are text files that contain RRs in text form.  Since the
+contents of a zone can be expressed in the form of a list of RRs a
+master file is most often used to define a zone, though it can be used
+to list a cache's contents.  Hence, this section first discusses the
+format of RRs in a master file, and then the special considerations when
+a master file is used to create a zone in some name server.
+
+5.1. Format
+
+The format of these files is a sequence of entries.  Entries are
+predominantly line-oriented, though parentheses can be used to continue
+a list of items across a line boundary, and text literals can contain
+CRLF within the text.  Any combination of tabs and spaces act as a
+delimiter between the separate items that make up an entry.  The end of
+any line in the master file can end with a comment.  The comment starts
+with a ";" (semicolon).
+
+The following entries are defined:
+
+    <blank>[<comment>]
+
+
+
+
+Mockapetris                                                    [Page 33]
+\f
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+    $ORIGIN <domain-name> [<comment>]
+
+    $INCLUDE <file-name> [<domain-name>] [<comment>]
+
+    <domain-name><rr> [<comment>]
+
+    <blank><rr> [<comment>]
+
+Blank lines, with or without comments, are allowed anywhere in the file.
+
+Two control entries are defined: $ORIGIN and $INCLUDE.  $ORIGIN is
+followed by a domain name, and resets the current origin for relative
+domain names to the stated name.  $INCLUDE inserts the named file into
+the current file, and may optionally specify a domain name that sets the
+relative domain name origin for the included file.  $INCLUDE may also
+have a comment.  Note that a $INCLUDE entry never changes the relative
+origin of the parent file, regardless of changes to the relative origin
+made within the included file.
+
+The last two forms represent RRs.  If an entry for an RR begins with a
+blank, then the RR is assumed to be owned by the last stated owner.  If
+an RR entry begins with a <domain-name>, then the owner name is reset.
+
+<rr> contents take one of the following forms:
+
+    [<TTL>] [<class>] <type> <RDATA>
+
+    [<class>] [<TTL>] <type> <RDATA>
+
+The RR begins with optional TTL and class fields, followed by a type and
+RDATA field appropriate to the type and class.  Class and type use the
+standard mnemonics, TTL is a decimal integer.  Omitted class and TTL
+values are default to the last explicitly stated values.  Since type and
+class mnemonics are disjoint, the parse is unique.  (Note that this
+order is different from the order used in examples and the order used in
+the actual RRs; the given order allows easier parsing and defaulting.)
+
+<domain-name>s make up a large share of the data in the master file.
+The labels in the domain name are expressed as character strings and
+separated by dots.  Quoting conventions allow arbitrary characters to be
+stored in domain names.  Domain names that end in a dot are called
+absolute, and are taken as complete.  Domain names which do not end in a
+dot are called relative; the actual domain name is the concatenation of
+the relative part with an origin specified in a $ORIGIN, $INCLUDE, or as
+an argument to the master file loading routine.  A relative name is an
+error when no origin is available.
+
+
+
+
+
+Mockapetris                                                    [Page 34]
+\f
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+<character-string> is expressed in one or two ways: as a contiguous set
+of characters without interior spaces, or as a string beginning with a "
+and ending with a ".  Inside a " delimited string any character can
+occur, except for a " itself, which must be quoted using \ (back slash).
+
+Because these files are text files several special encodings are
+necessary to allow arbitrary data to be loaded.  In particular:
+
+                of the root.
+
+@               A free standing @ is used to denote the current origin.
+
+\X              where X is any character other than a digit (0-9), is
+                used to quote that character so that its special meaning
+                does not apply.  For example, "\." can be used to place
+                a dot character in a label.
+
+\DDD            where each D is a digit is the octet corresponding to
+                the decimal number described by DDD.  The resulting
+                octet is assumed to be text and is not checked for
+                special meaning.
+
+( )             Parentheses are used to group data that crosses a line
+                boundary.  In effect, line terminations are not
+                recognized within parentheses.
+
+;               Semicolon is used to start a comment; the remainder of
+                the line is ignored.
+
+5.2. Use of master files to define zones
+
+When a master file is used to load a zone, the operation should be
+suppressed if any errors are encountered in the master file.  The
+rationale for this is that a single error can have widespread
+consequences.  For example, suppose that the RRs defining a delegation
+have syntax errors; then the server will return authoritative name
+errors for all names in the subzone (except in the case where the
+subzone is also present on the server).
+
+Several other validity checks that should be performed in addition to
+insuring that the file is syntactically correct:
+
+   1. All RRs in the file should have the same class.
+
+   2. Exactly one SOA RR should be present at the top of the zone.
+
+   3. If delegations are present and glue information is required,
+      it should be present.
+
+
+
+Mockapetris                                                    [Page 35]
+\f
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+   4. Information present outside of the authoritative nodes in the
+      zone should be glue information, rather than the result of an
+      origin or similar error.
+
+5.3. Master file example
+
+The following is an example file which might be used to define the
+ISI.EDU zone.and is loaded with an origin of ISI.EDU:
+
+@   IN  SOA     VENERA      Action\.domains (
+                                 20     ; SERIAL
+                                 7200   ; REFRESH
+                                 600    ; RETRY
+                                 3600000; EXPIRE
+                                 60)    ; MINIMUM
+
+        NS      A.ISI.EDU.
+        NS      VENERA
+        NS      VAXA
+        MX      10      VENERA
+        MX      20      VAXA
+
+A       A       26.3.0.103
+
+VENERA  A       10.1.0.52
+        A       128.9.0.32
+
+VAXA    A       10.2.0.27
+        A       128.9.0.33
+
+
+$INCLUDE <SUBSYS>ISI-MAILBOXES.TXT
+
+Where the file <SUBSYS>ISI-MAILBOXES.TXT is:
+
+    MOE     MB      A.ISI.EDU.
+    LARRY   MB      A.ISI.EDU.
+    CURLEY  MB      A.ISI.EDU.
+    STOOGES MG      MOE
+            MG      LARRY
+            MG      CURLEY
+
+Note the use of the \ character in the SOA RR to specify the responsible
+person mailbox "Action.domains@E.ISI.EDU".
+
+
+
+
+
+
+
+Mockapetris                                                    [Page 36]
+\f
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+6. NAME SERVER IMPLEMENTATION
+
+6.1. Architecture
+
+The optimal structure for the name server will depend on the host
+operating system and whether the name server is integrated with resolver
+operations, either by supporting recursive service, or by sharing its
+database with a resolver.  This section discusses implementation
+considerations for a name server which shares a database with a
+resolver, but most of these concerns are present in any name server.
+
+6.1.1. Control
+
+A name server must employ multiple concurrent activities, whether they
+are implemented as separate tasks in the host's OS or multiplexing
+inside a single name server program.  It is simply not acceptable for a
+name server to block the service of UDP requests while it waits for TCP
+data for refreshing or query activities.  Similarly, a name server
+should not attempt to provide recursive service without processing such
+requests in parallel, though it may choose to serialize requests from a
+single client, or to regard identical requests from the same client as
+duplicates.  A name server should not substantially delay requests while
+it reloads a zone from master files or while it incorporates a newly
+refreshed zone into its database.
+
+6.1.2. Database
+
+While name server implementations are free to use any internal data
+structures they choose, the suggested structure consists of three major
+parts:
+
+   - A "catalog" data structure which lists the zones available to
+     this server, and a "pointer" to the zone data structure.  The
+     main purpose of this structure is to find the nearest ancestor
+     zone, if any, for arriving standard queries.
+
+   - Separate data structures for each of the zones held by the
+     name server.
+
+   - A data structure for cached data. (or perhaps separate caches
+     for different classes)
+
+All of these data structures can be implemented an identical tree
+structure format, with different data chained off the nodes in different
+parts: in the catalog the data is pointers to zones, while in the zone
+and cache data structures, the data will be RRs.  In designing the tree
+framework the designer should recognize that query processing will need
+to traverse the tree using case-insensitive label comparisons; and that
+
+
+
+Mockapetris                                                    [Page 37]
+\f
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+in real data, a few nodes have a very high branching factor (100-1000 or
+more), but the vast majority have a very low branching factor (0-1).
+
+One way to solve the case problem is to store the labels for each node
+in two pieces: a standardized-case representation of the label where all
+ASCII characters are in a single case, together with a bit mask that
+denotes which characters are actually of a different case.  The
+branching factor diversity can be handled using a simple linked list for
+a node until the branching factor exceeds some threshold, and
+transitioning to a hash structure after the threshold is exceeded.  In
+any case, hash structures used to store tree sections must insure that
+hash functions and procedures preserve the casing conventions of the
+DNS.
+
+The use of separate structures for the different parts of the database
+is motivated by several factors:
+
+   - The catalog structure can be an almost static structure that
+     need change only when the system administrator changes the
+     zones supported by the server.  This structure can also be
+     used to store parameters used to control refreshing
+     activities.
+
+   - The individual data structures for zones allow a zone to be
+     replaced simply by changing a pointer in the catalog.  Zone
+     refresh operations can build a new structure and, when
+     complete, splice it into the database via a simple pointer
+     replacement.  It is very important that when a zone is
+     refreshed, queries should not use old and new data
+     simultaneously.
+
+   - With the proper search procedures, authoritative data in zones
+     will always "hide", and hence take precedence over, cached
+     data.
+
+   - Errors in zone definitions that cause overlapping zones, etc.,
+     may cause erroneous responses to queries, but problem
+     determination is simplified, and the contents of one "bad"
+     zone can't corrupt another.
+
+   - Since the cache is most frequently updated, it is most
+     vulnerable to corruption during system restarts.  It can also
+     become full of expired RR data.  In either case, it can easily
+     be discarded without disturbing zone data.
+
+A major aspect of database design is selecting a structure which allows
+the name server to deal with crashes of the name server's host.  State
+information which a name server should save across system crashes
+
+
+
+Mockapetris                                                    [Page 38]
+\f
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+includes the catalog structure (including the state of refreshing for
+each zone) and the zone data itself.
+
+6.1.3. Time
+
+Both the TTL data for RRs and the timing data for refreshing activities
+depends on 32 bit timers in units of seconds.  Inside the database,
+refresh timers and TTLs for cached data conceptually "count down", while
+data in the zone stays with constant TTLs.
+
+A recommended implementation strategy is to store time in two ways:  as
+a relative increment and as an absolute time.  One way to do this is to
+use positive 32 bit numbers for one type and negative numbers for the
+other.  The RRs in zones use relative times; the refresh timers and
+cache data use absolute times.  Absolute numbers are taken with respect
+to some known origin and converted to relative values when placed in the
+response to a query.  When an absolute TTL is negative after conversion
+to relative, then the data is expired and should be ignored.
+
+6.2. Standard query processing
+
+The major algorithm for standard query processing is presented in
+[RFC-1034].
+
+When processing queries with QCLASS=*, or some other QCLASS which
+matches multiple classes, the response should never be authoritative
+unless the server can guarantee that the response covers all classes.
+
+When composing a response, RRs which are to be inserted in the
+additional section, but duplicate RRs in the answer or authority
+sections, may be omitted from the additional section.
+
+When a response is so long that truncation is required, the truncation
+should start at the end of the response and work forward in the
+datagram.  Thus if there is any data for the authority section, the
+answer section is guaranteed to be unique.
+
+The MINIMUM value in the SOA should be used to set a floor on the TTL of
+data distributed from a zone.  This floor function should be done when
+the data is copied into a response.  This will allow future dynamic
+update protocols to change the SOA MINIMUM field without ambiguous
+semantics.
+
+6.3. Zone refresh and reload processing
+
+In spite of a server's best efforts, it may be unable to load zone data
+from a master file due to syntax errors, etc., or be unable to refresh a
+zone within the its expiration parameter.  In this case, the name server
+
+
+
+Mockapetris                                                    [Page 39]
+\f
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+should answer queries as if it were not supposed to possess the zone.
+
+If a master is sending a zone out via AXFR, and a new version is created
+during the transfer, the master should continue to send the old version
+if possible.  In any case, it should never send part of one version and
+part of another.  If completion is not possible, the master should reset
+the connection on which the zone transfer is taking place.
+
+6.4. Inverse queries (Optional)
+
+Inverse queries are an optional part of the DNS.  Name servers are not
+required to support any form of inverse queries.  If a name server
+receives an inverse query that it does not support, it returns an error
+response with the "Not Implemented" error set in the header.  While
+inverse query support is optional, all name servers must be at least
+able to return the error response.
+
+6.4.1. The contents of inverse queries and responses          Inverse
+queries reverse the mappings performed by standard query operations;
+while a standard query maps a domain name to a resource, an inverse
+query maps a resource to a domain name.  For example, a standard query
+might bind a domain name to a host address; the corresponding inverse
+query binds the host address to a domain name.
+
+Inverse queries take the form of a single RR in the answer section of
+the message, with an empty question section.  The owner name of the
+query RR and its TTL are not significant.  The response carries
+questions in the question section which identify all names possessing
+the query RR WHICH THE NAME SERVER KNOWS.  Since no name server knows
+about all of the domain name space, the response can never be assumed to
+be complete.  Thus inverse queries are primarily useful for database
+management and debugging activities.  Inverse queries are NOT an
+acceptable method of mapping host addresses to host names; use the IN-
+ADDR.ARPA domain instead.
+
+Where possible, name servers should provide case-insensitive comparisons
+for inverse queries.  Thus an inverse query asking for an MX RR of
+"Venera.isi.edu" should get the same response as a query for
+"VENERA.ISI.EDU"; an inverse query for HINFO RR "IBM-PC UNIX" should
+produce the same result as an inverse query for "IBM-pc unix".  However,
+this cannot be guaranteed because name servers may possess RRs that
+contain character strings but the name server does not know that the
+data is character.
+
+When a name server processes an inverse query, it either returns:
+
+   1. zero, one, or multiple domain names for the specified
+      resource as QNAMEs in the question section
+
+
+
+Mockapetris                                                    [Page 40]
+\f
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+   2. an error code indicating that the name server doesn't support
+      inverse mapping of the specified resource type.
+
+When the response to an inverse query contains one or more QNAMEs, the
+owner name and TTL of the RR in the answer section which defines the
+inverse query is modified to exactly match an RR found at the first
+QNAME.
+
+RRs returned in the inverse queries cannot be cached using the same
+mechanism as is used for the replies to standard queries.  One reason
+for this is that a name might have multiple RRs of the same type, and
+only one would appear.  For example, an inverse query for a single
+address of a multiply homed host might create the impression that only
+one address existed.
+
+6.4.2. Inverse query and response example          The overall structure
+of an inverse query for retrieving the domain name that corresponds to
+Internet address 10.1.0.52 is shown below:
+
+                         +-----------------------------------------+
+           Header        |          OPCODE=IQUERY, ID=997          |
+                         +-----------------------------------------+
+          Question       |                 <empty>                 |
+                         +-----------------------------------------+
+           Answer        |        <anyname> A IN 10.1.0.52         |
+                         +-----------------------------------------+
+          Authority      |                 <empty>                 |
+                         +-----------------------------------------+
+         Additional      |                 <empty>                 |
+                         +-----------------------------------------+
+
+This query asks for a question whose answer is the Internet style
+address 10.1.0.52.  Since the owner name is not known, any domain name
+can be used as a placeholder (and is ignored).  A single octet of zero,
+signifying the root, is usually used because it minimizes the length of
+the message.  The TTL of the RR is not significant.  The response to
+this query might be:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Mockapetris                                                    [Page 41]
+\f
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+                         +-----------------------------------------+
+           Header        |         OPCODE=RESPONSE, ID=997         |
+                         +-----------------------------------------+
+          Question       |QTYPE=A, QCLASS=IN, QNAME=VENERA.ISI.EDU |
+                         +-----------------------------------------+
+           Answer        |  VENERA.ISI.EDU  A IN 10.1.0.52         |
+                         +-----------------------------------------+
+          Authority      |                 <empty>                 |
+                         +-----------------------------------------+
+         Additional      |                 <empty>                 |
+                         +-----------------------------------------+
+
+Note that the QTYPE in a response to an inverse query is the same as the
+TYPE field in the answer section of the inverse query.  Responses to
+inverse queries may contain multiple questions when the inverse is not
+unique.  If the question section in the response is not empty, then the
+RR in the answer section is modified to correspond to be an exact copy
+of an RR at the first QNAME.
+
+6.4.3. Inverse query processing
+
+Name servers that support inverse queries can support these operations
+through exhaustive searches of their databases, but this becomes
+impractical as the size of the database increases.  An alternative
+approach is to invert the database according to the search key.
+
+For name servers that support multiple zones and a large amount of data,
+the recommended approach is separate inversions for each zone.  When a
+particular zone is changed during a refresh, only its inversions need to
+be redone.
+
+Support for transfer of this type of inversion may be included in future
+versions of the domain system, but is not supported in this version.
+
+6.5. Completion queries and responses
+
+The optional completion services described in RFC-882 and RFC-883 have
+been deleted.  Redesigned services may become available in the future.
+
+
+
+
+
+
+
+
+
+
+
+
+
+Mockapetris                                                    [Page 42]
+\f
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+7. RESOLVER IMPLEMENTATION
+
+The top levels of the recommended resolver algorithm are discussed in
+[RFC-1034].  This section discusses implementation details assuming the
+database structure suggested in the name server implementation section
+of this memo.
+
+7.1. Transforming a user request into a query
+
+The first step a resolver takes is to transform the client's request,
+stated in a format suitable to the local OS, into a search specification
+for RRs at a specific name which match a specific QTYPE and QCLASS.
+Where possible, the QTYPE and QCLASS should correspond to a single type
+and a single class, because this makes the use of cached data much
+simpler.  The reason for this is that the presence of data of one type
+in a cache doesn't confirm the existence or non-existence of data of
+other types, hence the only way to be sure is to consult an
+authoritative source.  If QCLASS=* is used, then authoritative answers
+won't be available.
+
+Since a resolver must be able to multiplex multiple requests if it is to
+perform its function efficiently, each pending request is usually
+represented in some block of state information.  This state block will
+typically contain:
+
+   - A timestamp indicating the time the request began.
+     The timestamp is used to decide whether RRs in the database
+     can be used or are out of date.  This timestamp uses the
+     absolute time format previously discussed for RR storage in
+     zones and caches.  Note that when an RRs TTL indicates a
+     relative time, the RR must be timely, since it is part of a
+     zone.  When the RR has an absolute time, it is part of a
+     cache, and the TTL of the RR is compared against the timestamp
+     for the start of the request.
+
+     Note that using the timestamp is superior to using a current
+     time, since it allows RRs with TTLs of zero to be entered in
+     the cache in the usual manner, but still used by the current
+     request, even after intervals of many seconds due to system
+     load, query retransmission timeouts, etc.
+
+   - Some sort of parameters to limit the amount of work which will
+     be performed for this request.
+
+     The amount of work which a resolver will do in response to a
+     client request must be limited to guard against errors in the
+     database, such as circular CNAME references, and operational
+     problems, such as network partition which prevents the
+
+
+
+Mockapetris                                                    [Page 43]
+\f
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+     resolver from accessing the name servers it needs.  While
+     local limits on the number of times a resolver will retransmit
+     a particular query to a particular name server address are
+     essential, the resolver should have a global per-request
+     counter to limit work on a single request.  The counter should
+     be set to some initial value and decremented whenever the
+     resolver performs any action (retransmission timeout,
+     retransmission, etc.)  If the counter passes zero, the request
+     is terminated with a temporary error.
+
+     Note that if the resolver structure allows one request to
+     start others in parallel, such as when the need to access a
+     name server for one request causes a parallel resolve for the
+     name server's addresses, the spawned request should be started
+     with a lower counter.  This prevents circular references in
+     the database from starting a chain reaction of resolver
+     activity.
+
+   - The SLIST data structure discussed in [RFC-1034].
+
+     This structure keeps track of the state of a request if it
+     must wait for answers from foreign name servers.
+
+7.2. Sending the queries
+
+As described in [RFC-1034], the basic task of the resolver is to
+formulate a query which will answer the client's request and direct that
+query to name servers which can provide the information.  The resolver
+will usually only have very strong hints about which servers to ask, in
+the form of NS RRs, and may have to revise the query, in response to
+CNAMEs, or revise the set of name servers the resolver is asking, in
+response to delegation responses which point the resolver to name
+servers closer to the desired information.  In addition to the
+information requested by the client, the resolver may have to call upon
+its own services to determine the address of name servers it wishes to
+contact.
+
+In any case, the model used in this memo assumes that the resolver is
+multiplexing attention between multiple requests, some from the client,
+and some internally generated.  Each request is represented by some
+state information, and the desired behavior is that the resolver
+transmit queries to name servers in a way that maximizes the probability
+that the request is answered, minimizes the time that the request takes,
+and avoids excessive transmissions.  The key algorithm uses the state
+information of the request to select the next name server address to
+query, and also computes a timeout which will cause the next action
+should a response not arrive.  The next action will usually be a
+transmission to some other server, but may be a temporary error to the
+
+
+
+Mockapetris                                                    [Page 44]
+\f
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+client.
+
+The resolver always starts with a list of server names to query (SLIST).
+This list will be all NS RRs which correspond to the nearest ancestor
+zone that the resolver knows about.  To avoid startup problems, the
+resolver should have a set of default servers which it will ask should
+it have no current NS RRs which are appropriate.  The resolver then adds
+to SLIST all of the known addresses for the name servers, and may start
+parallel requests to acquire the addresses of the servers when the
+resolver has the name, but no addresses, for the name servers.
+
+To complete initialization of SLIST, the resolver attaches whatever
+history information it has to the each address in SLIST.  This will
+usually consist of some sort of weighted averages for the response time
+of the address, and the batting average of the address (i.e., how often
+the address responded at all to the request).  Note that this
+information should be kept on a per address basis, rather than on a per
+name server basis, because the response time and batting average of a
+particular server may vary considerably from address to address.  Note
+also that this information is actually specific to a resolver address /
+server address pair, so a resolver with multiple addresses may wish to
+keep separate histories for each of its addresses.  Part of this step
+must deal with addresses which have no such history; in this case an
+expected round trip time of 5-10 seconds should be the worst case, with
+lower estimates for the same local network, etc.
+
+Note that whenever a delegation is followed, the resolver algorithm
+reinitializes SLIST.
+
+The information establishes a partial ranking of the available name
+server addresses.  Each time an address is chosen and the state should
+be altered to prevent its selection again until all other addresses have
+been tried.  The timeout for each transmission should be 50-100% greater
+than the average predicted value to allow for variance in response.
+
+Some fine points:
+
+   - The resolver may encounter a situation where no addresses are
+     available for any of the name servers named in SLIST, and
+     where the servers in the list are precisely those which would
+     normally be used to look up their own addresses.  This
+     situation typically occurs when the glue address RRs have a
+     smaller TTL than the NS RRs marking delegation, or when the
+     resolver caches the result of a NS search.  The resolver
+     should detect this condition and restart the search at the
+     next ancestor zone, or alternatively at the root.
+
+
+
+
+
+Mockapetris                                                    [Page 45]
+\f
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+   - If a resolver gets a server error or other bizarre response
+     from a name server, it should remove it from SLIST, and may
+     wish to schedule an immediate transmission to the next
+     candidate server address.
+
+7.3. Processing responses
+
+The first step in processing arriving response datagrams is to parse the
+response.  This procedure should include:
+
+   - Check the header for reasonableness.  Discard datagrams which
+     are queries when responses are expected.
+
+   - Parse the sections of the message, and insure that all RRs are
+     correctly formatted.
+
+   - As an optional step, check the TTLs of arriving data looking
+     for RRs with excessively long TTLs.  If a RR has an
+     excessively long TTL, say greater than 1 week, either discard
+     the whole response, or limit all TTLs in the response to 1
+     week.
+
+The next step is to match the response to a current resolver request.
+The recommended strategy is to do a preliminary matching using the ID
+field in the domain header, and then to verify that the question section
+corresponds to the information currently desired.  This requires that
+the transmission algorithm devote several bits of the domain ID field to
+a request identifier of some sort.  This step has several fine points:
+
+   - Some name servers send their responses from different
+     addresses than the one used to receive the query.  That is, a
+     resolver cannot rely that a response will come from the same
+     address which it sent the corresponding query to.  This name
+     server bug is typically encountered in UNIX systems.
+
+   - If the resolver retransmits a particular request to a name
+     server it should be able to use a response from any of the
+     transmissions.  However, if it is using the response to sample
+     the round trip time to access the name server, it must be able
+     to determine which transmission matches the response (and keep
+     transmission times for each outgoing message), or only
+     calculate round trip times based on initial transmissions.
+
+   - A name server will occasionally not have a current copy of a
+     zone which it should have according to some NS RRs.  The
+     resolver should simply remove the name server from the current
+     SLIST, and continue.
+
+
+
+
+Mockapetris                                                    [Page 46]
+\f
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+7.4. Using the cache
+
+In general, we expect a resolver to cache all data which it receives in
+responses since it may be useful in answering future client requests.
+However, there are several types of data which should not be cached:
+
+   - When several RRs of the same type are available for a
+     particular owner name, the resolver should either cache them
+     all or none at all.  When a response is truncated, and a
+     resolver doesn't know whether it has a complete set, it should
+     not cache a possibly partial set of RRs.
+
+   - Cached data should never be used in preference to
+     authoritative data, so if caching would cause this to happen
+     the data should not be cached.
+
+   - The results of an inverse query should not be cached.
+
+   - The results of standard queries where the QNAME contains "*"
+     labels if the data might be used to construct wildcards.  The
+     reason is that the cache does not necessarily contain existing
+     RRs or zone boundary information which is necessary to
+     restrict the application of the wildcard RRs.
+
+   - RR data in responses of dubious reliability.  When a resolver
+     receives unsolicited responses or RR data other than that
+     requested, it should discard it without caching it.  The basic
+     implication is that all sanity checks on a packet should be
+     performed before any of it is cached.
+
+In a similar vein, when a resolver has a set of RRs for some name in a
+response, and wants to cache the RRs, it should check its cache for
+already existing RRs.  Depending on the circumstances, either the data
+in the response or the cache is preferred, but the two should never be
+combined.  If the data in the response is from authoritative data in the
+answer section, it is always preferred.
+
+8. MAIL SUPPORT
+
+The domain system defines a standard for mapping mailboxes into domain
+names, and two methods for using the mailbox information to derive mail
+routing information.  The first method is called mail exchange binding
+and the other method is mailbox binding.  The mailbox encoding standard
+and mail exchange binding are part of the DNS official protocol, and are
+the recommended method for mail routing in the Internet.  Mailbox
+binding is an experimental feature which is still under development and
+subject to change.
+
+
+
+
+Mockapetris                                                    [Page 47]
+\f
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+The mailbox encoding standard assumes a mailbox name of the form
+"<local-part>@<mail-domain>".  While the syntax allowed in each of these
+sections varies substantially between the various mail internets, the
+preferred syntax for the ARPA Internet is given in [RFC-822].
+
+The DNS encodes the <local-part> as a single label, and encodes the
+<mail-domain> as a domain name.  The single label from the <local-part>
+is prefaced to the domain name from <mail-domain> to form the domain
+name corresponding to the mailbox.  Thus the mailbox HOSTMASTER@SRI-
+NIC.ARPA is mapped into the domain name HOSTMASTER.SRI-NIC.ARPA.  If the
+<local-part> contains dots or other special characters, its
+representation in a master file will require the use of backslash
+quoting to ensure that the domain name is properly encoded.  For
+example, the mailbox Action.domains@ISI.EDU would be represented as
+Action\.domains.ISI.EDU.
+
+8.1. Mail exchange binding
+
+Mail exchange binding uses the <mail-domain> part of a mailbox
+specification to determine where mail should be sent.  The <local-part>
+is not even consulted.  [RFC-974] specifies this method in detail, and
+should be consulted before attempting to use mail exchange support.
+
+One of the advantages of this method is that it decouples mail
+destination naming from the hosts used to support mail service, at the
+cost of another layer of indirection in the lookup function.  However,
+the addition layer should eliminate the need for complicated "%", "!",
+etc encodings in <local-part>.
+
+The essence of the method is that the <mail-domain> is used as a domain
+name to locate type MX RRs which list hosts willing to accept mail for
+<mail-domain>, together with preference values which rank the hosts
+according to an order specified by the administrators for <mail-domain>.
+
+In this memo, the <mail-domain> ISI.EDU is used in examples, together
+with the hosts VENERA.ISI.EDU and VAXA.ISI.EDU as mail exchanges for
+ISI.EDU.  If a mailer had a message for Mockapetris@ISI.EDU, it would
+route it by looking up MX RRs for ISI.EDU.  The MX RRs at ISI.EDU name
+VENERA.ISI.EDU and VAXA.ISI.EDU, and type A queries can find the host
+addresses.
+
+8.2. Mailbox binding (Experimental)
+
+In mailbox binding, the mailer uses the entire mail destination
+specification to construct a domain name.  The encoded domain name for
+the mailbox is used as the QNAME field in a QTYPE=MAILB query.
+
+Several outcomes are possible for this query:
+
+
+
+Mockapetris                                                    [Page 48]
+\f
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+   1. The query can return a name error indicating that the mailbox
+      does not exist as a domain name.
+
+      In the long term, this would indicate that the specified
+      mailbox doesn't exist.  However, until the use of mailbox
+      binding is universal, this error condition should be
+      interpreted to mean that the organization identified by the
+      global part does not support mailbox binding.  The
+      appropriate procedure is to revert to exchange binding at
+      this point.
+
+   2. The query can return a Mail Rename (MR) RR.
+
+      The MR RR carries new mailbox specification in its RDATA
+      field.  The mailer should replace the old mailbox with the
+      new one and retry the operation.
+
+   3. The query can return a MB RR.
+
+      The MB RR carries a domain name for a host in its RDATA
+      field.  The mailer should deliver the message to that host
+      via whatever protocol is applicable, e.g., b,SMTP.
+
+   4. The query can return one or more Mail Group (MG) RRs.
+
+      This condition means that the mailbox was actually a mailing
+      list or mail group, rather than a single mailbox.  Each MG RR
+      has a RDATA field that identifies a mailbox that is a member
+      of the group.  The mailer should deliver a copy of the
+      message to each member.
+
+   5. The query can return a MB RR as well as one or more MG RRs.
+
+      This condition means the the mailbox was actually a mailing
+      list.  The mailer can either deliver the message to the host
+      specified by the MB RR, which will in turn do the delivery to
+      all members, or the mailer can use the MG RRs to do the
+      expansion itself.
+
+In any of these cases, the response may include a Mail Information
+(MINFO) RR.  This RR is usually associated with a mail group, but is
+legal with a MB.  The MINFO RR identifies two mailboxes.  One of these
+identifies a responsible person for the original mailbox name.  This
+mailbox should be used for requests to be added to a mail group, etc.
+The second mailbox name in the MINFO RR identifies a mailbox that should
+receive error messages for mail failures.  This is particularly
+appropriate for mailing lists when errors in member names should be
+reported to a person other than the one who sends a message to the list.
+
+
+
+Mockapetris                                                    [Page 49]
+\f
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+New fields may be added to this RR in the future.
+
+
+9. REFERENCES and BIBLIOGRAPHY
+
+[Dyer 87]       S. Dyer, F. Hsu, "Hesiod", Project Athena
+                Technical Plan - Name Service, April 1987, version 1.9.
+
+                Describes the fundamentals of the Hesiod name service.
+
+[IEN-116]       J. Postel, "Internet Name Server", IEN-116,
+                USC/Information Sciences Institute, August 1979.
+
+                A name service obsoleted by the Domain Name System, but
+                still in use.
+
+[Quarterman 86] J. Quarterman, and J. Hoskins, "Notable Computer Networks",
+                Communications of the ACM, October 1986, volume 29, number
+                10.
+
+[RFC-742]       K. Harrenstien, "NAME/FINGER", RFC-742, Network
+                Information Center, SRI International, December 1977.
+
+[RFC-768]       J. Postel, "User Datagram Protocol", RFC-768,
+                USC/Information Sciences Institute, August 1980.
+
+[RFC-793]       J. Postel, "Transmission Control Protocol", RFC-793,
+                USC/Information Sciences Institute, September 1981.
+
+[RFC-799]       D. Mills, "Internet Name Domains", RFC-799, COMSAT,
+                September 1981.
+
+                Suggests introduction of a hierarchy in place of a flat
+                name space for the Internet.
+
+[RFC-805]       J. Postel, "Computer Mail Meeting Notes", RFC-805,
+                USC/Information Sciences Institute, February 1982.
+
+[RFC-810]       E. Feinler, K. Harrenstien, Z. Su, and V. White, "DOD
+                Internet Host Table Specification", RFC-810, Network
+                Information Center, SRI International, March 1982.
+
+                Obsolete.  See RFC-952.
+
+[RFC-811]       K. Harrenstien, V. White, and E. Feinler, "Hostnames
+                Server", RFC-811, Network Information Center, SRI
+                International, March 1982.
+
+
+
+
+Mockapetris                                                    [Page 50]
+\f
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+                Obsolete.  See RFC-953.
+
+[RFC-812]       K. Harrenstien, and V. White, "NICNAME/WHOIS", RFC-812,
+                Network Information Center, SRI International, March
+                1982.
+
+[RFC-819]       Z. Su, and J. Postel, "The Domain Naming Convention for
+                Internet User Applications", RFC-819, Network
+                Information Center, SRI International, August 1982.
+
+                Early thoughts on the design of the domain system.
+                Current implementation is completely different.
+
+[RFC-821]       J. Postel, "Simple Mail Transfer Protocol", RFC-821,
+                USC/Information Sciences Institute, August 1980.
+
+[RFC-830]       Z. Su, "A Distributed System for Internet Name Service",
+                RFC-830, Network Information Center, SRI International,
+                October 1982.
+
+                Early thoughts on the design of the domain system.
+                Current implementation is completely different.
+
+[RFC-882]       P. Mockapetris, "Domain names - Concepts and
+                Facilities," RFC-882, USC/Information Sciences
+                Institute, November 1983.
+
+                Superceeded by this memo.
+
+[RFC-883]       P. Mockapetris, "Domain names - Implementation and
+                Specification," RFC-883, USC/Information Sciences
+                Institute, November 1983.
+
+                Superceeded by this memo.
+
+[RFC-920]       J. Postel and J. Reynolds, "Domain Requirements",
+                RFC-920, USC/Information Sciences Institute,
+                October 1984.
+
+                Explains the naming scheme for top level domains.
+
+[RFC-952]       K. Harrenstien, M. Stahl, E. Feinler, "DoD Internet Host
+                Table Specification", RFC-952, SRI, October 1985.
+
+                Specifies the format of HOSTS.TXT, the host/address
+                table replaced by the DNS.
+
+
+
+
+
+Mockapetris                                                    [Page 51]
+\f
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+[RFC-953]       K. Harrenstien, M. Stahl, E. Feinler, "HOSTNAME Server",
+                RFC-953, SRI, October 1985.
+
+                This RFC contains the official specification of the
+                hostname server protocol, which is obsoleted by the DNS.
+                This TCP based protocol accesses information stored in
+                the RFC-952 format, and is used to obtain copies of the
+                host table.
+
+[RFC-973]       P. Mockapetris, "Domain System Changes and
+                Observations", RFC-973, USC/Information Sciences
+                Institute, January 1986.
+
+                Describes changes to RFC-882 and RFC-883 and reasons for
+                them.
+
+[RFC-974]       C. Partridge, "Mail routing and the domain system",
+                RFC-974, CSNET CIC BBN Labs, January 1986.
+
+                Describes the transition from HOSTS.TXT based mail
+                addressing to the more powerful MX system used with the
+                domain system.
+
+[RFC-1001]      NetBIOS Working Group, "Protocol standard for a NetBIOS
+                service on a TCP/UDP transport: Concepts and Methods",
+                RFC-1001, March 1987.
+
+                This RFC and RFC-1002 are a preliminary design for
+                NETBIOS on top of TCP/IP which proposes to base NetBIOS
+                name service on top of the DNS.
+
+[RFC-1002]      NetBIOS Working Group, "Protocol standard for a NetBIOS
+                service on a TCP/UDP transport: Detailed
+                Specifications", RFC-1002, March 1987.
+
+[RFC-1010]      J. Reynolds, and J. Postel, "Assigned Numbers", RFC-1010,
+                USC/Information Sciences Institute, May 1987.
+
+                Contains socket numbers and mnemonics for host names,
+                operating systems, etc.
+
+[RFC-1031]      W. Lazear, "MILNET Name Domain Transition", RFC-1031,
+                November 1987.
+
+                Describes a plan for converting the MILNET to the DNS.
+
+[RFC-1032]      M. Stahl, "Establishing a Domain - Guidelines for
+                Administrators", RFC-1032, November 1987.
+
+
+
+Mockapetris                                                    [Page 52]
+\f
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+                Describes the registration policies used by the NIC to
+                administer the top level domains and delegate subzones.
+
+[RFC-1033]      M. Lottor, "Domain Administrators Operations Guide",
+                RFC-1033, November 1987.
+
+                A cookbook for domain administrators.
+
+[Solomon 82]    M. Solomon, L. Landweber, and D. Neuhengen, "The CSNET
+                Name Server", Computer Networks, vol 6, nr 3, July 1982.
+
+                Describes a name service for CSNET which is independent
+                from the DNS and DNS use in the CSNET.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Mockapetris                                                    [Page 53]
+\f
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+Index
+
+          *   13
+
+          ;   33, 35
+
+          <character-string>   35
+          <domain-name>   34
+
+          @   35
+
+          \   35
+
+          A   12
+
+          Byte order   8
+
+          CH   13
+          Character case   9
+          CLASS   11
+          CNAME   12
+          Completion   42
+          CS   13
+
+          Hesiod   13
+          HINFO   12
+          HS   13
+
+          IN   13
+          IN-ADDR.ARPA domain   22
+          Inverse queries   40
+
+          Mailbox names   47
+          MB   12
+          MD   12
+          MF   12
+          MG   12
+          MINFO   12
+          MINIMUM   20
+          MR   12
+          MX   12
+
+          NS   12
+          NULL   12
+
+          Port numbers   32
+          Primary server   5
+          PTR   12, 18
+
+
+
+Mockapetris                                                    [Page 54]
+\f
+RFC 1035        Domain Implementation and Specification    November 1987
+
+
+          QCLASS   13
+          QTYPE   12
+
+          RDATA   12
+          RDLENGTH  11
+
+          Secondary server   5
+          SOA   12
+          Stub resolvers   7
+
+          TCP   32
+          TXT   12
+          TYPE   11
+
+          UDP   32
+
+          WKS   12
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Mockapetris                                                    [Page 55]
+\f
index e175dcece4aa48426b8fdd76fc374929316fdd10..17ede58a2477ecf8126e97de7d00f183580b44df 100644 (file)
@@ -1 +1,451 @@
-\r\r\r\r\r\rNetwork Working Group                                       M. St. Johns\rRequest for Comments: 1413                      US Department of Defense\rObsoletes: 931                                             February 1993\r\r\r                        Identification Protocol\r\rStatus of this Memo\r\r   This RFC specifies an IAB standards track protocol for the Internet\r   community, and requests discussion and suggestions for improvements.\r   Please refer to the current edition of the "IAB Official Protocol\r   Standards" for the standardization state and status of this protocol.\r   Distribution of this memo is unlimited.\r\r1.  INTRODUCTION\r\r   The Identification Protocol (a.k.a., "ident", a.k.a., "the Ident\r   Protocol") provides a means to determine the identity of a user of a\r   particular TCP connection.  Given a TCP port number pair, it returns\r   a character string which identifies the owner of that connection on\r   the server's system.\r\r   The Identification Protocol was formerly called the Authentication\r   Server Protocol.  It has been renamed to better reflect its function.\r   This document is a product of the TCP Client Identity Protocol\r   Working Group of the Internet Engineering Task Force (IETF).\r\r2.  OVERVIEW\r\r   This is a connection based application on TCP.  A server listens for\r   TCP connections on TCP port 113 (decimal).  Once a connection is\r   established, the server reads a line of data which specifies the\r   connection of interest.  If it exists, the system dependent user\r   identifier of the connection of interest is sent as the reply.  The\r   server may then either shut the connection down or it may continue to\r   read/respond to multiple queries.\r\r   The server should close the connection down after a configurable\r   amount of time with no queries - a 60-180 second idle timeout is\r   recommended.  The client may close the connection down at any time;\r   however to allow for network delays the client should wait at least\r   30 seconds (or longer) after a query before abandoning the query and\r   closing the connection.\r\r\r\r\r\r\r\rSt. Johns                                                       [Page 1]\r\f\rRFC 1413                Identification Protocol            February 1993\r\r\r3.  RESTRICTIONS\r\r   Queries are permitted only for fully specified connections.  The\r   query contains the local/foreign port pair -- the local/foreign\r   address pair used to fully specify the connection is taken from the\r   local and foreign address of query connection.  This means a user on\r   address A may only query the server on address B about connections\r   between A and B.\r\r4.  QUERY/RESPONSE FORMAT\r\r   The server accepts simple text query requests of the form:\r\r            <port-on-server> , <port-on-client>\r\r   where <port-on-server> is the TCP port (decimal) on the target (where\r   the "ident" server is running) system, and <port-on-client> is the\r   TCP port (decimal) on the source (client) system.\r\r   N.B - If a client on host A wants to ask a server on host B about a\r   connection specified locally (on the client's machine) as 23, 6191\r   (an inbound TELNET connection), the client must actually ask about\r   6191, 23 - which is how the connection would be specified on host B.\r\r      For example:\r\r                 6191, 23\r\r   The response is of the form\r\r   <port-on-server> , <port-on-client> : <resp-type> : <add-info>\r\r   where <port-on-server>,<port-on-client> are the same pair as the\r   query, <resp-type> is a keyword identifying the type of response, and\r   <add-info> is context dependent.\r\r   The information returned is that associated with the fully specified\r   TCP connection identified by <server-address>, <client-address>,\r   <port-on-server>, <port-on-client>, where <server-address> and\r   <client-address> are the local and foreign IP addresses of the\r   querying connection -- i.e., the TCP connection to the Identification\r   Protocol Server.  (<port-on-server> and <port-on-client> are taken\r   from the query.)\r\r      For example:\r\r         6193, 23 : USERID : UNIX : stjohns\r         6195, 23 : ERROR : NO-USER\r\r\r\rSt. Johns                                                       [Page 2]\r\f\rRFC 1413                Identification Protocol            February 1993\r\r\r5.  RESPONSE TYPES\r\rA response can be one of two types:\r\rUSERID\r\r     In this case, <add-info> is a string consisting of an\r     operating system name (with an optional character set\r     identifier), followed by ":", followed by an\r     identification string.\r\r     The character set (if present) is separated from the\r     operating system name by ",".  The character set\r     identifier is used to indicate the character set of the\r     identification string.  The character set identifier,\r     if omitted, defaults to "US-ASCII" (see below).\r\r     Permitted operating system names and character set\r     names are specified in RFC 1340, "Assigned Numbers" or\r     its successors.\r\r     In addition to those operating system and character set\r     names specified in "Assigned Numbers" there is one\r     special case operating system identifier - "OTHER".\r\r     Unless "OTHER" is specified as the operating system\r     type, the server is expected to return the "normal"\r     user identification of the owner of this connection.\r     "Normal" in this context may be taken to mean a string\r     of characters which uniquely identifies the connection\r     owner such as a user identifier assigned by the system\r     administrator and used by such user as a mail\r     identifier, or as the "user" part of a user/password\r     pair used to gain access to system resources.  When an\r     operating system is specified (e.g., anything but\r     "OTHER"), the user identifier is expected to be in a\r     more or less immediately useful form - e.g., something\r     that could be used as an argument to "finger" or as a\r     mail address.\r\r     "OTHER" indicates the identifier is an unformatted\r     character string consisting of printable characters in\r     the specified character set.  "OTHER" should be\r     specified if the user identifier does not meet the\r     constraints of the previous paragraph.  Sending an\r     encrypted audit token, or returning other non-userid\r     information about a user (such as the real name and\r     phone number of a user from a UNIX passwd file) are\r\r\r\rSt. Johns                                                       [Page 3]\r\f\rRFC 1413                Identification Protocol            February 1993\r\r\r     both examples of when "OTHER" should be used.\r\r     Returned user identifiers are expected to be printable\r     in the character set indicated.\r\r     The identifier is an unformatted octet string - - all\r     octets are permissible EXCEPT octal 000 (NUL), 012 (LF)\r     and 015 (CR).  N.B. - space characters (040) following the\r     colon separator ARE part of the identifier string and\r     may not be ignored. A response string is still\r     terminated normally by a CR/LF.  N.B. A string may be\r     printable, but is not *necessarily* printable.\r\rERROR\r\r   For some reason the port owner could not be determined, <add-info>\r   tells why.  The following are the permitted values of <add-info> and\r   their meanings:\r\r          INVALID-PORT\r\r          Either the local or foreign port was improperly\r          specified.  This should be returned if either or\r          both of the port ids were out of range (TCP port\r          numbers are from 1-65535), negative integers, reals or\r          in any fashion not recognized as a non-negative\r          integer.\r\r          NO-USER\r\r          The connection specified by the port pair is not\r          currently in use or currently not owned by an\r          identifiable entity.\r\r          HIDDEN-USER\r\r          The server was able to identify the user of this\r          port, but the information was not returned at the\r          request of the user.\r\r          UNKNOWN-ERROR\r\r          Can't determine connection owner; reason unknown.\r          Any error not covered above should return this\r          error code value.  Optionally, this code MAY be\r          returned in lieu of any other specific error code\r          if, for example, the server desires to hide\r          information implied by the return of that error\r\r\r\rSt. Johns                                                       [Page 4]\r\f\rRFC 1413                Identification Protocol            February 1993\r\r\r          code, or for any other reason.  If a server\r          implements such a feature, it MUST be configurable\r          and it MUST default to returning the proper error\r          message.\r\r   Other values may eventually be specified and defined in future\r   revisions to this document.  If an implementer has a need to specify\r   a non-standard error code, that code must begin with "X".\r\r   In addition, the server is allowed to drop the query connection\r   without responding.  Any premature close (i.e., one where the client\r   does not receive the EOL, whether graceful or an abort should be\r   considered to have the same meaning as "ERROR : UNKNOWN-ERROR".\r\rFORMAL SYNTAX\r\r   <request> ::= <port-pair> <EOL>\r\r   <port-pair> ::= <integer> "," <integer>\r\r   <reply> ::= <reply-text> <EOL>\r\r   <EOL> ::= "015 012"  ; CR-LF End of Line Indicator\r\r   <reply-text> ::= <error-reply> | <ident-reply>\r\r   <error-reply> ::= <port-pair> ":" "ERROR" ":" <error-type>\r\r   <ident-reply> ::= <port-pair> ":" "USERID" ":" <opsys-field>\r                     ":" <user-id>\r\r   <error-type> ::= "INVALID-PORT" | "NO-USER" | "UNKNOWN-ERROR"\r                    | "HIDDEN-USER" |  <error-token>\r\r   <opsys-field> ::= <opsys> [ "," <charset>]\r\r   <opsys> ::= "OTHER" | "UNIX" | <token> ...etc.\r               ;  (See "Assigned Numbers")\r\r   <charset> ::= "US-ASCII" | ...etc.\r                 ;  (See "Assigned Numbers")\r\r   <user-id> ::= <octet-string>\r\r   <token> ::= 1*64<token-characters> ; 1-64 characters\r\r   <error-token> ::= "X"1*63<token-characters>\r                     ; 2-64 chars beginning w/X\r\r\r\rSt. Johns                                                       [Page 5]\r\f\rRFC 1413                Identification Protocol            February 1993\r\r\r   <integer> ::= 1*5<digit> ; 1-5 digits.\r\r   <digit> ::= "0" | "1" ... "8" | "9" ; 0-9\r\r   <token-characters> ::=\r                  <Any of these ASCII characters: a-z, A-Z,\r                   - (dash), .!@#$%^&*()_=+.,<>/?"'~`{}[]; >\r                               ; upper and lowercase a-z plus\r                               ; printables minus the colon ":"\r                               ; character.\r\r   <octet-string> ::= 1*512<octet-characters>\r\r   <octet-characters> ::=\r                  <any octet from  00 to 377 (octal) except for\r                   ASCII NUL (000), CR (015) and LF (012)>\r\rNotes on Syntax:\r\r   1)   To promote interoperability among variant\r        implementations, with respect to white space the above\r        syntax is understood to embody the "be conservative in\r        what you send and be liberal in what you accept"\r        philosophy.  Clients and servers should not generate\r        unnecessary white space (space and tab characters) but\r        should accept white space anywhere except within a\r        token.  In parsing responses, white space may occur\r        anywhere, except within a token.  Specifically, any\r        amount of white space is permitted at the beginning or\r        end of a line both for queries and responses.  This\r        does not apply for responses that contain a user ID\r        because everything after the colon after the operating\r        system type until the terminating CR/LF is taken as\r        part of the user ID.  The terminating CR/LF is NOT\r        considered part of the user ID.\r\r   2)   The above notwithstanding, servers should restrict the\r        amount of inter-token white space they send to the\r        smallest amount reasonable or useful.  Clients should\r        feel free to abort a connection if they receive 1000\r        characters without receiving an <EOL>.\r\r   3)   The 512 character limit on user IDs and the 64\r        character limit on tokens should be understood to mean\r        as follows: a) No new token (i.e., OPSYS or ERROR-TYPE)\r        token will be defined that has a length greater than 64\r        and b) a server SHOULD NOT send more than 512 octets of\r        user ID and a client MUST accept at least 512 octets of\r\r\r\rSt. Johns                                                       [Page 6]\r\f\rRFC 1413                Identification Protocol            February 1993\r\r\r        user ID.  Because of this limitation, a server MUST\r        return the most significant portion of the user ID in\r        the first 512 octets.\r\r   4)   The character sets and character set identifiers should\r        map directly to those defined in or referenced by RFC 1340,\r        "Assigned Numbers" or its successors.  Character set\r        identifiers only apply to the user identification field\r        - all other fields will be defined in and must be sent\r        as US-ASCII.\r\r   5)   Although <user-id> is defined as an <octet-string>\r        above, it must follow the format and character set\r        constraints implied by the <opsys-field>; see the\r        discussion above.\r\r   6)   The character set provides context for the client to\r        print or store the returned user identification string.\r        If the client does not recognize or implement the\r        returned character set, it should handle the returned\r        identification string as OCTET, but should in addition\r        store or report the character set.  An OCTET string\r        should be printed, stored or handled in hex notation\r        (0-9a-f) in addition to any other representation the\r        client implements - this provides a standard\r        representation among differing implementations.\r\r6.  Security Considerations\r\r   The information returned by this protocol is at most as trustworthy\r   as the host providing it OR the organization operating the host.  For\r   example, a PC in an open lab has few if any controls on it to prevent\r   a user from having this protocol return any identifier the user\r   wants.  Likewise, if the host has been compromised the information\r   returned may be completely erroneous and misleading.\r\r   The Identification Protocol is not intended as an authorization or\r   access control protocol.  At best, it provides some additional\r   auditing information with respect to TCP connections.  At worst, it\r   can provide misleading, incorrect, or maliciously incorrect\r   information.\r\r   The use of the information returned by this protocol for other than\r   auditing is strongly discouraged.  Specifically, using Identification\r   Protocol information to make access control decisions - either as the\r   primary method (i.e., no other checks) or as an adjunct to other\r   methods may result in a weakening of normal host security.\r\r\r\r\rSt. Johns                                                       [Page 7]\r\f\rRFC 1413                Identification Protocol            February 1993\r\r\r   An Identification server may reveal information about users,\r   entities, objects or processes which might normally be considered\r   private.  An Identification server provides service which is a rough\r   analog of the CallerID services provided by some phone companies and\r   many of the same privacy considerations and arguments that apply to\r   the CallerID service apply to Identification.  If you wouldn't run a\r   "finger" server due to privacy considerations you may not want to run\r   this protocol.\r\r7.  ACKNOWLEDGEMENTS\r\r   Acknowledgement is given to Dan Bernstein who is primarily\r   responsible for renewing interest in this protocol and for pointing\r   out some annoying errors in RFC 931.\r\rReferences\r\r   [1] St. Johns, M., "Authentication Server", RFC 931, TPSC, January\r       1985.\r\r   [2] Reynolds, J., and J. Postel, "Assigned Numbers", STD 2, RFC 1340,\r       USC/Information Sciences Institute, July 1992.\r\rAuthor's Address\r\r       Michael C. St. Johns\r       DARPA/CSTO\r       3701 N. Fairfax Dr\r       Arlington, VA 22203\r\r       Phone: (703) 696-2271\r       EMail: stjohns@DARPA.MIL\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\rSt. Johns                                                       [Page 8]\r\f
\ No newline at end of file
+
+
+
+
+
+
+Network Working Group                                       M. St. Johns
+Request for Comments: 1413                      US Department of Defense
+Obsoletes: 931                                             February 1993
+
+
+                        Identification Protocol
+
+Status of this Memo
+
+   This RFC specifies an IAB standards track protocol for the Internet
+   community, and requests discussion and suggestions for improvements.
+   Please refer to the current edition of the "IAB Official Protocol
+   Standards" for the standardization state and status of this protocol.
+   Distribution of this memo is unlimited.
+
+1.  INTRODUCTION
+
+   The Identification Protocol (a.k.a., "ident", a.k.a., "the Ident
+   Protocol") provides a means to determine the identity of a user of a
+   particular TCP connection.  Given a TCP port number pair, it returns
+   a character string which identifies the owner of that connection on
+   the server's system.
+
+   The Identification Protocol was formerly called the Authentication
+   Server Protocol.  It has been renamed to better reflect its function.
+   This document is a product of the TCP Client Identity Protocol
+   Working Group of the Internet Engineering Task Force (IETF).
+
+2.  OVERVIEW
+
+   This is a connection based application on TCP.  A server listens for
+   TCP connections on TCP port 113 (decimal).  Once a connection is
+   established, the server reads a line of data which specifies the
+   connection of interest.  If it exists, the system dependent user
+   identifier of the connection of interest is sent as the reply.  The
+   server may then either shut the connection down or it may continue to
+   read/respond to multiple queries.
+
+   The server should close the connection down after a configurable
+   amount of time with no queries - a 60-180 second idle timeout is
+   recommended.  The client may close the connection down at any time;
+   however to allow for network delays the client should wait at least
+   30 seconds (or longer) after a query before abandoning the query and
+   closing the connection.
+
+
+
+
+
+
+
+St. Johns                                                       [Page 1]
+\f
+RFC 1413                Identification Protocol            February 1993
+
+
+3.  RESTRICTIONS
+
+   Queries are permitted only for fully specified connections.  The
+   query contains the local/foreign port pair -- the local/foreign
+   address pair used to fully specify the connection is taken from the
+   local and foreign address of query connection.  This means a user on
+   address A may only query the server on address B about connections
+   between A and B.
+
+4.  QUERY/RESPONSE FORMAT
+
+   The server accepts simple text query requests of the form:
+
+            <port-on-server> , <port-on-client>
+
+   where <port-on-server> is the TCP port (decimal) on the target (where
+   the "ident" server is running) system, and <port-on-client> is the
+   TCP port (decimal) on the source (client) system.
+
+   N.B - If a client on host A wants to ask a server on host B about a
+   connection specified locally (on the client's machine) as 23, 6191
+   (an inbound TELNET connection), the client must actually ask about
+   6191, 23 - which is how the connection would be specified on host B.
+
+      For example:
+
+                 6191, 23
+
+   The response is of the form
+
+   <port-on-server> , <port-on-client> : <resp-type> : <add-info>
+
+   where <port-on-server>,<port-on-client> are the same pair as the
+   query, <resp-type> is a keyword identifying the type of response, and
+   <add-info> is context dependent.
+
+   The information returned is that associated with the fully specified
+   TCP connection identified by <server-address>, <client-address>,
+   <port-on-server>, <port-on-client>, where <server-address> and
+   <client-address> are the local and foreign IP addresses of the
+   querying connection -- i.e., the TCP connection to the Identification
+   Protocol Server.  (<port-on-server> and <port-on-client> are taken
+   from the query.)
+
+      For example:
+
+         6193, 23 : USERID : UNIX : stjohns
+         6195, 23 : ERROR : NO-USER
+
+
+
+St. Johns                                                       [Page 2]
+\f
+RFC 1413                Identification Protocol            February 1993
+
+
+5.  RESPONSE TYPES
+
+A response can be one of two types:
+
+USERID
+
+     In this case, <add-info> is a string consisting of an
+     operating system name (with an optional character set
+     identifier), followed by ":", followed by an
+     identification string.
+
+     The character set (if present) is separated from the
+     operating system name by ",".  The character set
+     identifier is used to indicate the character set of the
+     identification string.  The character set identifier,
+     if omitted, defaults to "US-ASCII" (see below).
+
+     Permitted operating system names and character set
+     names are specified in RFC 1340, "Assigned Numbers" or
+     its successors.
+
+     In addition to those operating system and character set
+     names specified in "Assigned Numbers" there is one
+     special case operating system identifier - "OTHER".
+
+     Unless "OTHER" is specified as the operating system
+     type, the server is expected to return the "normal"
+     user identification of the owner of this connection.
+     "Normal" in this context may be taken to mean a string
+     of characters which uniquely identifies the connection
+     owner such as a user identifier assigned by the system
+     administrator and used by such user as a mail
+     identifier, or as the "user" part of a user/password
+     pair used to gain access to system resources.  When an
+     operating system is specified (e.g., anything but
+     "OTHER"), the user identifier is expected to be in a
+     more or less immediately useful form - e.g., something
+     that could be used as an argument to "finger" or as a
+     mail address.
+
+     "OTHER" indicates the identifier is an unformatted
+     character string consisting of printable characters in
+     the specified character set.  "OTHER" should be
+     specified if the user identifier does not meet the
+     constraints of the previous paragraph.  Sending an
+     encrypted audit token, or returning other non-userid
+     information about a user (such as the real name and
+     phone number of a user from a UNIX passwd file) are
+
+
+
+St. Johns                                                       [Page 3]
+\f
+RFC 1413                Identification Protocol            February 1993
+
+
+     both examples of when "OTHER" should be used.
+
+     Returned user identifiers are expected to be printable
+     in the character set indicated.
+
+     The identifier is an unformatted octet string - - all
+     octets are permissible EXCEPT octal 000 (NUL), 012 (LF)
+     and 015 (CR).  N.B. - space characters (040) following the
+     colon separator ARE part of the identifier string and
+     may not be ignored. A response string is still
+     terminated normally by a CR/LF.  N.B. A string may be
+     printable, but is not *necessarily* printable.
+
+ERROR
+
+   For some reason the port owner could not be determined, <add-info>
+   tells why.  The following are the permitted values of <add-info> and
+   their meanings:
+
+          INVALID-PORT
+
+          Either the local or foreign port was improperly
+          specified.  This should be returned if either or
+          both of the port ids were out of range (TCP port
+          numbers are from 1-65535), negative integers, reals or
+          in any fashion not recognized as a non-negative
+          integer.
+
+          NO-USER
+
+          The connection specified by the port pair is not
+          currently in use or currently not owned by an
+          identifiable entity.
+
+          HIDDEN-USER
+
+          The server was able to identify the user of this
+          port, but the information was not returned at the
+          request of the user.
+
+          UNKNOWN-ERROR
+
+          Can't determine connection owner; reason unknown.
+          Any error not covered above should return this
+          error code value.  Optionally, this code MAY be
+          returned in lieu of any other specific error code
+          if, for example, the server desires to hide
+          information implied by the return of that error
+
+
+
+St. Johns                                                       [Page 4]
+\f
+RFC 1413                Identification Protocol            February 1993
+
+
+          code, or for any other reason.  If a server
+          implements such a feature, it MUST be configurable
+          and it MUST default to returning the proper error
+          message.
+
+   Other values may eventually be specified and defined in future
+   revisions to this document.  If an implementer has a need to specify
+   a non-standard error code, that code must begin with "X".
+
+   In addition, the server is allowed to drop the query connection
+   without responding.  Any premature close (i.e., one where the client
+   does not receive the EOL, whether graceful or an abort should be
+   considered to have the same meaning as "ERROR : UNKNOWN-ERROR".
+
+FORMAL SYNTAX
+
+   <request> ::= <port-pair> <EOL>
+
+   <port-pair> ::= <integer> "," <integer>
+
+   <reply> ::= <reply-text> <EOL>
+
+   <EOL> ::= "015 012"  ; CR-LF End of Line Indicator
+
+   <reply-text> ::= <error-reply> | <ident-reply>
+
+   <error-reply> ::= <port-pair> ":" "ERROR" ":" <error-type>
+
+   <ident-reply> ::= <port-pair> ":" "USERID" ":" <opsys-field>
+                     ":" <user-id>
+
+   <error-type> ::= "INVALID-PORT" | "NO-USER" | "UNKNOWN-ERROR"
+                    | "HIDDEN-USER" |  <error-token>
+
+   <opsys-field> ::= <opsys> [ "," <charset>]
+
+   <opsys> ::= "OTHER" | "UNIX" | <token> ...etc.
+               ;  (See "Assigned Numbers")
+
+   <charset> ::= "US-ASCII" | ...etc.
+                 ;  (See "Assigned Numbers")
+
+   <user-id> ::= <octet-string>
+
+   <token> ::= 1*64<token-characters> ; 1-64 characters
+
+   <error-token> ::= "X"1*63<token-characters>
+                     ; 2-64 chars beginning w/X
+
+
+
+St. Johns                                                       [Page 5]
+\f
+RFC 1413                Identification Protocol            February 1993
+
+
+   <integer> ::= 1*5<digit> ; 1-5 digits.
+
+   <digit> ::= "0" | "1" ... "8" | "9" ; 0-9
+
+   <token-characters> ::=
+                  <Any of these ASCII characters: a-z, A-Z,
+                   - (dash), .!@#$%^&*()_=+.,<>/?"'~`{}[]; >
+                               ; upper and lowercase a-z plus
+                               ; printables minus the colon ":"
+                               ; character.
+
+   <octet-string> ::= 1*512<octet-characters>
+
+   <octet-characters> ::=
+                  <any octet from  00 to 377 (octal) except for
+                   ASCII NUL (000), CR (015) and LF (012)>
+
+Notes on Syntax:
+
+   1)   To promote interoperability among variant
+        implementations, with respect to white space the above
+        syntax is understood to embody the "be conservative in
+        what you send and be liberal in what you accept"
+        philosophy.  Clients and servers should not generate
+        unnecessary white space (space and tab characters) but
+        should accept white space anywhere except within a
+        token.  In parsing responses, white space may occur
+        anywhere, except within a token.  Specifically, any
+        amount of white space is permitted at the beginning or
+        end of a line both for queries and responses.  This
+        does not apply for responses that contain a user ID
+        because everything after the colon after the operating
+        system type until the terminating CR/LF is taken as
+        part of the user ID.  The terminating CR/LF is NOT
+        considered part of the user ID.
+
+   2)   The above notwithstanding, servers should restrict the
+        amount of inter-token white space they send to the
+        smallest amount reasonable or useful.  Clients should
+        feel free to abort a connection if they receive 1000
+        characters without receiving an <EOL>.
+
+   3)   The 512 character limit on user IDs and the 64
+        character limit on tokens should be understood to mean
+        as follows: a) No new token (i.e., OPSYS or ERROR-TYPE)
+        token will be defined that has a length greater than 64
+        and b) a server SHOULD NOT send more than 512 octets of
+        user ID and a client MUST accept at least 512 octets of
+
+
+
+St. Johns                                                       [Page 6]
+\f
+RFC 1413                Identification Protocol            February 1993
+
+
+        user ID.  Because of this limitation, a server MUST
+        return the most significant portion of the user ID in
+        the first 512 octets.
+
+   4)   The character sets and character set identifiers should
+        map directly to those defined in or referenced by RFC 1340,
+        "Assigned Numbers" or its successors.  Character set
+        identifiers only apply to the user identification field
+        - all other fields will be defined in and must be sent
+        as US-ASCII.
+
+   5)   Although <user-id> is defined as an <octet-string>
+        above, it must follow the format and character set
+        constraints implied by the <opsys-field>; see the
+        discussion above.
+
+   6)   The character set provides context for the client to
+        print or store the returned user identification string.
+        If the client does not recognize or implement the
+        returned character set, it should handle the returned
+        identification string as OCTET, but should in addition
+        store or report the character set.  An OCTET string
+        should be printed, stored or handled in hex notation
+        (0-9a-f) in addition to any other representation the
+        client implements - this provides a standard
+        representation among differing implementations.
+
+6.  Security Considerations
+
+   The information returned by this protocol is at most as trustworthy
+   as the host providing it OR the organization operating the host.  For
+   example, a PC in an open lab has few if any controls on it to prevent
+   a user from having this protocol return any identifier the user
+   wants.  Likewise, if the host has been compromised the information
+   returned may be completely erroneous and misleading.
+
+   The Identification Protocol is not intended as an authorization or
+   access control protocol.  At best, it provides some additional
+   auditing information with respect to TCP connections.  At worst, it
+   can provide misleading, incorrect, or maliciously incorrect
+   information.
+
+   The use of the information returned by this protocol for other than
+   auditing is strongly discouraged.  Specifically, using Identification
+   Protocol information to make access control decisions - either as the
+   primary method (i.e., no other checks) or as an adjunct to other
+   methods may result in a weakening of normal host security.
+
+
+
+
+St. Johns                                                       [Page 7]
+\f
+RFC 1413                Identification Protocol            February 1993
+
+
+   An Identification server may reveal information about users,
+   entities, objects or processes which might normally be considered
+   private.  An Identification server provides service which is a rough
+   analog of the CallerID services provided by some phone companies and
+   many of the same privacy considerations and arguments that apply to
+   the CallerID service apply to Identification.  If you wouldn't run a
+   "finger" server due to privacy considerations you may not want to run
+   this protocol.
+
+7.  ACKNOWLEDGEMENTS
+
+   Acknowledgement is given to Dan Bernstein who is primarily
+   responsible for renewing interest in this protocol and for pointing
+   out some annoying errors in RFC 931.
+
+References
+
+   [1] St. Johns, M., "Authentication Server", RFC 931, TPSC, January
+       1985.
+
+   [2] Reynolds, J., and J. Postel, "Assigned Numbers", STD 2, RFC 1340,
+       USC/Information Sciences Institute, July 1992.
+
+Author's Address
+
+       Michael C. St. Johns
+       DARPA/CSTO
+       3701 N. Fairfax Dr
+       Arlington, VA 22203
+
+       Phone: (703) 696-2271
+       EMail: stjohns@DARPA.MIL
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+St. Johns                                                       [Page 8]
+\f
\ No newline at end of file
index c9300537701e1b8655939e5239b06c21c78d88d6..09fbf34f705d64889935478ee8a507b72f3b98b5 100644 (file)
@@ -1 +1,3643 @@
-\r\r\r\r\r\rNetwork Working Group                                      J. Oikarinen\rRequest for Comments: 1459                                      D. Reed\r                                                               May 1993\r\r\r                      Internet Relay Chat Protocol\r\rStatus of This Memo\r\r   This memo defines an Experimental Protocol for the Internet\r   community.  Discussion and suggestions for improvement are requested.\r   Please refer to the current edition of the "IAB Official Protocol\r   Standards" for the standardization state and status of this protocol.\r   Distribution of this memo is unlimited.\r\rAbstract\r\r   The IRC protocol was developed over the last 4 years since it was\r   first implemented as a means for users on a BBS to chat amongst\r   themselves.  Now it supports a world-wide network of servers and\r   clients, and is stringing to cope with growth. Over the past 2 years,\r   the average number of users connected to the main IRC network has\r   grown by a factor of 10.\r\r   The IRC protocol is a text-based protocol, with the simplest client\r   being any socket program capable of connecting to the server.\r\rTable of Contents\r\r   1.  INTRODUCTION ...............................................    4\r      1.1  Servers ................................................    4\r      1.2  Clients ................................................    5\r         1.2.1 Operators ..........................................    5\r      1.3 Channels ................................................    5\r      1.3.1  Channel Operators ....................................    6\r   2. THE IRC SPECIFICATION .......................................    7\r      2.1 Overview ................................................    7\r      2.2 Character codes .........................................    7\r      2.3 Messages ................................................    7\r         2.3.1  Message format in 'pseudo' BNF ....................    8\r      2.4 Numeric replies .........................................   10\r   3. IRC Concepts ................................................   10\r      3.1 One-to-one communication ................................   10\r      3.2 One-to-many .............................................   11\r         3.2.1 To a list ..........................................   11\r         3.2.2 To a group (channel) ...............................   11\r         3.2.3 To a host/server mask ..............................   12\r      3.3 One to all ..............................................   12\r\r\r\rOikarinen & Reed                                                [Page 1]\r\f\rRFC 1459              Internet Relay Chat Protocol              May 1993\r\r\r         3.3.1 Client to Client ...................................   12\r         3.3.2 Clients to Server ..................................   12\r         3.3.3 Server to Server ...................................   12\r   4. MESSAGE DETAILS .............................................   13\r      4.1 Connection Registration .................................   13\r         4.1.1 Password message ...................................   14\r         4.1.2 Nickname message ...................................   14\r         4.1.3 User message .......................................   15\r         4.1.4 Server message .....................................   16\r         4.1.5 Operator message ...................................   17\r         4.1.6 Quit message .......................................   17\r         4.1.7 Server Quit message ................................   18\r      4.2 Channel operations ......................................   19\r         4.2.1 Join message .......................................   19\r         4.2.2 Part message .......................................   20\r         4.2.3 Mode message .......................................   21\r            4.2.3.1 Channel modes .................................   21\r            4.2.3.2 User modes ....................................   22\r         4.2.4 Topic message ......................................   23\r         4.2.5 Names message ......................................   24\r         4.2.6 List message .......................................   24\r         4.2.7 Invite message .....................................   25\r         4.2.8 Kick message .......................................   25\r      4.3 Server queries and commands .............................   26\r         4.3.1 Version message ....................................   26\r         4.3.2 Stats message ......................................   27\r         4.3.3 Links message ......................................   28\r         4.3.4 Time message .......................................   29\r         4.3.5 Connect message ....................................   29\r         4.3.6 Trace message ......................................   30\r         4.3.7 Admin message ......................................   31\r         4.3.8 Info message .......................................   31\r      4.4 Sending messages ........................................   32\r         4.4.1 Private messages ...................................   32\r         4.4.2 Notice messages ....................................   33\r      4.5 User-based queries ......................................   33\r         4.5.1 Who query ..........................................   33\r         4.5.2 Whois query ........................................   34\r         4.5.3 Whowas message .....................................   35\r      4.6 Miscellaneous messages ..................................   35\r         4.6.1 Kill message .......................................   36\r         4.6.2 Ping message .......................................   37\r         4.6.3 Pong message .......................................   37\r         4.6.4 Error message ......................................   38\r   5. OPTIONAL MESSAGES ...........................................   38\r      5.1 Away message ............................................   38\r      5.2 Rehash command ..........................................   39\r      5.3 Restart command .........................................   39\r\r\r\rOikarinen & Reed                                                [Page 2]\r\f\rRFC 1459              Internet Relay Chat Protocol              May 1993\r\r\r      5.4 Summon message ..........................................   40\r      5.5 Users message ...........................................   40\r      5.6 Operwall command ........................................   41\r      5.7 Userhost message ........................................   42\r      5.8 Ison message ............................................   42\r   6. REPLIES .....................................................   43\r      6.1 Error Replies ...........................................   43\r      6.2 Command responses .......................................   48\r      6.3 Reserved numerics .......................................   56\r   7. Client and server authentication ............................   56\r   8. Current Implementations Details .............................   56\r      8.1 Network protocol: TCP ...................................   57\r         8.1.1 Support of Unix sockets ............................   57\r      8.2 Command Parsing .........................................   57\r      8.3 Message delivery ........................................   57\r      8.4 Connection 'Liveness' ...................................   58\r      8.5 Establishing a server-client connection .................   58\r      8.6 Establishing a server-server connection .................   58\r         8.6.1 State information exchange when connecting .........   59\r      8.7 Terminating server-client connections ...................   59\r      8.8 Terminating server-server connections ...................   59\r      8.9 Tracking nickname changes ...............................   60\r      8.10 Flood control of clients ...............................   60\r      8.11 Non-blocking lookups ...................................   61\r         8.11.1 Hostname (DNS) lookups ............................   61\r         8.11.2 Username (Ident) lookups ..........................   61\r      8.12 Configuration file .....................................   61\r         8.12.1 Allowing clients to connect .......................   62\r         8.12.2 Operators .........................................   62\r         8.12.3 Allowing servers to connect .......................   62\r         8.12.4 Administrivia .....................................   63\r      8.13 Channel membership .....................................   63\r   9. Current problems ............................................   63\r      9.1 Scalability .............................................   63\r      9.2 Labels ..................................................   63\r         9.2.1 Nicknames ..........................................   63\r         9.2.2 Channels ...........................................   64\r         9.2.3 Servers ............................................   64\r      9.3 Algorithms ..............................................   64\r   10. Support and availability ...................................   64\r   11. Security Considerations ....................................   65\r   12. Authors' Addresses .........................................   65\r\r\r\r\r\r\r\r\r\rOikarinen & Reed                                                [Page 3]\r\f\rRFC 1459              Internet Relay Chat Protocol              May 1993\r\r\r1.  INTRODUCTION\r\r   The IRC (Internet Relay Chat) protocol has been designed over a\r   number of years for use with text based conferencing.  This document\r   describes the current IRC protocol.\r\r   The IRC protocol has been developed on systems using the TCP/IP\r   network protocol, although there is no requirement that this remain\r   the only sphere in which it operates.\r\r   IRC itself is a teleconferencing system, which (through the use of\r   the client-server model) is well-suited to running on many machines\r   in a distributed fashion.  A typical setup involves a single process\r   (the server) forming a central point for clients (or other servers)\r   to connect to, performing the required message delivery/multiplexing\r   and other functions.\r\r1.1 Servers\r\r   The server forms the backbone of IRC, providing a point to which\r   clients may connect to to talk to each other, and a point for other\r   servers to connect to, forming an IRC network.  The only network\r   configuration allowed for IRC servers is that of a spanning tree [see\r   Fig. 1] where each server acts as a central node for the rest of the\r   net it sees.\r\r\r                           [ Server 15 ]  [ Server 13 ] [ Server 14]\r                                 /                \         /\r                                /                  \       /\r        [ Server 11 ] ------ [ Server 1 ]       [ Server 12]\r                              /        \          /\r                             /          \        /\r                  [ Server 2 ]          [ Server 3 ]\r                    /       \                      \\r                   /         \                      \\r           [ Server 4 ]    [ Server 5 ]         [ Server 6 ]\r            /    |    \                           /\r           /     |     \                         /\r          /      |      \____                   /\r         /       |           \                 /\r [ Server 7 ] [ Server 8 ] [ Server 9 ]   [ Server 10 ]\r\r                                  :\r                               [ etc. ]\r                                  :\r\r                 [ Fig. 1. Format of IRC server network ]\r\r\r\rOikarinen & Reed                                                [Page 4]\r\f\rRFC 1459              Internet Relay Chat Protocol              May 1993\r\r\r1.2 Clients\r\r   A client is anything connecting to a server that is not another\r   server.  Each client is distinguished from other clients by a unique\r   nickname having a maximum length of nine (9) characters.  See the\r   protocol grammar rules for what may and may not be used in a\r   nickname.  In addition to the nickname, all servers must have the\r   following information about all clients: the real name of the host\r   that the client is running on, the username of the client on that\r   host, and the server to which the client is connected.\r\r1.2.1 Operators\r\r   To allow a reasonable amount of order to be kept within the IRC\r   network, a special class of clients (operators) is allowed to perform\r   general maintenance functions on the network.  Although the powers\r   granted to an operator can be considered as 'dangerous', they are\r   nonetheless required.  Operators should be able to perform basic\r   network tasks such as disconnecting and reconnecting servers as\r   needed to prevent long-term use of bad network routing.  In\r   recognition of this need, the protocol discussed herein provides for\r   operators only to be able to perform such functions.  See sections\r   4.1.7 (SQUIT) and 4.3.5 (CONNECT).\r\r   A more controversial power of operators is the ability  to  remove  a\r   user  from  the connected network by 'force', i.e. operators are able\r   to close the connection between any client and server.   The\r   justification for  this  is delicate since its abuse is both\r   destructive and annoying.  For further details on this type of\r   action, see section 4.6.1 (KILL).\r\r1.3 Channels\r\r   A channel is a named group of one or more clients which will all\r   receive messages addressed to that channel.  The channel is created\r   implicitly when the first client joins it, and the channel ceases to\r   exist when the last client leaves it.  While channel exists, any\r   client can reference the channel using the name of the channel.\r\r   Channels names are strings (beginning with a '&' or '#' character) of\r   length up to 200 characters.  Apart from the the requirement that the\r   first character being either '&' or '#'; the only restriction on a\r   channel name is that it may not contain any spaces (' '), a control G\r   (^G or ASCII 7), or a comma (',' which is used as a list item\r   separator by the protocol).\r\r   There are two types of channels allowed by this protocol.  One is a\r   distributed channel which is known to all the servers that are\r\r\r\rOikarinen & Reed                                                [Page 5]\r\f\rRFC 1459              Internet Relay Chat Protocol              May 1993\r\r\r   connected to the network. These channels are marked by the first\r   character being a only clients on the server where it exists may join\r   it.  These are distinguished by a leading '&' character.  On top of\r   these two types, there are the various channel modes available to\r   alter the characteristics of individual channels.  See section 4.2.3\r   (MODE command) for more details on this.\r\r   To create a new channel or become part of an existing channel, a user\r   is required to JOIN the channel.  If the channel doesn't exist prior\r   to joining, the channel is created and the creating user becomes a\r   channel operator.  If the channel already exists, whether or not your\r   request to JOIN that channel is honoured depends on the current modes\r   of the channel. For example, if the channel is invite-only, (+i),\r   then you may only join if invited.  As part of the protocol, a user\r   may be a part of several channels at once, but a limit of ten (10)\r   channels is recommended as being ample for both experienced and\r   novice users.  See section 8.13 for more information on this.\r\r   If the IRC network becomes disjoint because of a split between two\r   servers, the channel on each side is only composed of those clients\r   which are connected to servers on the respective sides of the split,\r   possibly ceasing to exist on one side of the split.  When the split\r   is healed, the connecting servers announce to each other who they\r   think is in each channel and the mode of that channel.  If the\r   channel exists on both sides, the JOINs and MODEs are interpreted in\r   an inclusive manner so that both sides of the new connection will\r   agree about which clients are in the channel and what modes the\r   channel has.\r\r1.3.1 Channel Operators\r\r   The channel operator (also referred to as a "chop" or "chanop") on a\r   given channel is considered to 'own' that channel.  In recognition of\r   this status, channel operators are endowed with certain powers which\r   enable them to keep control and some sort of sanity in their channel.\r   As an owner of a channel, a channel operator is not required to have\r   reasons for their actions, although if their actions are generally\r   antisocial or otherwise abusive, it might be reasonable to ask an IRC\r   operator to intervene, or for the usersjust leave and go elsewhere\r   and form their own channel.\r\r   The commands which may only be used by channel operators are:\r\r        KICK    - Eject a client from the channel\r        MODE    - Change the channel's mode\r        INVITE  - Invite a client to an invite-only channel (mode +i)\r        TOPIC   - Change the channel topic in a mode +t channel\r\r\r\r\rOikarinen & Reed                                                [Page 6]\r\f\rRFC 1459              Internet Relay Chat Protocol              May 1993\r\r\r   A channel operator is identified by the '@' symbol next to their\r   nickname whenever it is associated with a channel (ie replies to the\r   NAMES, WHO and WHOIS commands).\r\r2. The IRC Specification\r\r2.1 Overview\r\r   The protocol as described herein is for use both with server to\r   server and client to server connections.  There are, however, more\r   restrictions on client connections (which are considered to be\r   untrustworthy) than on server connections.\r\r2.2 Character codes\r\r   No specific character set is specified. The protocol is based on a a\r   set of codes which are composed of eight (8) bits, making up an\r   octet.  Each message may be composed of any number of these octets;\r   however, some octet values are used for control codes which act as\r   message delimiters.\r\r   Regardless of being an 8-bit protocol, the delimiters and keywords\r   are such that protocol is mostly usable from USASCII terminal and a\r   telnet connection.\r\r   Because of IRC's scandanavian origin, the characters {}| are\r   considered to be the lower case equivalents of the characters []\,\r   respectively. This is a critical issue when determining the\r   equivalence of two nicknames.\r\r2.3 Messages\r\r   Servers and clients send eachother messages which may or may not\r   generate a reply.  If the message contains a valid command, as\r   described in later sections, the client should expect a reply as\r   specified but it is not advised to wait forever for the reply; client\r   to server and server to server communication is essentially\r   asynchronous in nature.\r\r   Each IRC message may consist of up to three main parts: the prefix\r   (optional), the command, and the command parameters (of which there\r   may be up to 15).  The prefix, command, and all parameters are\r   separated by one (or more) ASCII space character(s) (0x20).\r\r   The presence of a prefix is indicated with a single leading ASCII\r   colon character (':', 0x3b), which must be the first character of the\r   message itself.  There must be no gap (whitespace) between the colon\r   and the prefix.  The prefix is used by servers to indicate the true\r\r\r\rOikarinen & Reed                                                [Page 7]\r\f\rRFC 1459              Internet Relay Chat Protocol              May 1993\r\r\r   origin of the message.  If the prefix is missing from the message, it\r   is assumed to have originated from the connection from which it was\r   received.  Clients should not use prefix when sending a message from\r   themselves; if they use a prefix, the only valid prefix is the\r   registered nickname associated with the client.  If the source\r   identified by the prefix cannot be found from the server's internal\r   database, or if the source is registered from a different link than\r   from which the message arrived, the server must ignore the message\r   silently.\r\r   The command must either be a valid IRC command or a three (3) digit\r   number represented in ASCII text.\r\r   IRC messages are always lines of characters terminated with a CR-LF\r   (Carriage Return - Line Feed) pair, and these messages shall not\r   exceed 512 characters in length, counting all characters including\r   the trailing CR-LF. Thus, there are 510 characters maximum allowed\r   for the command and its parameters.  There is no provision for\r   continuation message lines.  See section 7 for more details about\r   current implementations.\r\r2.3.1 Message format in 'pseudo' BNF\r\r   The protocol messages must be extracted from the contiguous stream of\r   octets.  The current solution is to designate two characters, CR and\r   LF, as message separators.   Empty  messages  are  silently  ignored,\r   which permits  use  of  the  sequence  CR-LF  between  messages\r   without extra problems.\r\r   The extracted message is parsed into the components <prefix>,\r   <command> and list of parameters matched either by <middle> or\r   <trailing> components.\r\r   The BNF representation for this is:\r\r\r<message>  ::= [':' <prefix> <SPACE> ] <command> <params> <crlf>\r<prefix>   ::= <servername> | <nick> [ '!' <user> ] [ '@' <host> ]\r<command>  ::= <letter> { <letter> } | <number> <number> <number>\r<SPACE>    ::= ' ' { ' ' }\r<params>   ::= <SPACE> [ ':' <trailing> | <middle> <params> ]\r\r<middle>   ::= <Any *non-empty* sequence of octets not including SPACE\r               or NUL or CR or LF, the first of which may not be ':'>\r<trailing> ::= <Any, possibly *empty*, sequence of octets not including\r                 NUL or CR or LF>\r\r<crlf>     ::= CR LF\r\r\r\rOikarinen & Reed                                                [Page 8]\r\f\rRFC 1459              Internet Relay Chat Protocol              May 1993\r\r\rNOTES:\r\r  1)    <SPACE> is consists only of SPACE character(s) (0x20).\r        Specially notice that TABULATION, and all other control\r        characters are considered NON-WHITE-SPACE.\r\r  2)    After extracting the parameter list, all parameters are equal,\r        whether matched by <middle> or <trailing>. <Trailing> is just\r        a syntactic trick to allow SPACE within parameter.\r\r  3)    The fact that CR and LF cannot appear in parameter strings is\r        just artifact of the message framing. This might change later.\r\r  4)    The NUL character is not special in message framing, and\r        basically could end up inside a parameter, but as it would\r        cause extra complexities in normal C string handling. Therefore\r        NUL is not allowed within messages.\r\r  5)    The last parameter may be an empty string.\r\r  6)    Use of the extended prefix (['!' <user> ] ['@' <host> ]) must\r        not be used in server to server communications and is only\r        intended for server to client messages in order to provide\r        clients with more useful information about who a message is\r        from without the need for additional queries.\r\r   Most protocol messages specify additional semantics and syntax for\r   the extracted parameter strings dictated by their position in the\r   list.  For example, many server commands will assume that the first\r   parameter after the command is the list of targets, which can be\r   described with:\r\r   <target>     ::= <to> [ "," <target> ]\r   <to>         ::= <channel> | <user> '@' <servername> | <nick> | <mask>\r   <channel>    ::= ('#' | '&') <chstring>\r   <servername> ::= <host>\r   <host>       ::= see RFC 952 [DNS:4] for details on allowed hostnames\r   <nick>       ::= <letter> { <letter> | <number> | <special> }\r   <mask>       ::= ('#' | '$') <chstring>\r   <chstring>   ::= <any 8bit code except SPACE, BELL, NUL, CR, LF and\r                     comma (',')>\r\r   Other parameter syntaxes are:\r\r   <user>       ::= <nonwhite> { <nonwhite> }\r   <letter>     ::= 'a' ... 'z' | 'A' ... 'Z'\r   <number>     ::= '0' ... '9'\r   <special>    ::= '-' | '[' | ']' | '\' | '`' | '^' | '{' | '}'\r\r\r\rOikarinen & Reed                                                [Page 9]\r\f\rRFC 1459              Internet Relay Chat Protocol              May 1993\r\r\r   <nonwhite>   ::= <any 8bit code except SPACE (0x20), NUL (0x0), CR\r                     (0xd), and LF (0xa)>\r\r2.4 Numeric replies\r\r   Most of the messages sent to the server generate a reply of some\r   sort.  The most common reply is the numeric reply, used for both\r   errors and normal replies.  The numeric reply must be sent as one\r   message consisting of the sender prefix, the three digit numeric, and\r   the target of the reply.  A numeric reply is not allowed to originate\r   from a client; any such messages received by a server are silently\r   dropped. In all other respects, a numeric reply is just like a normal\r   message, except that the keyword is made up of 3 numeric digits\r   rather than a string of letters.  A list of different replies is\r   supplied in section 6.\r\r3. IRC Concepts.\r\r   This section is devoted to describing the actual concepts behind  the\r   organization  of  the  IRC  protocol and how the current\r   implementations deliver different classes of messages.\r\r\r\r                          1--\\r                              A        D---4\r                          2--/ \      /\r                                B----C\r                               /      \\r                              3        E\r\r   Servers: A, B, C, D, E         Clients: 1, 2, 3, 4\r\r                    [ Fig. 2. Sample small IRC network ]\r\r3.1 One-to-one communication\r\r   Communication on a one-to-one basis is usually only performed by\r   clients, since most server-server traffic is not a result of servers\r   talking only to each other.  To provide a secure means for clients to\r   talk to each other, it is required that all servers be able to send a\r   message in exactly one direction along the spanning tree in order to\r   reach any client.  The path of a message being delivered is the\r   shortest path between any two points on the spanning tree.\r\r   The following examples all refer to Figure 2 above.\r\r\r\r\r\rOikarinen & Reed                                               [Page 10]\r\f\rRFC 1459              Internet Relay Chat Protocol              May 1993\r\r\rExample 1:\r     A message between clients 1 and 2 is only seen by server A, which\r     sends it straight to client 2.\r\rExample 2:\r     A message between clients 1 and 3 is seen by servers A & B, and\r     client 3.  No other clients or servers are allowed see the message.\r\rExample 3:\r     A message between clients 2 and 4 is seen by servers A, B, C & D\r     and client 4 only.\r\r3.2 One-to-many\r\r   The main goal of IRC is to provide a  forum  which  allows  easy  and\r   efficient  conferencing (one to many conversations).  IRC offers\r   several means to achieve this, each serving its own purpose.\r\r3.2.1 To a list\r\r   The least efficient style of one-to-many conversation is through\r   clients talking to a 'list' of users.  How this is done is almost\r   self explanatory: the client gives a list of destinations to which\r   the message is to be delivered and the server breaks it up and\r   dispatches a separate copy of the message to each given destination.\r   This isn't as efficient as using a group since the destination list\r   is broken up and the dispatch sent without checking to make sure\r   duplicates aren't sent down each path.\r\r3.2.2 To a group (channel)\r\r   In IRC the channel has a role equivalent to that of the multicast\r   group; their existence is dynamic (coming and going as people join\r   and leave channels) and the actual conversation carried out on a\r   channel is only sent to servers which are supporting users on a given\r   channel.  If there are multiple users on a server in the same\r   channel, the message text is sent only once to that server and then\r   sent to each client on the channel.  This action is then repeated for\r   each client-server combination until the original message has fanned\r   out and reached each member of the channel.\r\r   The following examples all refer to Figure 2.\r\rExample 4:\r     Any channel with 1 client in it. Messages to the channel go to the\r     server and then nowhere else.\r\r\r\r\r\rOikarinen & Reed                                               [Page 11]\r\f\rRFC 1459              Internet Relay Chat Protocol              May 1993\r\r\rExample 5:\r     2 clients in a channel. All messages traverse a path as if they\r     were private messages between the two clients outside a channel.\r\rExample 6:\r     Clients 1, 2 and 3 in a channel.  All messages to the channel are\r     sent to all clients and only those servers which must be traversed\r     by the message if it were a private message to a single client.  If\r     client 1 sends a message, it goes back to client 2 and then via\r     server B to client 3.\r\r3.2.3 To a host/server mask\r\r   To provide IRC operators with some mechanism to send  messages  to  a\r   large body of related users, host and server mask messages are\r   provided.  These messages are sent to users whose host or server\r   information  match that  of  the mask.  The messages are only sent to\r   locations where users are, in a fashion similar to that of channels.\r\r3.3 One-to-all\r\r   The one-to-all type of message is better described as a broadcast\r   message, sent to all clients or servers or both.  On a large network\r   of users and servers, a single message can result in a lot of traffic\r   being sent over the network in an effort to reach all of the desired\r   destinations.\r\r   For some messages, there is no option but to broadcast it to all\r   servers so that the state information held by each server is\r   reasonably consistent between servers.\r\r3.3.1 Client-to-Client\r\r   There is no class of message which, from a single message, results in\r   a message being sent to every other client.\r\r3.3.2 Client-to-Server\r\r   Most of the commands which result in a change of state information\r   (such as channel membership, channel mode, user status, etc) must be\r   sent to all servers by default, and this distribution may not be\r   changed by the client.\r\r3.3.3 Server-to-Server.\r\r   While most messages between servers are distributed to all 'other'\r   servers, this is only required for any message that affects either a\r   user, channel or server.  Since these are the basic items found in\r\r\r\rOikarinen & Reed                                               [Page 12]\r\f\rRFC 1459              Internet Relay Chat Protocol              May 1993\r\r\r   IRC, nearly all messages originating from a server are broadcast to\r   all other connected servers.\r\r4. Message details\r\r   On the following pages are descriptions of each message recognized by\r   the IRC server and client.  All commands described in this section\r   must be implemented by any server for this protocol.\r\r   Where the reply ERR_NOSUCHSERVER is listed, it means that the\r   <server> parameter could not be found.  The server must not send any\r   other replies after this for that command.\r\r   The server to which a client is connected is required to parse the\r   complete message, returning any appropriate errors.  If the server\r   encounters a fatal error while parsing a message, an error must be\r   sent back to the client and the parsing terminated.  A fatal error\r   may be considered to be incorrect command, a destination which is\r   otherwise unknown to the server (server, nick or channel names fit\r   this category), not enough parameters or incorrect privileges.\r\r   If a full set of parameters is presented, then each must be checked\r   for validity and appropriate responses sent back to the client.  In\r   the case of messages which use parameter lists using the comma as an\r   item separator, a reply must be sent for each item.\r\r   In the examples below, some messages appear using the full format:\r\r   :Name COMMAND parameter list\r\r   Such examples represent a message from "Name" in transit between\r   servers, where it is essential to include the name of the original\r   sender of the message so remote servers may send back a reply along\r   the correct path.\r\r4.1 Connection Registration\r\r   The commands described here are used to register a connection with an\r   IRC server as either a user or a server as well as correctly\r   disconnect.\r\r   A "PASS" command is not required for either client or server\r   connection to be registered, but it must precede the server message\r   or the latter of the NICK/USER combination.  It is strongly\r   recommended that all server connections have a password in order to\r   give some level of security to the actual connections.  The\r   recommended order for a client to register is as follows:\r\r\r\r\rOikarinen & Reed                                               [Page 13]\r\f\rRFC 1459              Internet Relay Chat Protocol              May 1993\r\r\r           1. Pass message\r           2. Nick message\r           3. User message\r\r4.1.1 Password message\r\r\r      Command: PASS\r   Parameters: <password>\r\r   The PASS command is used to set a 'connection password'.  The\r   password can and must be set before any attempt to register the\r   connection is made.  Currently this requires that clients send a PASS\r   command before sending the NICK/USER combination and servers *must*\r   send a PASS command before any SERVER command.  The password supplied\r   must match the one contained in the C/N lines (for servers) or I\r   lines (for clients).  It is possible to send multiple PASS commands\r   before registering but only the last one sent is used for\r   verification and it may not be changed once registered.  Numeric\r   Replies:\r\r           ERR_NEEDMOREPARAMS              ERR_ALREADYREGISTRED\r\r   Example:\r\r           PASS secretpasswordhere\r\r4.1.2 Nick message\r\r      Command: NICK\r   Parameters: <nickname> [ <hopcount> ]\r\r   NICK message is used to give user a nickname or change the previous\r   one.  The <hopcount> parameter is only used by servers to indicate\r   how far away a nick is from its home server.  A local connection has\r   a hopcount of 0.  If supplied by a client, it must be ignored.\r\r   If a NICK message arrives at a server which already knows about an\r   identical nickname for another client, a nickname collision occurs.\r   As a result of a nickname collision, all instances of the nickname\r   are removed from the server's database, and a KILL command is issued\r   to remove the nickname from all other server's database. If the NICK\r   message causing the collision was a nickname change, then the\r   original (old) nick must be removed as well.\r\r   If the server recieves an identical NICK from a client which is\r   directly connected, it may issue an ERR_NICKCOLLISION to the local\r   client, drop the NICK command, and not generate any kills.\r\r\r\rOikarinen & Reed                                               [Page 14]\r\f\rRFC 1459              Internet Relay Chat Protocol              May 1993\r\r\r   Numeric Replies:\r\r           ERR_NONICKNAMEGIVEN             ERR_ERRONEUSNICKNAME\r           ERR_NICKNAMEINUSE               ERR_NICKCOLLISION\r\r   Example:\r\r   NICK Wiz                        ; Introducing new nick "Wiz".\r\r   :WiZ NICK Kilroy                ; WiZ changed his nickname to Kilroy.\r\r4.1.3 User message\r\r      Command: USER\r   Parameters: <username> <hostname> <servername> <realname>\r\r   The USER message is used at the beginning of connection to specify\r   the username, hostname, servername and realname of s new user.  It is\r   also used in communication between servers to indicate new user\r   arriving on IRC, since only after both USER and NICK have been\r   received from a client does a user become registered.\r\r   Between servers USER must to be prefixed with client's NICKname.\r   Note that hostname and servername are normally ignored by the IRC\r   server when the USER command comes from a directly connected client\r   (for security reasons), but they are used in server to server\r   communication.  This means that a NICK must always be sent to a\r   remote server when a new user is being introduced to the rest of the\r   network before the accompanying USER is sent.\r\r   It must be noted that realname parameter must be the last parameter,\r   because it may contain space characters and must be prefixed with a\r   colon (':') to make sure this is recognised as such.\r\r   Since it is easy for a client to lie about its username by relying\r   solely on the USER message, the use of an "Identity Server" is\r   recommended.  If the host which a user connects from has such a\r   server enabled the username is set to that as in the reply from the\r   "Identity Server".\r\r   Numeric Replies:\r\r           ERR_NEEDMOREPARAMS              ERR_ALREADYREGISTRED\r\r   Examples:\r\r\r   USER guest tolmoon tolsun :Ronnie Reagan\r\r\r\rOikarinen & Reed                                               [Page 15]\r\f\rRFC 1459              Internet Relay Chat Protocol              May 1993\r\r\r                                   ; User registering themselves with a\r                                   username of "guest" and real name\r                                   "Ronnie Reagan".\r\r\r   :testnick USER guest tolmoon tolsun :Ronnie Reagan\r                                   ; message between servers with the\r                                   nickname for which the USER command\r                                   belongs to\r\r4.1.4 Server message\r\r      Command: SERVER\r   Parameters: <servername> <hopcount> <info>\r\r   The server message is used to tell a server that the other end of a\r   new connection is a server. This message is also used to pass server\r   data over whole net.  When a new server is connected to net,\r   information about it be broadcast to the whole network.  <hopcount>\r   is used to give all servers some internal information on how far away\r   all servers are.  With a full server list, it would be possible to\r   construct a map of the entire server tree, but hostmasks prevent this\r   from being done.\r\r   The SERVER message must only be accepted from either (a) a connection\r   which is yet to be registered and is attempting to register as a\r   server, or (b) an existing connection to another server, in  which\r   case the SERVER message is introducing a new server behind that\r   server.\r\r   Most errors that occur with the receipt of a SERVER command result in\r   the connection being terminated by the destination host (target\r   SERVER).  Error replies are usually sent using the "ERROR" command\r   rather than the numeric since the ERROR command has several useful\r   properties which make it useful here.\r\r   If a SERVER message is parsed and attempts to introduce a server\r   which is already known to the receiving server, the connection from\r   which that message must be closed (following the correct procedures),\r   since a duplicate route to a server has formed and the acyclic nature\r   of the IRC tree broken.\r\r   Numeric Replies:\r\r           ERR_ALREADYREGISTRED\r\r   Example:\r\r\r\r\rOikarinen & Reed                                               [Page 16]\r\f\rRFC 1459              Internet Relay Chat Protocol              May 1993\r\r\rSERVER test.oulu.fi 1 :[tolsun.oulu.fi] Experimental server\r                                ; New server test.oulu.fi introducing\r                                itself and attempting to register.  The\r                                name in []'s is the hostname for the\r                                host running test.oulu.fi.\r\r\r:tolsun.oulu.fi SERVER csd.bu.edu 5 :BU Central Server\r                                ; Server tolsun.oulu.fi is our uplink\r                                for csd.bu.edu which is 5 hops away.\r\r4.1.5 Oper\r\r      Command: OPER\r   Parameters: <user> <password>\r\r   OPER message is used by a normal user to obtain operator privileges.\r   The combination of <user> and <password> are required to gain\r   Operator privileges.\r\r   If the client sending the OPER command supplies the correct password\r   for the given user, the server then informs the rest of the network\r   of the new operator by issuing a "MODE +o" for the clients nickname.\r\r   The OPER message is client-server only.\r\r   Numeric Replies:\r\r           ERR_NEEDMOREPARAMS              RPL_YOUREOPER\r           ERR_NOOPERHOST                  ERR_PASSWDMISMATCH\r\r   Example:\r\r   OPER foo bar                    ; Attempt to register as an operator\r                                   using a username of "foo" and "bar" as\r                                   the password.\r\r4.1.6 Quit\r\r      Command: QUIT\r   Parameters: [<Quit message>]\r\r   A client session is ended with a quit message.  The server must close\r   the connection to a client which sends a QUIT message. If a "Quit\r   Message" is given, this will be sent instead of the default message,\r   the nickname.\r\r   When netsplits (disconnecting of two servers) occur, the quit message\r\r\r\rOikarinen & Reed                                               [Page 17]\r\f\rRFC 1459              Internet Relay Chat Protocol              May 1993\r\r\r   is composed of the names of two servers involved, separated by a\r   space.  The first name is that of the server which is still connected\r   and the second name is that of the server that has become\r   disconnected.\r\r   If, for some other reason, a client connection is closed without  the\r   client  issuing  a  QUIT  command  (e.g.  client  dies and EOF occurs\r   on socket), the server is required to fill in the quit  message  with\r   some sort  of  message  reflecting the nature of the event which\r   caused it to happen.\r\r   Numeric Replies:\r\r           None.\r\r   Examples:\r\r   QUIT :Gone to have lunch        ; Preferred message format.\r\r4.1.7 Server quit message\r\r      Command: SQUIT\r   Parameters: <server> <comment>\r\r   The SQUIT message is needed to tell about quitting or dead servers.\r   If a server wishes to break the connection to another server it must\r   send a SQUIT message to the other server, using the the name of the\r   other server as the server parameter, which then closes its\r   connection to the quitting server.\r\r   This command is also available operators to help keep a network of\r   IRC servers connected in an orderly fashion.  Operators may also\r   issue an SQUIT message for a remote server connection.  In this case,\r   the SQUIT must be parsed by each server inbetween the operator and\r   the remote server, updating the view of the network held by each\r   server as explained below.\r\r   The <comment> should be supplied by all operators who execute a SQUIT\r   for a remote server (that is not connected to the server they are\r   currently on) so that other operators are aware for the reason of\r   this action.  The <comment> is also filled in by servers which may\r   place an error or similar message here.\r\r   Both of the servers which are on either side of the connection being\r   closed are required to to send out a SQUIT message (to all its other\r   server connections) for all other servers which are considered to be\r   behind that link.\r\r\r\r\rOikarinen & Reed                                               [Page 18]\r\f\rRFC 1459              Internet Relay Chat Protocol              May 1993\r\r\r   Similarly, a QUIT message must be sent to the other connected servers\r   rest of the network on behalf of all clients behind that link.  In\r   addition to this, all channel members of a channel which lost a\r   member due to the split must be sent a QUIT message.\r\r   If a server connection is terminated prematurely (e.g. the server  on\r   the  other  end  of  the  link  died),  the  server  which  detects\r   this disconnection is required to inform the rest of  the  network\r   that  the connection  has  closed  and  fill  in  the comment field\r   with something appropriate.\r\r   Numeric replies:\r\r           ERR_NOPRIVILEGES                ERR_NOSUCHSERVER\r\r   Example:\r\r   SQUIT tolsun.oulu.fi :Bad Link ? ; the server link tolson.oulu.fi has\r                                   been terminated because of "Bad Link".\r\r   :Trillian SQUIT cm22.eng.umd.edu :Server out of control\r                                    ; message from Trillian to disconnect\r                                   "cm22.eng.umd.edu" from the net\r                                    because "Server out of control".\r\r4.2 Channel operations\r\r   This group of messages is concerned with manipulating channels, their\r   properties (channel modes), and their contents (typically clients).\r   In implementing these, a number of race conditions are inevitable\r   when clients at opposing ends of a network send commands which will\r   ultimately clash.  It is also required that servers keep a nickname\r   history to ensure that wherever a <nick> parameter is given, the\r   server check its history in case it has recently been changed.\r\r4.2.1 Join message\r\r      Command: JOIN\r   Parameters: <channel>{,<channel>} [<key>{,<key>}]\r\r   The JOIN command is used by client to start listening a specific\r   channel. Whether or not a client is allowed to join a channel is\r   checked only by the server the client is connected to; all other\r   servers automatically add the user to the channel when it is received\r   from other servers.  The conditions which affect this are as follows:\r\r           1.  the user must be invited if the channel is invite-only;\r\r\r\r\rOikarinen & Reed                                               [Page 19]\r\f\rRFC 1459              Internet Relay Chat Protocol              May 1993\r\r\r           2.  the user's nick/username/hostname must not match any\r               active bans;\r\r           3.  the correct key (password) must be given if it is set.\r\r   These are discussed in more detail under the MODE command (see\r   section 4.2.3 for more details).\r\r   Once a user has joined a channel, they receive notice about all\r   commands their server receives which affect the channel.  This\r   includes MODE, KICK, PART, QUIT and of course PRIVMSG/NOTICE.  The\r   JOIN command needs to be broadcast to all servers so that each server\r   knows where to find the users who are on the channel.  This allows\r   optimal delivery of PRIVMSG/NOTICE messages to the channel.\r\r   If a JOIN is successful, the user is then sent the channel's topic\r   (using RPL_TOPIC) and the list of users who are on the channel (using\r   RPL_NAMREPLY), which must include the user joining.\r\r   Numeric Replies:\r\r           ERR_NEEDMOREPARAMS              ERR_BANNEDFROMCHAN\r           ERR_INVITEONLYCHAN              ERR_BADCHANNELKEY\r           ERR_CHANNELISFULL               ERR_BADCHANMASK\r           ERR_NOSUCHCHANNEL               ERR_TOOMANYCHANNELS\r           RPL_TOPIC\r\r   Examples:\r\r   JOIN #foobar                    ; join channel #foobar.\r\r   JOIN &foo fubar                 ; join channel &foo using key "fubar".\r\r   JOIN #foo,&bar fubar            ; join channel #foo using key "fubar"\r                                   and &bar using no key.\r\r   JOIN #foo,#bar fubar,foobar     ; join channel #foo using key "fubar".\r                                   and channel #bar using key "foobar".\r\r   JOIN #foo,#bar                  ; join channels #foo and #bar.\r\r   :WiZ JOIN #Twilight_zone        ; JOIN message from WiZ\r\r4.2.2 Part message\r\r      Command: PART\r   Parameters: <channel>{,<channel>}\r\r\r\r\rOikarinen & Reed                                               [Page 20]\r\f\rRFC 1459              Internet Relay Chat Protocol              May 1993\r\r\r   The PART message causes the client sending the message to be removed\r   from the list of active users for all given channels listed in the\r   parameter string.\r\r   Numeric Replies:\r\r           ERR_NEEDMOREPARAMS              ERR_NOSUCHCHANNEL\r           ERR_NOTONCHANNEL\r\r   Examples:\r\r   PART #twilight_zone             ; leave channel "#twilight_zone"\r\r   PART #oz-ops,&group5            ; leave both channels "&group5" and\r                                   "#oz-ops".\r\r4.2.3 Mode message\r\r      Command: MODE\r\r   The MODE command is a dual-purpose command in IRC.  It allows both\r   usernames and channels to have their mode changed.  The rationale for\r   this choice is that one day nicknames will be obsolete and the\r   equivalent property will be the channel.\r\r   When parsing MODE messages, it is recommended that the entire message\r   be parsed first and then the changes which resulted then passed on.\r\r4.2.3.1 Channel modes\r\r   Parameters: <channel> {[+|-]|o|p|s|i|t|n|b|v} [<limit>] [<user>]\r               [<ban mask>]\r\r   The MODE command is provided so that channel operators may change the\r   characteristics of `their' channel.  It is also required that servers\r   be able to change channel modes so that channel operators may be\r   created.\r\r   The various modes available for channels are as follows:\r\r           o - give/take channel operator privileges;\r           p - private channel flag;\r           s - secret channel flag;\r           i - invite-only channel flag;\r           t - topic settable by channel operator only flag;\r           n - no messages to channel from clients on the outside;\r           m - moderated channel;\r           l - set the user limit to channel;\r\r\r\rOikarinen & Reed                                               [Page 21]\r\f\rRFC 1459              Internet Relay Chat Protocol              May 1993\r\r\r           b - set a ban mask to keep users out;\r           v - give/take the ability to speak on a moderated channel;\r           k - set a channel key (password).\r\r   When using the 'o' and 'b' options, a restriction on a total of three\r   per mode command has been imposed.  That is, any combination of 'o'\r   and\r\r4.2.3.2 User modes\r\r   Parameters: <nickname> {[+|-]|i|w|s|o}\r\r   The user MODEs are typically changes which affect either how the\r   client is seen by others or what 'extra' messages the client is sent.\r   A user MODE command may only be accepted if both the sender of the\r   message and the nickname given as a parameter are both the same.\r\r   The available modes are as follows:\r\r           i - marks a users as invisible;\r           s - marks a user for receipt of server notices;\r           w - user receives wallops;\r           o - operator flag.\r\r   Additional modes may be available later on.\r\r   If a user attempts to make themselves an operator using the "+o"\r   flag, the attempt should be ignored.  There is no restriction,\r   however, on anyone `deopping' themselves (using "-o").  Numeric\r   Replies:\r\r           ERR_NEEDMOREPARAMS              RPL_CHANNELMODEIS\r           ERR_CHANOPRIVSNEEDED            ERR_NOSUCHNICK\r           ERR_NOTONCHANNEL                ERR_KEYSET\r           RPL_BANLIST                     RPL_ENDOFBANLIST\r           ERR_UNKNOWNMODE                 ERR_NOSUCHCHANNEL\r\r           ERR_USERSDONTMATCH              RPL_UMODEIS\r           ERR_UMODEUNKNOWNFLAG\r\r   Examples:\r\r           Use of Channel Modes:\r\rMODE #Finnish +im               ; Makes #Finnish channel moderated and\r                                'invite-only'.\r\rMODE #Finnish +o Kilroy         ; Gives 'chanop' privileges to Kilroy on\r\r\r\rOikarinen & Reed                                               [Page 22]\r\f\rRFC 1459              Internet Relay Chat Protocol              May 1993\r\r\r                                channel #Finnish.\r\rMODE #Finnish +v Wiz            ; Allow WiZ to speak on #Finnish.\r\rMODE #Fins -s                   ; Removes 'secret' flag from channel\r                                #Fins.\r\rMODE #42 +k oulu                ; Set the channel key to "oulu".\r\rMODE #eu-opers +l 10            ; Set the limit for the number of users\r                                on channel to 10.\r\rMODE &oulu +b                   ; list ban masks set for channel.\r\rMODE &oulu +b *!*@*             ; prevent all users from joining.\r\rMODE &oulu +b *!*@*.edu         ; prevent any user from a hostname\r                                matching *.edu from joining.\r\r        Use of user Modes:\r\r:MODE WiZ -w                    ; turns reception of WALLOPS messages\r                                off for WiZ.\r\r:Angel MODE Angel +i            ; Message from Angel to make themselves\r                                invisible.\r\rMODE WiZ -o                     ; WiZ 'deopping' (removing operator\r                                status).  The plain reverse of this\r                                command ("MODE WiZ +o") must not be\r                                allowed from users since would bypass\r                                the OPER command.\r\r4.2.4 Topic message\r\r      Command: TOPIC\r   Parameters: <channel> [<topic>]\r\r   The TOPIC message is used to change or view the topic of a channel.\r   The topic for channel <channel> is returned if there is no <topic>\r   given.  If the <topic> parameter is present, the topic for that\r   channel will be changed, if the channel modes permit this action.\r\r   Numeric Replies:\r\r           ERR_NEEDMOREPARAMS              ERR_NOTONCHANNEL\r           RPL_NOTOPIC                     RPL_TOPIC\r           ERR_CHANOPRIVSNEEDED\r\r\r\rOikarinen & Reed                                               [Page 23]\r\f\rRFC 1459              Internet Relay Chat Protocol              May 1993\r\r\r   Examples:\r\r   :Wiz TOPIC #test :New topic     ;User Wiz setting the topic.\r\r   TOPIC #test :another topic      ;set the topic on #test to "another\r                                   topic".\r\r   TOPIC #test                     ; check the topic for #test.\r\r4.2.5 Names message\r\r      Command: NAMES\r   Parameters: [<channel>{,<channel>}]\r\r   By using the NAMES command, a user can list all nicknames that are\r   visible to them on any channel that they can see.  Channel names\r   which they can see are those which aren't private (+p) or secret (+s)\r   or those which they are actually on.  The <channel> parameter\r   specifies which channel(s) to return information about if valid.\r   There is no error reply for bad channel names.\r\r   If no <channel> parameter is given, a list of all channels and their\r   occupants is returned.  At the end of this list, a list of users who\r   are visible but either not on any channel or not on a visible channel\r   are listed as being on `channel' "*".\r\r   Numerics:\r\r           RPL_NAMREPLY                    RPL_ENDOFNAMES\r\r   Examples:\r\r   NAMES #twilight_zone,#42        ; list visible users on #twilight_zone\r                                   and #42 if the channels are visible to\r                                   you.\r\r   NAMES                           ; list all visible channels and users\r\r4.2.6 List message\r\r      Command: LIST\r   Parameters: [<channel>{,<channel>} [<server>]]\r\r   The list message is used to list channels and their topics.  If  the\r   <channel>  parameter  is  used,  only  the  status  of  that  channel\r   is displayed.  Private  channels  are  listed  (without  their\r   topics)  as channel "Prv" unless the client generating the query is\r   actually on that channel.  Likewise, secret channels are not listed\r\r\r\rOikarinen & Reed                                               [Page 24]\r\f\rRFC 1459              Internet Relay Chat Protocol              May 1993\r\r\r   at  all  unless  the client is a member of the channel in question.\r\r   Numeric Replies:\r\r           ERR_NOSUCHSERVER                RPL_LISTSTART\r           RPL_LIST                        RPL_LISTEND\r\r   Examples:\r\r   LIST                            ; List all channels.\r\r   LIST #twilight_zone,#42         ; List channels #twilight_zone and #42\r\r4.2.7 Invite message\r\r      Command: INVITE\r   Parameters: <nickname> <channel>\r\r   The INVITE message is used to invite users to a channel.  The\r   parameter <nickname> is the nickname of the person to be invited to\r   the target channel <channel>.  There is no requirement that the\r   channel the target user is being invited to must exist or be a valid\r   channel.  To invite a user to a channel which is invite only (MODE\r   +i), the client sending the invite must be recognised as being a\r   channel operator on the given channel.\r\r   Numeric Replies:\r\r           ERR_NEEDMOREPARAMS              ERR_NOSUCHNICK\r           ERR_NOTONCHANNEL                ERR_USERONCHANNEL\r           ERR_CHANOPRIVSNEEDED\r           RPL_INVITING                    RPL_AWAY\r\r   Examples:\r\r   :Angel INVITE Wiz #Dust         ; User Angel inviting WiZ to channel\r                                   #Dust\r\r   INVITE Wiz #Twilight_Zone       ; Command to invite WiZ to\r                                   #Twilight_zone\r\r4.2.8 Kick command\r\r      Command: KICK\r   Parameters: <channel> <user> [<comment>]\r\r   The KICK command can be  used  to  forcibly  remove  a  user  from  a\r   channel.   It  'kicks  them  out'  of the channel (forced PART).\r\r\r\rOikarinen & Reed                                               [Page 25]\r\f\rRFC 1459              Internet Relay Chat Protocol              May 1993\r\r\r   Only a channel operator may kick another user out of a  channel.\r   Each  server that  receives  a KICK message checks that it is valid\r   (ie the sender is actually a  channel  operator)  before  removing\r   the  victim  from  the channel.\r\r   Numeric Replies:\r\r           ERR_NEEDMOREPARAMS              ERR_NOSUCHCHANNEL\r           ERR_BADCHANMASK                 ERR_CHANOPRIVSNEEDED\r           ERR_NOTONCHANNEL\r\r   Examples:\r\rKICK &Melbourne Matthew         ; Kick Matthew from &Melbourne\r\rKICK #Finnish John :Speaking English\r                                ; Kick John from #Finnish using\r                                "Speaking English" as the reason\r                                (comment).\r\r:WiZ KICK #Finnish John         ; KICK message from WiZ to remove John\r                                from channel #Finnish\r\rNOTE:\r     It is possible to extend the KICK command parameters to the\rfollowing:\r\r<channel>{,<channel>} <user>{,<user>} [<comment>]\r\r4.3 Server queries and commands\r\r   The server query group of commands has been designed to return\r   information about any server which is connected to the network.  All\r   servers connected must respond to these queries and respond\r   correctly.  Any invalid response (or lack thereof) must be considered\r   a sign of a broken server and it must be disconnected/disabled as\r   soon as possible until the situation is remedied.\r\r   In these queries, where a parameter appears as "<server>", it will\r   usually mean it can be a nickname or a server or a wildcard name of\r   some sort.  For each parameter, however, only one query and set of\r   replies is to be generated.\r\r4.3.1 Version message\r\r      Command: VERSION\r   Parameters: [<server>]\r\r\r\r\rOikarinen & Reed                                               [Page 26]\r\f\rRFC 1459              Internet Relay Chat Protocol              May 1993\r\r\r   The VERSION message is used  to  query  the  version  of  the  server\r   program.  An optional parameter <server> is used to query the version\r   of the server program which a client is not directly connected to.\r\r   Numeric Replies:\r\r           ERR_NOSUCHSERVER                RPL_VERSION\r\r   Examples:\r\r   :Wiz VERSION *.se               ; message from Wiz to check the version\r                                   of a server matching "*.se"\r\r   VERSION tolsun.oulu.fi          ; check the version of server\r                                   "tolsun.oulu.fi".\r\r4.3.2 Stats message\r\r      Command: STATS\r   Parameters: [<query> [<server>]]\r\r   The stats message is used to query statistics of certain server.  If\r   <server> parameter is omitted, only the end of stats reply is sent\r   back.  The implementation of this command is highly dependent on the\r   server which replies, although the server must be able to supply\r   information as described by the queries below (or similar).\r\r   A query may be given by any single letter which is only checked by\r   the destination server (if given as the <server> parameter) and is\r   otherwise passed on by intermediate servers, ignored and unaltered.\r   The following queries are those found in the current IRC\r   implementation and provide a large portion of the setup information\r   for that server.  Although these may not be supported in the same way\r   by other versions, all servers should be able to supply a valid reply\r   to a STATS query which is consistent with the reply formats currently\r   used and the purpose of the query.\r\r   The currently supported queries are:\r\r           c - returns a list of servers which the server may connect\r               to or allow connections from;\r           h - returns a list of servers which are either forced to be\r               treated as leaves or allowed to act as hubs;\r           i - returns a list of hosts which the server allows a client\r               to connect from;\r           k - returns a list of banned username/hostname combinations\r               for that server;\r           l - returns a list of the server's connections, showing how\r\r\r\rOikarinen & Reed                                               [Page 27]\r\f\rRFC 1459              Internet Relay Chat Protocol              May 1993\r\r\r               long each connection has been established and the traffic\r               over that connection in bytes and messages for each\r               direction;\r           m - returns a list of commands supported by the server and\r               the usage count for each if the usage count is non zero;\r           o - returns a list of hosts from which normal clients may\r               become operators;\r           y - show Y (Class) lines from server's configuration file;\r           u - returns a string showing how long the server has been up.\r\r   Numeric Replies:\r\r           ERR_NOSUCHSERVER\r           RPL_STATSCLINE                  RPL_STATSNLINE\r           RPL_STATSILINE                  RPL_STATSKLINE\r           RPL_STATSQLINE                  RPL_STATSLLINE\r           RPL_STATSLINKINFO               RPL_STATSUPTIME\r           RPL_STATSCOMMANDS               RPL_STATSOLINE\r           RPL_STATSHLINE                  RPL_ENDOFSTATS\r\r   Examples:\r\rSTATS m                         ; check the command usage for the server\r                                you are connected to\r\r:Wiz STATS c eff.org            ; request by WiZ for C/N line\r                                information from server eff.org\r\r4.3.3 Links message\r\r      Command: LINKS\r   Parameters: [[<remote server>] <server mask>]\r\r   With LINKS, a user can list all servers which are known by the server\r   answering the query.  The returned list of servers must match the\r   mask, or if no mask is given, the full list is returned.\r\r   If <remote server> is given in addition to <server mask>, the LINKS\r   command is forwarded to the first server found that matches that name\r   (if any), and that server is then required to answer the query.\r\r   Numeric Replies:\r\r           ERR_NOSUCHSERVER\r           RPL_LINKS                       RPL_ENDOFLINKS\r\r   Examples:\r\r\r\r\rOikarinen & Reed                                               [Page 28]\r\f\rRFC 1459              Internet Relay Chat Protocol              May 1993\r\r\rLINKS *.au                      ; list all servers which have a name\r                                that matches *.au;\r\r:WiZ LINKS *.bu.edu *.edu       ; LINKS message from WiZ to the first\r                                server matching *.edu for a list of\r                                servers matching *.bu.edu.\r\r4.3.4 Time message\r\r      Command: TIME\r   Parameters: [<server>]\r\r   The time message is used to query local time from the specified\r   server. If the server parameter is not given, the server handling the\r   command must reply to the query.\r\r   Numeric Replies:\r\r           ERR_NOSUCHSERVER                RPL_TIME\r\r   Examples:\r\r   TIME tolsun.oulu.fi             ; check the time on the server\r                                   "tolson.oulu.fi"\r\r   Angel TIME *.au                 ; user angel checking the time on a\r                                   server matching "*.au"\r\r4.3.5 Connect message\r\r      Command: CONNECT\r   Parameters: <target server> [<port> [<remote server>]]\r\r   The CONNECT command can be used to force a server to try to establish\r   a new connection to another server immediately.  CONNECT is a\r   privileged command and is to be available only to IRC Operators.  If\r   a remote server is given then the CONNECT attempt is made by that\r   server to <target server> and <port>.\r\r   Numeric Replies:\r\r           ERR_NOSUCHSERVER                ERR_NOPRIVILEGES\r           ERR_NEEDMOREPARAMS\r\r   Examples:\r\rCONNECT tolsun.oulu.fi          ; Attempt to connect a server to\r                                tolsun.oulu.fi\r\r\r\rOikarinen & Reed                                               [Page 29]\r\f\rRFC 1459              Internet Relay Chat Protocol              May 1993\r\r\r:WiZ CONNECT eff.org 6667 csd.bu.edu\r                                ; CONNECT attempt by WiZ to get servers\r                                eff.org and csd.bu.edu connected on port\r                                6667.\r\r4.3.6 Trace message\r\r      Command: TRACE\r   Parameters: [<server>]\r\r   TRACE command is used to find the route to specific server.  Each\r   server that processes this message must tell the sender about it by\r   sending a reply indicating it is a pass-through link, forming a chain\r   of replies similar to that gained from using "traceroute".  After\r   sending this reply back, it must then send the TRACE message to the\r   next server until given server is reached.  If the <server> parameter\r   is omitted, it is recommended that TRACE command send a message to\r   the sender telling which servers the current server has direct\r   connection to.\r\r   If the destination given by "<server>" is an actual server, then the\r   destination server is required to report all servers and users which\r   are connected to it, although only operators are permitted to see\r   users present.  If the destination given by <server> is a nickname,\r   they only a reply for that nickname is given.\r\r   Numeric Replies:\r\r           ERR_NOSUCHSERVER\r\r   If the TRACE message is destined for another server, all intermediate\r   servers must return a RPL_TRACELINK reply to indicate that the TRACE\r   passed through it and where its going next.\r\r           RPL_TRACELINK\r   A TRACE reply may be composed of any number of the following numeric\r   replies.\r\r           RPL_TRACECONNECTING             RPL_TRACEHANDSHAKE\r           RPL_TRACEUNKNOWN                RPL_TRACEOPERATOR\r           RPL_TRACEUSER                   RPL_TRACESERVER\r           RPL_TRACESERVICE                RPL_TRACENEWTYPE\r           RPL_TRACECLASS\r\r   Examples:\r\rTRACE *.oulu.fi                 ; TRACE to a server matching *.oulu.fi\r\r\r\r\rOikarinen & Reed                                               [Page 30]\r\f\rRFC 1459              Internet Relay Chat Protocol              May 1993\r\r\r:WiZ TRACE AngelDust            ; TRACE issued by WiZ to nick AngelDust\r\r4.3.7 Admin command\r\r      Command: ADMIN\r   Parameters: [<server>]\r\r   The admin message is used to find the name of the administrator of\r   the given server, or current server if <server> parameter is omitted.\r   Each server must have the ability to forward ADMIN messages to other\r   servers.\r\r   Numeric Replies:\r\r           ERR_NOSUCHSERVER\r           RPL_ADMINME                     RPL_ADMINLOC1\r           RPL_ADMINLOC2                   RPL_ADMINEMAIL\r\r   Examples:\r\r   ADMIN tolsun.oulu.fi            ; request an ADMIN reply from\r                                   tolsun.oulu.fi\r\r   :WiZ ADMIN *.edu                ; ADMIN request from WiZ for first\r                                   server found to match *.edu.\r\r4.3.8 Info command\r\r      Command: INFO\r   Parameters: [<server>]\r\r   The INFO command is required to return information which describes\r   the server: its version, when it was compiled, the patchlevel, when\r   it was started, and any other miscellaneous information which may be\r   considered to be relevant.\r\r   Numeric Replies:\r\r           ERR_NOSUCHSERVER\r           RPL_INFO                        RPL_ENDOFINFO\r\r   Examples:\r\r   INFO csd.bu.edu                 ; request an INFO reply from\r   csd.bu.edu\r\r   :Avalon INFO *.fi               ; INFO request from Avalon for first\r                                   server found to match *.fi.\r\r\r\rOikarinen & Reed                                               [Page 31]\r\f\rRFC 1459              Internet Relay Chat Protocol              May 1993\r\r\r   INFO Angel                      ; request info from the server that\r                                   Angel is connected to.\r\r4.4 Sending messages\r\r   The main purpose of the IRC protocol is to provide a base for clients\r   to communicate with each other.  PRIVMSG and NOTICE are the only\r   messages available which actually perform delivery of a text message\r   from one client to another - the rest just make it possible and try\r   to ensure it happens in a reliable and structured manner.\r\r4.4.1 Private messages\r\r      Command: PRIVMSG\r   Parameters: <receiver>{,<receiver>} <text to be sent>\r\r   PRIVMSG is used to send private messages between users.  <receiver>\r   is the nickname of the receiver of the message.  <receiver> can also\r   be a list of names or channels separated with commas.\r\r   The <receiver> parameter may also me a host mask  (#mask)  or  server\r   mask  ($mask).   In  both cases the server will only send the PRIVMSG\r   to those who have a server or host matching the mask.  The mask  must\r   have at  least  1  (one)  "."  in it and no wildcards following the\r   last ".".  This requirement exists to prevent people sending messages\r   to  "#*"  or "$*",  which  would  broadcast  to  all  users; from\r   experience, this is abused more than used responsibly and properly.\r   Wildcards are  the  '*' and  '?'   characters.   This  extension  to\r   the PRIVMSG command is only available to Operators.\r\r   Numeric Replies:\r\r           ERR_NORECIPIENT                 ERR_NOTEXTTOSEND\r           ERR_CANNOTSENDTOCHAN            ERR_NOTOPLEVEL\r           ERR_WILDTOPLEVEL                ERR_TOOMANYTARGETS\r           ERR_NOSUCHNICK\r           RPL_AWAY\r\r   Examples:\r\r:Angel PRIVMSG Wiz :Hello are you receiving this message ?\r                                ; Message from Angel to Wiz.\r\rPRIVMSG Angel :yes I'm receiving it !receiving it !'u>(768u+1n) .br ;\r                                Message to Angel.\r\rPRIVMSG jto@tolsun.oulu.fi :Hello !\r                                ; Message to a client on server\r\r\r\rOikarinen & Reed                                               [Page 32]\r\f\rRFC 1459              Internet Relay Chat Protocol              May 1993\r\r\r                                tolsun.oulu.fi with username of "jto".\r\rPRIVMSG $*.fi :Server tolsun.oulu.fi rebooting.\r                                ; Message to everyone on a server which\r                                has a name matching *.fi.\r\rPRIVMSG #*.edu :NSFNet is undergoing work, expect interruptions\r                                ; Message to all users who come from a\r                                host which has a name matching *.edu.\r\r4.4.2 Notice\r\r      Command: NOTICE\r   Parameters: <nickname> <text>\r\r   The NOTICE message is used similarly to PRIVMSG.  The difference\r   between NOTICE and PRIVMSG is that automatic replies must never be\r   sent in response to a NOTICE message.  This rule applies to servers\r   too - they must not send any error reply back to the client on\r   receipt of a notice.  The object of this rule is to avoid loops\r   between a client automatically sending something in response to\r   something it received.  This is typically used by automatons (clients\r   with either an AI or other interactive program controlling their\r   actions) which are always seen to be replying lest they end up in a\r   loop with another automaton.\r\r   See PRIVMSG for more details on replies and examples.\r\r4.5 User based queries\r\r   User queries are a group of commands which are primarily concerned\r   with finding details on a particular user or group users.  When using\r   wildcards with any of these commands, if they match, they will only\r   return information on users who are 'visible' to you.  The visibility\r   of a user is determined as a combination of the user's mode and the\r   common set of channels you are both on.\r\r4.5.1 Who query\r\r      Command: WHO\r   Parameters: [<name> [<o>]]\r\r   The WHO message is used by a client to generate a query which returns\r   a list of information which 'matches' the <name> parameter given by\r   the client.  In the absence of the <name> parameter, all visible\r   (users who aren't invisible (user mode +i) and who don't have a\r   common channel with the requesting client) are listed.  The same\r   result can be achieved by using a <name> of "0" or any wildcard which\r\r\r\rOikarinen & Reed                                               [Page 33]\r\f\rRFC 1459              Internet Relay Chat Protocol              May 1993\r\r\r   will end up matching every entry possible.\r\r   The <name> passed to WHO is matched against users' host, server, real\r   name and nickname if the channel <name> cannot be found.\r\r   If the "o" parameter is passed only operators are returned according\r   to the name mask supplied.\r\r   Numeric Replies:\r\r           ERR_NOSUCHSERVER\r           RPL_WHOREPLY                    RPL_ENDOFWHO\r\r   Examples:\r\r   WHO *.fi                        ; List all users who match against\r                                   "*.fi".\r\r   WHO jto* o                      ; List all users with a match against\r                                   "jto*" if they are an operator.\r\r4.5.2 Whois query\r\r      Command: WHOIS\r   Parameters: [<server>] <nickmask>[,<nickmask>[,...]]\r\r   This message is used to query information about particular user.  The\r   server will answer this message with several numeric messages\r   indicating different statuses of each user which matches the nickmask\r   (if you are entitled to see them).  If no wildcard is present in the\r   <nickmask>, any information about that nick which you are allowed to\r   see is presented.  A comma (',') separated list of nicknames may be\r   given.\r\r   The latter version sends the query to a specific server.  It is\r   useful if you want to know how long the user in question has been\r   idle as only local server (ie. the server the user is directly\r   connected to) knows that information, while everything else is\r   globally known.\r\r   Numeric Replies:\r\r           ERR_NOSUCHSERVER                ERR_NONICKNAMEGIVEN\r           RPL_WHOISUSER                   RPL_WHOISCHANNELS\r           RPL_WHOISCHANNELS               RPL_WHOISSERVER\r           RPL_AWAY                        RPL_WHOISOPERATOR\r           RPL_WHOISIDLE                   ERR_NOSUCHNICK\r           RPL_ENDOFWHOIS\r\r\r\rOikarinen & Reed                                               [Page 34]\r\f\rRFC 1459              Internet Relay Chat Protocol              May 1993\r\r\r   Examples:\r\r   WHOIS wiz                       ; return available user information\r                                   about nick WiZ\r\r   WHOIS eff.org trillian          ; ask server eff.org for user\r                                   information about trillian\r\r4.5.3 Whowas\r\r      Command: WHOWAS\r   Parameters: <nickname> [<count> [<server>]]\r\r   Whowas asks for information about a nickname which no longer exists.\r   This may either be due to a nickname change or the user leaving IRC.\r   In response to this query, the server searches through its nickname\r   history, looking for any nicks which are lexically the same (no wild\r   card matching here).  The history is searched backward, returning the\r   most recent entry first.  If there are multiple entries, up to\r   <count> replies will be returned (or all of them if no <count>\r   parameter is given).  If a non-positive number is passed as being\r   <count>, then a full search is done.\r\r   Numeric Replies:\r\r           ERR_NONICKNAMEGIVEN             ERR_WASNOSUCHNICK\r           RPL_WHOWASUSER                  RPL_WHOISSERVER\r           RPL_ENDOFWHOWAS\r\r   Examples:\r\r   WHOWAS Wiz                      ; return all information in the nick\r                                   history about nick "WiZ";\r\r   WHOWAS Mermaid 9                ; return at most, the 9 most recent\r                                   entries in the nick history for\r                                   "Mermaid";\r\r   WHOWAS Trillian 1 *.edu         ; return the most recent history for\r                                   "Trillian" from the first server found\r                                   to match "*.edu".\r\r4.6 Miscellaneous messages\r\r   Messages in this category do not fit into any of the above categories\r   but are nonetheless still a part of and required by the protocol.\r\r\r\r\r\rOikarinen & Reed                                               [Page 35]\r\f\rRFC 1459              Internet Relay Chat Protocol              May 1993\r\r\r4.6.1 Kill message\r\r      Command: KILL\r   Parameters: <nickname> <comment>\r\r   The KILL message is used to cause a client-server connection to be\r   closed by the server which has the actual connection.  KILL is used\r   by servers when they encounter a duplicate entry in the list of valid\r   nicknames and is used to remove both entries.  It is also available\r   to operators.\r\r   Clients which have automatic reconnect algorithms effectively make\r   this command useless since the disconnection is only brief.  It does\r   however break the flow of data and can be used to stop large amounts\r   of being abused, any user may elect to receive KILL messages\r   generated for others to keep an 'eye' on would be trouble spots.\r\r   In an arena where nicknames are required to be globally unique at all\r   times, KILL messages are sent whenever 'duplicates' are detected\r   (that is an attempt to register two users with the same nickname) in\r   the hope that both of them will disappear and only 1 reappear.\r\r   The comment given must reflect the actual reason for the KILL.  For\r   server-generated KILLs it usually is made up of details concerning\r   the origins of the two conflicting nicknames.  For users it is left\r   up to them to provide an adequate reason to satisfy others who see\r   it.  To prevent/discourage fake KILLs from being generated to hide\r   the identify of the KILLer, the comment also shows a 'kill-path'\r   which is updated by each server it passes through, each prepending\r   its name to the path.\r\r   Numeric Replies:\r\r           ERR_NOPRIVILEGES                ERR_NEEDMOREPARAMS\r           ERR_NOSUCHNICK                  ERR_CANTKILLSERVER\r\r\r   KILL David (csd.bu.edu <- tolsun.oulu.fi)\r                                   ; Nickname collision between csd.bu.edu\r                                   and tolson.oulu.fi\r\r\r   NOTE:\r   It is recommended that only Operators be allowed to kill other users\r   with KILL message.  In an ideal world not even operators would need\r   to do this and it would be left to servers to deal with.\r\r\r\r\r\rOikarinen & Reed                                               [Page 36]\r\f\rRFC 1459              Internet Relay Chat Protocol              May 1993\r\r\r4.6.2 Ping message\r\r      Command: PING\r   Parameters: <server1> [<server2>]\r\r   The PING message is used to test the presence of an active client at\r   the other end of the connection.  A PING message is sent at regular\r   intervals if no other activity detected coming from a connection.  If\r   a connection fails to respond to a PING command within a set amount\r   of time, that connection is closed.\r\r   Any client which receives a PING message must respond to <server1>\r   (server which sent the PING message out) as quickly as possible with\r   an appropriate PONG message to indicate it is still there and alive.\r   Servers should not respond to PING commands but rely on PINGs from\r   the other end of the connection to indicate the connection is alive.\r   If the <server2> parameter is specified, the PING message gets\r   forwarded there.\r\r   Numeric Replies:\r\r           ERR_NOORIGIN                    ERR_NOSUCHSERVER\r\r   Examples:\r\r   PING tolsun.oulu.fi             ; server sending a PING message to\r                                   another server to indicate it is still\r                                   alive.\r\r   PING WiZ                        ; PING message being sent to nick WiZ\r\r4.6.3 Pong message\r\r      Command: PONG\r   Parameters: <daemon> [<daemon2>]\r\r   PONG message is a reply to ping message.  If parameter <daemon2> is\r   given this message must be forwarded to given daemon.  The <daemon>\r   parameter is the name of the daemon who has responded to PING message\r   and generated this message.\r\r   Numeric Replies:\r\r           ERR_NOORIGIN                    ERR_NOSUCHSERVER\r\r   Examples:\r\r   PONG csd.bu.edu tolsun.oulu.fi  ; PONG message from csd.bu.edu to\r\r\r\rOikarinen & Reed                                               [Page 37]\r\f\rRFC 1459              Internet Relay Chat Protocol              May 1993\r\r\r                                   tolsun.oulu.fi\r\r4.6.4 Error\r\r      Command: ERROR\r   Parameters: <error message>\r\r   The ERROR command is for use by servers when reporting a serious or\r   fatal error to its operators.  It may also be sent from one server to\r   another but must not be accepted from any normal unknown clients.\r\r   An ERROR message is for use for reporting errors which occur with a\r   server-to-server link only.  An ERROR message is sent to the server\r   at the other end (which sends it to all of its connected operators)\r   and to all operators currently connected.  It is not to be passed\r   onto any other servers by a server if it is received from a server.\r\r   When a server sends a received ERROR message to its operators, the\r   message should be encapsulated inside a NOTICE message, indicating\r   that the client was not responsible for the error.\r\r   Numerics:\r\r           None.\r\r   Examples:\r\r   ERROR :Server *.fi already exists; ERROR message to the other server\r                                   which caused this error.\r\r   NOTICE WiZ :ERROR from csd.bu.edu -- Server *.fi already exists\r                                   ; Same ERROR message as above but sent\r                                   to user WiZ on the other server.\r\r5. OPTIONALS\r\r   This section describes OPTIONAL messages.  They are not required in a\r   working server implementation of the protocol described herein.  In\r   the absence of the option, an error reply message must be generated\r   or an unknown command error.  If the message is destined for another\r   server to answer then it must be passed on (elementary parsing\r   required) The allocated numerics for this are listed with the\r   messages below.\r\r5.1 Away\r\r      Command: AWAY\r   Parameters: [message]\r\r\r\rOikarinen & Reed                                               [Page 38]\r\f\rRFC 1459              Internet Relay Chat Protocol              May 1993\r\r\r   With the AWAY message, clients can set an automatic reply string for\r   any PRIVMSG commands directed at them (not to a channel they are on).\r   The automatic reply is sent by the server to client sending the\r   PRIVMSG command.  The only replying server is the one to which the\r   sending client is connected to.\r\r   The AWAY message is used either with one parameter (to set an AWAY\r   message) or with no parameters (to remove the AWAY message).\r\r   Numeric Replies:\r\r           RPL_UNAWAY                      RPL_NOWAWAY\r\r   Examples:\r\r   AWAY :Gone to lunch.  Back in 5 ; set away message to "Gone to lunch.\r                                   Back in 5".\r\r   :WiZ AWAY                       ; unmark WiZ as being away.\r\r\r5.2 Rehash message\r\r      Command: REHASH\r   Parameters: None\r\r   The rehash message can be used by the operator to force the server to\r   re-read and process its configuration file.\r\r   Numeric Replies:\r\r        RPL_REHASHING                   ERR_NOPRIVILEGES\r\rExamples:\r\rREHASH                          ; message from client with operator\r                                status to server asking it to reread its\r                                configuration file.\r\r5.3 Restart message\r\r      Command: RESTART\r   Parameters: None\r\r   The restart message can only be used by an operator to force a server\r   restart itself.  This message is optional since it may be viewed as a\r   risk to allow arbitrary people to connect to a server as an operator\r   and execute this command, causing (at least) a disruption to service.\r\r\r\rOikarinen & Reed                                               [Page 39]\r\f\rRFC 1459              Internet Relay Chat Protocol              May 1993\r\r\r   The RESTART command must always be fully processed by the server to\r   which the sending client is connected and not be passed onto other\r   connected servers.\r\r   Numeric Replies:\r\r           ERR_NOPRIVILEGES\r\r   Examples:\r\r   RESTART                         ; no parameters required.\r\r5.4 Summon message\r\r      Command: SUMMON\r   Parameters: <user> [<server>]\r\r   The SUMMON command can be used to give users who are on a host\r   running an IRC server a message asking them to please join IRC.  This\r   message is only sent if the target server (a) has SUMMON enabled, (b)\r   the user is logged in and (c) the server process can write to the\r   user's tty (or similar).\r\r   If no <server> parameter is given it tries to summon <user> from the\r   server the client is connected to is assumed as the target.\r\r   If summon is not enabled in a server, it must return the\r   ERR_SUMMONDISABLED numeric and pass the summon message onwards.\r\r   Numeric Replies:\r\r           ERR_NORECIPIENT                 ERR_FILEERROR\r           ERR_NOLOGIN                     ERR_NOSUCHSERVER\r           RPL_SUMMONING\r\r   Examples:\r\r   SUMMON jto                      ; summon user jto on the server's host\r\r   SUMMON jto tolsun.oulu.fi       ; summon user jto on the host which a\r                                   server named "tolsun.oulu.fi" is\r                                   running.\r\r\r5.5 Users\r\r      Command: USERS\r   Parameters: [<server>]\r\r\r\rOikarinen & Reed                                               [Page 40]\r\f\rRFC 1459              Internet Relay Chat Protocol              May 1993\r\r\r   The USERS command returns a list of users logged into the server in a\r   similar  format  to  who(1),  rusers(1)  and finger(1).  Some people\r   may disable this command on their server for security related\r   reasons.   If disabled, the correct numeric must be returned to\r   indicate this.\r\r   Numeric Replies:\r\r           ERR_NOSUCHSERVER                ERR_FILEERROR\r           RPL_USERSSTART                  RPL_USERS\r           RPL_NOUSERS                     RPL_ENDOFUSERS\r           ERR_USERSDISABLED\r\r   Disabled Reply:\r\r           ERR_USERSDISABLED\r\r   Examples:\r\rUSERS eff.org                   ; request a list of users logged in on\r                                server eff.org\r\r:John USERS tolsun.oulu.fi      ; request from John for a list of users\r                                logged in on server tolsun.oulu.fi\r\r5.6 Operwall message\r\r      Command: WALLOPS\r   Parameters: Text to be sent to all operators currently online\r\r   Sends  a  message  to  all   operators   currently   online.    After\r   implementing  WALLOPS  as  a user command it was found that it was\r   often and commonly abused as a means of sending a message to a lot\r   of  people (much  similar to WALL).  Due to this it is recommended\r   that the current implementation of  WALLOPS  be  used  as  an\r   example  by  allowing  and recognising only servers as the senders of\r   WALLOPS.\r\r   Numeric Replies:\r\r           ERR_NEEDMOREPARAMS\r\r   Examples:\r\r   :csd.bu.edu WALLOPS :Connect '*.uiuc.edu 6667' from Joshua; WALLOPS\r                                   message from csd.bu.edu announcing a\r                                   CONNECT message it received and acted\r                                   upon from Joshua.\r\r\r\rOikarinen & Reed                                               [Page 41]\r\f\rRFC 1459              Internet Relay Chat Protocol              May 1993\r\r\r5.7 Userhost message\r\r      Command: USERHOST\r   Parameters: <nickname>{<space><nickname>}\r\r   The USERHOST command takes a list of up to 5 nicknames, each\r   separated by a space character and returns a list of information\r   about each nickname that it found.  The returned list has each reply\r   separated by a space.\r\r   Numeric Replies:\r\r           RPL_USERHOST                    ERR_NEEDMOREPARAMS\r\r   Examples:\r\r   USERHOST Wiz Michael Marty p    ;USERHOST request for information on\r                                   nicks "Wiz", "Michael", "Marty" and "p"\r\r5.8 Ison message\r\r      Command: ISON\r   Parameters: <nickname>{<space><nickname>}\r\r   The ISON command was implemented to provide  a  quick  and  efficient\r   means  to get a response about whether a given nickname was currently\r   on IRC. ISON only takes one (1) parameter: a space-separated list of\r   nicks.  For  each  nickname in the list that is present, the server\r   adds that to its reply string.  Thus the reply string may return\r   empty (none  of  the given  nicks are present), an exact copy of the\r   parameter string (all of them present) or as any other subset of the\r   set of nicks  given  in  the parameter.  The only limit on the number\r   of nicks that may be checked is that the combined length must not be\r   too large as to cause the server to chop it off so it fits in 512\r   characters.\r\r   ISON is only be processed by the server local to the client sending\r   the command and thus not passed onto other servers for further\r   processing.\r\r   Numeric Replies:\r\r           RPL_ISON                ERR_NEEDMOREPARAMS\r\r   Examples:\r\r   ISON phone trillian WiZ jarlek Avalon Angel Monstah\r                                   ; Sample ISON request for 7 nicks.\r\r\r\rOikarinen & Reed                                               [Page 42]\r\f\rRFC 1459              Internet Relay Chat Protocol              May 1993\r\r\r6. REPLIES\r\r   The following is a list of numeric replies which are generated in\r   response to the commands given above.  Each numeric is given with its\r   number, name and reply string.\r\r6.1 Error Replies.\r\r        401     ERR_NOSUCHNICK\r                        "<nickname> :No such nick/channel"\r\r                - Used to indicate the nickname parameter supplied to a\r                  command is currently unused.\r\r        402     ERR_NOSUCHSERVER\r                        "<server name> :No such server"\r\r                - Used to indicate the server name given currently\r                  doesn't exist.\r\r        403     ERR_NOSUCHCHANNEL\r                        "<channel name> :No such channel"\r\r                - Used to indicate the given channel name is invalid.\r\r        404     ERR_CANNOTSENDTOCHAN\r                        "<channel name> :Cannot send to channel"\r\r                - Sent to a user who is either (a) not on a channel\r                  which is mode +n or (b) not a chanop (or mode +v) on\r                  a channel which has mode +m set and is trying to send\r                  a PRIVMSG message to that channel.\r\r        405     ERR_TOOMANYCHANNELS\r                        "<channel name> :You have joined too many \\r                         channels"\r                - Sent to a user when they have joined the maximum\r                  number of allowed channels and they try to join\r                  another channel.\r\r        406     ERR_WASNOSUCHNICK\r                        "<nickname> :There was no such nickname"\r\r                - Returned by WHOWAS to indicate there is no history\r                  information for that nickname.\r\r        407     ERR_TOOMANYTARGETS\r                        "<target> :Duplicate recipients. No message \\r\r\r\rOikarinen & Reed                                               [Page 43]\r\f\rRFC 1459              Internet Relay Chat Protocol              May 1993\r\r\r                         delivered"\r\r                - Returned to a client which is attempting to send a\r                  PRIVMSG/NOTICE using the user@host destination format\r                  and for a user@host which has several occurrences.\r\r        409     ERR_NOORIGIN\r                        ":No origin specified"\r\r                - PING or PONG message missing the originator parameter\r                  which is required since these commands must work\r                  without valid prefixes.\r\r        411     ERR_NORECIPIENT\r                        ":No recipient given (<command>)"\r        412     ERR_NOTEXTTOSEND\r                        ":No text to send"\r        413     ERR_NOTOPLEVEL\r                        "<mask> :No toplevel domain specified"\r        414     ERR_WILDTOPLEVEL\r                        "<mask> :Wildcard in toplevel domain"\r\r                - 412 - 414 are returned by PRIVMSG to indicate that\r                  the message wasn't delivered for some reason.\r                  ERR_NOTOPLEVEL and ERR_WILDTOPLEVEL are errors that\r                  are returned when an invalid use of\r                  "PRIVMSG $<server>" or "PRIVMSG #<host>" is attempted.\r\r        421     ERR_UNKNOWNCOMMAND\r                        "<command> :Unknown command"\r\r                - Returned to a registered client to indicate that the\r                  command sent is unknown by the server.\r\r        422     ERR_NOMOTD\r                        ":MOTD File is missing"\r\r                - Server's MOTD file could not be opened by the server.\r\r        423     ERR_NOADMININFO\r                        "<server> :No administrative info available"\r\r                - Returned by a server in response to an ADMIN message\r                  when there is an error in finding the appropriate\r                  information.\r\r        424     ERR_FILEERROR\r                ":File error doing <file op> on <file>"\r\r\r\rOikarinen & Reed                                               [Page 44]\r\f\rRFC 1459              Internet Relay Chat Protocol              May 1993\r\r\r                - Generic error message used to report a failed file\r                  operation during the processing of a message.\r\r        431     ERR_NONICKNAMEGIVEN\r                        ":No nickname given"\r\r                - Returned when a nickname parameter expected for a\r                  command and isn't found.\r\r        432     ERR_ERRONEUSNICKNAME\r                        "<nick> :Erroneus nickname"\r\r                - Returned after receiving a NICK message which contains\r                  characters which do not fall in the defined set.  See\r                  section x.x.x for details on valid nicknames.\r\r        433     ERR_NICKNAMEINUSE\r                        "<nick> :Nickname is already in use"\r\r                - Returned when a NICK message is processed that results\r                  in an attempt to change to a currently existing\r                  nickname.\r\r        436     ERR_NICKCOLLISION\r                        "<nick> :Nickname collision KILL"\r\r                - Returned by a server to a client when it detects a\r                  nickname collision (registered of a NICK that\r                  already exists by another server).\r\r        441     ERR_USERNOTINCHANNEL\r                        "<nick> <channel> :They aren't on that channel"\r\r                - Returned by the server to indicate that the target\r                  user of the command is not on the given channel.\r\r        442     ERR_NOTONCHANNEL\r                        "<channel> :You're not on that channel"\r\r                - Returned by the server whenever a client tries to\r                  perform a channel effecting command for which the\r                  client isn't a member.\r\r        443     ERR_USERONCHANNEL\r                        "<user> <channel> :is already on channel"\r\r                - Returned when a client tries to invite a user to a\r                  channel they are already on.\r\r\r\rOikarinen & Reed                                               [Page 45]\r\f\rRFC 1459              Internet Relay Chat Protocol              May 1993\r\r\r        444     ERR_NOLOGIN\r                        "<user> :User not logged in"\r\r                - Returned by the summon after a SUMMON command for a\r                  user was unable to be performed since they were not\r                  logged in.\r\r        445     ERR_SUMMONDISABLED\r                        ":SUMMON has been disabled"\r\r                - Returned as a response to the SUMMON command.  Must be\r                  returned by any server which does not implement it.\r\r        446     ERR_USERSDISABLED\r                        ":USERS has been disabled"\r\r                - Returned as a response to the USERS command.  Must be\r                  returned by any server which does not implement it.\r\r        451     ERR_NOTREGISTERED\r                        ":You have not registered"\r\r                - Returned by the server to indicate that the client\r                  must be registered before the server will allow it\r                  to be parsed in detail.\r\r        461     ERR_NEEDMOREPARAMS\r                        "<command> :Not enough parameters"\r\r                - Returned by the server by numerous commands to\r                  indicate to the client that it didn't supply enough\r                  parameters.\r\r        462     ERR_ALREADYREGISTRED\r                        ":You may not reregister"\r\r                - Returned by the server to any link which tries to\r                  change part of the registered details (such as\r                  password or user details from second USER message).\r\r\r        463     ERR_NOPERMFORHOST\r                        ":Your host isn't among the privileged"\r\r                - Returned to a client which attempts to register with\r                  a server which does not been setup to allow\r                  connections from the host the attempted connection\r                  is tried.\r\r\r\rOikarinen & Reed                                               [Page 46]\r\f\rRFC 1459              Internet Relay Chat Protocol              May 1993\r\r\r        464     ERR_PASSWDMISMATCH\r                        ":Password incorrect"\r\r                - Returned to indicate a failed attempt at registering\r                  a connection for which a password was required and\r                  was either not given or incorrect.\r\r        465     ERR_YOUREBANNEDCREEP\r                        ":You are banned from this server"\r\r                - Returned after an attempt to connect and register\r                  yourself with a server which has been setup to\r                  explicitly deny connections to you.\r\r        467     ERR_KEYSET\r                        "<channel> :Channel key already set"\r        471     ERR_CHANNELISFULL\r                        "<channel> :Cannot join channel (+l)"\r        472     ERR_UNKNOWNMODE\r                        "<char> :is unknown mode char to me"\r        473     ERR_INVITEONLYCHAN\r                        "<channel> :Cannot join channel (+i)"\r        474     ERR_BANNEDFROMCHAN\r                        "<channel> :Cannot join channel (+b)"\r        475     ERR_BADCHANNELKEY\r                        "<channel> :Cannot join channel (+k)"\r        481     ERR_NOPRIVILEGES\r                        ":Permission Denied- You're not an IRC operator"\r\r                - Any command requiring operator privileges to operate\r                  must return this error to indicate the attempt was\r                  unsuccessful.\r\r        482     ERR_CHANOPRIVSNEEDED\r                        "<channel> :You're not channel operator"\r\r                - Any command requiring 'chanop' privileges (such as\r                  MODE messages) must return this error if the client\r                  making the attempt is not a chanop on the specified\r                  channel.\r\r        483     ERR_CANTKILLSERVER\r                        ":You cant kill a server!"\r\r                - Any attempts to use the KILL command on a server\r                  are to be refused and this error returned directly\r                  to the client.\r\r\r\r\rOikarinen & Reed                                               [Page 47]\r\f\rRFC 1459              Internet Relay Chat Protocol              May 1993\r\r\r        491     ERR_NOOPERHOST\r                        ":No O-lines for your host"\r\r                - If a client sends an OPER message and the server has\r                  not been configured to allow connections from the\r                  client's host as an operator, this error must be\r                  returned.\r\r        501     ERR_UMODEUNKNOWNFLAG\r                        ":Unknown MODE flag"\r\r                - Returned by the server to indicate that a MODE\r                  message was sent with a nickname parameter and that\r                  the a mode flag sent was not recognized.\r\r        502     ERR_USERSDONTMATCH\r                        ":Cant change mode for other users"\r\r                - Error sent to any user trying to view or change the\r                  user mode for a user other than themselves.\r\r6.2 Command responses.\r\r        300     RPL_NONE\r                        Dummy reply number. Not used.\r\r        302     RPL_USERHOST\r                        ":[<reply>{<space><reply>}]"\r\r                - Reply format used by USERHOST to list replies to\r                  the query list.  The reply string is composed as\r                  follows:\r\r                  <reply> ::= <nick>['*'] '=' <'+'|'-'><hostname>\r\r                  The '*' indicates whether the client has registered\r                  as an Operator.  The '-' or '+' characters represent\r                  whether the client has set an AWAY message or not\r                  respectively.\r\r        303     RPL_ISON\r                        ":[<nick> {<space><nick>}]"\r\r                - Reply format used by ISON to list replies to the\r                  query list.\r\r        301     RPL_AWAY\r                        "<nick> :<away message>"\r\r\r\rOikarinen & Reed                                               [Page 48]\r\f\rRFC 1459              Internet Relay Chat Protocol              May 1993\r\r\r        305     RPL_UNAWAY\r                        ":You are no longer marked as being away"\r        306     RPL_NOWAWAY\r                        ":You have been marked as being away"\r\r                - These replies are used with the AWAY command (if\r                  allowed).  RPL_AWAY is sent to any client sending a\r                  PRIVMSG to a client which is away.  RPL_AWAY is only\r                  sent by the server to which the client is connected.\r                  Replies RPL_UNAWAY and RPL_NOWAWAY are sent when the\r                  client removes and sets an AWAY message.\r\r        311     RPL_WHOISUSER\r                        "<nick> <user> <host> * :<real name>"\r        312     RPL_WHOISSERVER\r                        "<nick> <server> :<server info>"\r        313     RPL_WHOISOPERATOR\r                        "<nick> :is an IRC operator"\r        317     RPL_WHOISIDLE\r                        "<nick> <integer> :seconds idle"\r        318     RPL_ENDOFWHOIS\r                        "<nick> :End of /WHOIS list"\r        319     RPL_WHOISCHANNELS\r                        "<nick> :{[@|+]<channel><space>}"\r\r                - Replies 311 - 313, 317 - 319 are all replies\r                  generated in response to a WHOIS message.  Given that\r                  there are enough parameters present, the answering\r                  server must either formulate a reply out of the above\r                  numerics (if the query nick is found) or return an\r                  error reply.  The '*' in RPL_WHOISUSER is there as\r                  the literal character and not as a wild card.  For\r                  each reply set, only RPL_WHOISCHANNELS may appear\r                  more than once (for long lists of channel names).\r                  The '@' and '+' characters next to the channel name\r                  indicate whether a client is a channel operator or\r                  has been granted permission to speak on a moderated\r                  channel.  The RPL_ENDOFWHOIS reply is used to mark\r                  the end of processing a WHOIS message.\r\r        314     RPL_WHOWASUSER\r                        "<nick> <user> <host> * :<real name>"\r        369     RPL_ENDOFWHOWAS\r                        "<nick> :End of WHOWAS"\r\r                - When replying to a WHOWAS message, a server must use\r                  the replies RPL_WHOWASUSER, RPL_WHOISSERVER or\r                  ERR_WASNOSUCHNICK for each nickname in the presented\r\r\r\rOikarinen & Reed                                               [Page 49]\r\f\rRFC 1459              Internet Relay Chat Protocol              May 1993\r\r\r                  list.  At the end of all reply batches, there must\r                  be RPL_ENDOFWHOWAS (even if there was only one reply\r                  and it was an error).\r\r        321     RPL_LISTSTART\r                        "Channel :Users  Name"\r        322     RPL_LIST\r                        "<channel> <# visible> :<topic>"\r        323     RPL_LISTEND\r                        ":End of /LIST"\r\r                - Replies RPL_LISTSTART, RPL_LIST, RPL_LISTEND mark\r                  the start, actual replies with data and end of the\r                  server's response to a LIST command.  If there are\r                  no channels available to return, only the start\r                  and end reply must be sent.\r\r        324     RPL_CHANNELMODEIS\r                        "<channel> <mode> <mode params>"\r\r        331     RPL_NOTOPIC\r                        "<channel> :No topic is set"\r        332     RPL_TOPIC\r                        "<channel> :<topic>"\r\r                - When sending a TOPIC message to determine the\r                  channel topic, one of two replies is sent.  If\r                  the topic is set, RPL_TOPIC is sent back else\r                  RPL_NOTOPIC.\r\r        341     RPL_INVITING\r                        "<channel> <nick>"\r\r                - Returned by the server to indicate that the\r                  attempted INVITE message was successful and is\r                  being passed onto the end client.\r\r        342     RPL_SUMMONING\r                        "<user> :Summoning user to IRC"\r\r                - Returned by a server answering a SUMMON message to\r                  indicate that it is summoning that user.\r\r        351     RPL_VERSION\r                        "<version>.<debuglevel> <server> :<comments>"\r\r                - Reply by the server showing its version details.\r                  The <version> is the version of the software being\r\r\r\rOikarinen & Reed                                               [Page 50]\r\f\rRFC 1459              Internet Relay Chat Protocol              May 1993\r\r\r                  used (including any patchlevel revisions) and the\r                  <debuglevel> is used to indicate if the server is\r                  running in "debug mode".\r\r                  The "comments" field may contain any comments about\r                  the version or further version details.\r\r        352     RPL_WHOREPLY\r                        "<channel> <user> <host> <server> <nick> \\r                         <H|G>[*][@|+] :<hopcount> <real name>"\r        315     RPL_ENDOFWHO\r                        "<name> :End of /WHO list"\r\r                - The RPL_WHOREPLY and RPL_ENDOFWHO pair are used\r                  to answer a WHO message.  The RPL_WHOREPLY is only\r                  sent if there is an appropriate match to the WHO\r                  query.  If there is a list of parameters supplied\r                  with a WHO message, a RPL_ENDOFWHO must be sent\r                  after processing each list item with <name> being\r                  the item.\r\r        353     RPL_NAMREPLY\r                        "<channel> :[[@|+]<nick> [[@|+]<nick> [...]]]"\r        366     RPL_ENDOFNAMES\r                        "<channel> :End of /NAMES list"\r\r                - To reply to a NAMES message, a reply pair consisting\r                  of RPL_NAMREPLY and RPL_ENDOFNAMES is sent by the\r                  server back to the client.  If there is no channel\r                  found as in the query, then only RPL_ENDOFNAMES is\r                  returned.  The exception to this is when a NAMES\r                  message is sent with no parameters and all visible\r                  channels and contents are sent back in a series of\r                  RPL_NAMEREPLY messages with a RPL_ENDOFNAMES to mark\r                  the end.\r\r        364     RPL_LINKS\r                        "<mask> <server> :<hopcount> <server info>"\r        365     RPL_ENDOFLINKS\r                        "<mask> :End of /LINKS list"\r\r                - In replying to the LINKS message, a server must send\r                  replies back using the RPL_LINKS numeric and mark the\r                  end of the list using an RPL_ENDOFLINKS reply.\r\r        367     RPL_BANLIST\r                        "<channel> <banid>"\r        368     RPL_ENDOFBANLIST\r\r\r\rOikarinen & Reed                                               [Page 51]\r\f\rRFC 1459              Internet Relay Chat Protocol              May 1993\r\r\r                        "<channel> :End of channel ban list"\r\r                - When listing the active 'bans' for a given channel,\r                  a server is required to send the list back using the\r                  RPL_BANLIST and RPL_ENDOFBANLIST messages.  A separate\r                  RPL_BANLIST is sent for each active banid.  After the\r                  banids have been listed (or if none present) a\r                  RPL_ENDOFBANLIST must be sent.\r\r        371     RPL_INFO\r                        ":<string>"\r        374     RPL_ENDOFINFO\r                        ":End of /INFO list"\r\r                - A server responding to an INFO message is required to\r                  send all its 'info' in a series of RPL_INFO messages\r                  with a RPL_ENDOFINFO reply to indicate the end of the\r                  replies.\r\r        375     RPL_MOTDSTART\r                        ":- <server> Message of the day - "\r        372     RPL_MOTD\r                        ":- <text>"\r        376     RPL_ENDOFMOTD\r                        ":End of /MOTD command"\r\r                - When responding to the MOTD message and the MOTD file\r                  is found, the file is displayed line by line, with\r                  each line no longer than 80 characters, using\r                  RPL_MOTD format replies.  These should be surrounded\r                  by a RPL_MOTDSTART (before the RPL_MOTDs) and an\r                  RPL_ENDOFMOTD (after).\r\r        381     RPL_YOUREOPER\r                        ":You are now an IRC operator"\r\r                - RPL_YOUREOPER is sent back to a client which has\r                  just successfully issued an OPER message and gained\r                  operator status.\r\r        382     RPL_REHASHING\r                        "<config file> :Rehashing"\r\r                - If the REHASH option is used and an operator sends\r                  a REHASH message, an RPL_REHASHING is sent back to\r                  the operator.\r\r        391     RPL_TIME\r\r\r\rOikarinen & Reed                                               [Page 52]\r\f\rRFC 1459              Internet Relay Chat Protocol              May 1993\r\r\r                        "<server> :<string showing server's local time>"\r\r                - When replying to the TIME message, a server must send\r                  the reply using the RPL_TIME format above.  The string\r                  showing the time need only contain the correct day and\r                  time there.  There is no further requirement for the\r                  time string.\r\r        392     RPL_USERSSTART\r                        ":UserID   Terminal  Host"\r        393     RPL_USERS\r                        ":%-8s %-9s %-8s"\r        394     RPL_ENDOFUSERS\r                        ":End of users"\r        395     RPL_NOUSERS\r                        ":Nobody logged in"\r\r                - If the USERS message is handled by a server, the\r                  replies RPL_USERSTART, RPL_USERS, RPL_ENDOFUSERS and\r                  RPL_NOUSERS are used.  RPL_USERSSTART must be sent\r                  first, following by either a sequence of RPL_USERS\r                  or a single RPL_NOUSER.  Following this is\r                  RPL_ENDOFUSERS.\r\r        200     RPL_TRACELINK\r                        "Link <version & debug level> <destination> \\r                         <next server>"\r        201     RPL_TRACECONNECTING\r                        "Try. <class> <server>"\r        202     RPL_TRACEHANDSHAKE\r                        "H.S. <class> <server>"\r        203     RPL_TRACEUNKNOWN\r                        "???? <class> [<client IP address in dot form>]"\r        204     RPL_TRACEOPERATOR\r                        "Oper <class> <nick>"\r        205     RPL_TRACEUSER\r                        "User <class> <nick>"\r        206     RPL_TRACESERVER\r                        "Serv <class> <int>S <int>C <server> \\r                         <nick!user|*!*>@<host|server>"\r        208     RPL_TRACENEWTYPE\r                        "<newtype> 0 <client name>"\r        261     RPL_TRACELOG\r                        "File <logfile> <debug level>"\r\r                - The RPL_TRACE* are all returned by the server in\r                  response to the TRACE message.  How many are\r                  returned is dependent on the the TRACE message and\r\r\r\rOikarinen & Reed                                               [Page 53]\r\f\rRFC 1459              Internet Relay Chat Protocol              May 1993\r\r\r                  whether it was sent by an operator or not.  There\r                  is no predefined order for which occurs first.\r                  Replies RPL_TRACEUNKNOWN, RPL_TRACECONNECTING and\r                  RPL_TRACEHANDSHAKE are all used for connections\r                  which have not been fully established and are either\r                  unknown, still attempting to connect or in the\r                  process of completing the 'server handshake'.\r                  RPL_TRACELINK is sent by any server which handles\r                  a TRACE message and has to pass it on to another\r                  server.  The list of RPL_TRACELINKs sent in\r                  response to a TRACE command traversing the IRC\r                  network should reflect the actual connectivity of\r                  the servers themselves along that path.\r                  RPL_TRACENEWTYPE is to be used for any connection\r                  which does not fit in the other categories but is\r                  being displayed anyway.\r\r        211     RPL_STATSLINKINFO\r                        "<linkname> <sendq> <sent messages> \\r                         <sent bytes> <received messages> \\r                         <received bytes> <time open>"\r        212     RPL_STATSCOMMANDS\r                        "<command> <count>"\r        213     RPL_STATSCLINE\r                        "C <host> * <name> <port> <class>"\r        214     RPL_STATSNLINE\r                        "N <host> * <name> <port> <class>"\r        215     RPL_STATSILINE\r                        "I <host> * <host> <port> <class>"\r        216     RPL_STATSKLINE\r                        "K <host> * <username> <port> <class>"\r        218     RPL_STATSYLINE\r                        "Y <class> <ping frequency> <connect \\r                         frequency> <max sendq>"\r        219     RPL_ENDOFSTATS\r                        "<stats letter> :End of /STATS report"\r        241     RPL_STATSLLINE\r                        "L <hostmask> * <servername> <maxdepth>"\r        242     RPL_STATSUPTIME\r                        ":Server Up %d days %d:%02d:%02d"\r        243     RPL_STATSOLINE\r                        "O <hostmask> * <name>"\r        244     RPL_STATSHLINE\r                        "H <hostmask> * <servername>"\r\r        221     RPL_UMODEIS\r                        "<user mode string>"\r\r\r\r\rOikarinen & Reed                                               [Page 54]\r\f\rRFC 1459              Internet Relay Chat Protocol              May 1993\r\r\r                        - To answer a query about a client's own mode,\r                          RPL_UMODEIS is sent back.\r\r        251     RPL_LUSERCLIENT\r                        ":There are <integer> users and <integer> \\r                         invisible on <integer> servers"\r        252     RPL_LUSEROP\r                        "<integer> :operator(s) online"\r        253     RPL_LUSERUNKNOWN\r                        "<integer> :unknown connection(s)"\r        254     RPL_LUSERCHANNELS\r                        "<integer> :channels formed"\r        255     RPL_LUSERME\r                        ":I have <integer> clients and <integer> \\r                          servers"\r\r                        - In processing an LUSERS message, the server\r                          sends a set of replies from RPL_LUSERCLIENT,\r                          RPL_LUSEROP, RPL_USERUNKNOWN,\r                          RPL_LUSERCHANNELS and RPL_LUSERME.  When\r                          replying, a server must send back\r                          RPL_LUSERCLIENT and RPL_LUSERME.  The other\r                          replies are only sent back if a non-zero count\r                          is found for them.\r\r        256     RPL_ADMINME\r                        "<server> :Administrative info"\r        257     RPL_ADMINLOC1\r                        ":<admin info>"\r        258     RPL_ADMINLOC2\r                        ":<admin info>"\r        259     RPL_ADMINEMAIL\r                        ":<admin info>"\r\r                        - When replying to an ADMIN message, a server\r                          is expected to use replies RLP_ADMINME\r                          through to RPL_ADMINEMAIL and provide a text\r                          message with each.  For RPL_ADMINLOC1 a\r                          description of what city, state and country\r                          the server is in is expected, followed by\r                          details of the university and department\r                          (RPL_ADMINLOC2) and finally the administrative\r                          contact for the server (an email address here\r                          is required) in RPL_ADMINEMAIL.\r\r\r\r\r\r\r\rOikarinen & Reed                                               [Page 55]\r\f\rRFC 1459              Internet Relay Chat Protocol              May 1993\r\r\r6.3 Reserved numerics.\r\r   These numerics are not described above since they fall into one of\r   the following categories:\r\r        1. no longer in use;\r\r        2. reserved for future planned use;\r\r        3. in current use but are part of a non-generic 'feature' of\r           the current IRC server.\r\r        209     RPL_TRACECLASS          217     RPL_STATSQLINE\r        231     RPL_SERVICEINFO         232     RPL_ENDOFSERVICES\r        233     RPL_SERVICE             234     RPL_SERVLIST\r        235     RPL_SERVLISTEND\r        316     RPL_WHOISCHANOP         361     RPL_KILLDONE\r        362     RPL_CLOSING             363     RPL_CLOSEEND\r        373     RPL_INFOSTART           384     RPL_MYPORTIS\r        466     ERR_YOUWILLBEBANNED     476     ERR_BADCHANMASK\r        492     ERR_NOSERVICEHOST\r\r7. Client and server authentication\r\r   Clients and servers are both subject to the same level of\r   authentication.  For both, an IP number to hostname lookup (and\r   reverse check on this) is performed for all connections made to the\r   server.  Both connections are then subject to a password check (if\r   there is a password set for that connection).  These checks are\r   possible on all connections although the password check is only\r   commonly used with servers.\r\r   An additional check that is becoming of more and more common is that\r   of the username responsible for making the connection.  Finding the\r   username of the other end of the connection typically involves\r   connecting to an authentication server such as IDENT as described in\r   RFC 1413.\r\r   Given that without passwords it is not easy to reliably determine who\r   is on the other end of a network connection, use of passwords is\r   strongly recommended on inter-server connections in addition to any\r   other measures such as using an ident server.\r\r8. Current implementations\r\r   The only current implementation of this protocol is the IRC server,\r   version 2.8. Earlier versions may implement some or all of the\r   commands described by this document with NOTICE messages replacing\r\r\r\rOikarinen & Reed                                               [Page 56]\r\f\rRFC 1459              Internet Relay Chat Protocol              May 1993\r\r\r   many of the numeric replies.  Unfortunately, due to backward\r   compatibility requirements, the implementation of some parts of this\r   document varies with what is laid out.  On notable difference is:\r\r        * recognition that any LF or CR anywhere in a message marks the\r          end of that message (instead of requiring CR-LF);\r\r   The rest of this section deals with issues that are mostly of\r   importance to those who wish to implement a server but some parts\r   also apply directly to clients as well.\r\r8.1 Network protocol: TCP - why it is best used here.\r\r   IRC has been implemented on top of TCP since TCP supplies a reliable\r   network protocol which is well suited to this scale of conferencing.\r   The use of multicast IP is an alternative, but it is not widely\r   available or supported at the present time.\r\r8.1.1 Support of Unix sockets\r\r   Given that Unix domain sockets allow listen/connect operations, the\r   current implementation can be configured to listen and accept both\r   client and server connections on a Unix domain socket.  These are\r   recognized as sockets where the hostname starts with a '/'.\r\r   When providing any information about the connections on a Unix domain\r   socket, the server is required to supplant the actual hostname in\r   place of the pathname unless the actual socket name is being asked\r   for.\r\r8.2 Command Parsing\r\r   To provide useful 'non-buffered' network IO for clients and servers,\r   each connection is given its own private 'input buffer' in which the\r   results of the most recent read and parsing are kept.  A buffer size\r   of 512 bytes is used so as to hold 1 full message, although, this\r   will usually hold several commands.  The private buffer is parsed\r   after every read operation for valid messages.  When dealing with\r   multiple messages from one client in the buffer, care should be taken\r   in case one happens to cause the client to be 'removed'.\r\r8.3 Message delivery\r\r   It is common to find network links saturated or hosts to which you\r   are sending data unable to send data.  Although Unix typically\r   handles this through the TCP window and internal buffers, the server\r   often has large amounts of data to send (especially when a new\r   server-server link forms) and the small buffers provided in the\r\r\r\rOikarinen & Reed                                               [Page 57]\r\f\rRFC 1459              Internet Relay Chat Protocol              May 1993\r\r\r   kernel are not enough for the outgoing queue.  To alleviate this\r   problem, a "send queue" is used as a FIFO queue for data to be sent.\r   A typical "send queue" may grow to 200 Kbytes on a large IRC network\r   with a slow network connection when a new server connects.\r\r   When polling its connections, a server will first read and parse all\r   incoming data, queuing any data to be sent out. When all available\r   input is processed, the queued data is sent. This reduces the number\r   of write() system calls and helps TCP make bigger packets.\r\r8.4 Connection 'Liveness'\r\r   To detect when a connection has died or become unresponsive, the\r   server must ping each of its connections that it doesn't get a\r   response from in a given amount of time.\r\r   If a connection doesn't respond in time, its connection is closed\r   using the appropriate procedures.  A connection is also dropped if\r   its sendq grows beyond the maximum allowed, because it is better to\r   close a slow connection than have a server process block.\r\r8.5 Establishing a server to client connection\r\r   Upon connecting to an IRC server, a client is sent the MOTD (if\r   present) as well as the current user/server count (as per the LUSER\r   command).  The server is also required to give an unambiguous message\r   to the client which states its name and version as well as any other\r   introductory messages which may be deemed appropriate.\r\r   After dealing with this, the server must then send out the new user's\r   nickname and other information as supplied by itself (USER command)\r   and as the server could discover (from DNS/authentication servers).\r   The server must send this information out with NICK first followed by\r   USER.\r\r8.6 Establishing a server-server connection.\r\r   The process of establishing of a server-to-server connection is\r   fraught with danger since there are many possible areas where\r   problems can occur - the least of which are race conditions.\r\r   After a server has received a connection following by a PASS/SERVER\r   pair which were recognised as being valid, the server should then\r   reply with its own PASS/SERVER information for that connection as\r   well as all of the other state information it knows about as\r   described below.\r\r   When the initiating server receives a PASS/SERVER pair, it too then\r\r\r\rOikarinen & Reed                                               [Page 58]\r\f\rRFC 1459              Internet Relay Chat Protocol              May 1993\r\r\r   checks that the server responding is authenticated properly before\r   accepting the connection to be that server.\r\r8.6.1 Server exchange of state information when connecting\r\r   The order of state information being exchanged between servers is\r   essential.  The required order is as follows:\r\r        * all known other servers;\r\r        * all known user information;\r\r        * all known channel information.\r\r   Information regarding servers is sent via extra SERVER messages, user\r   information with NICK/USER/MODE/JOIN messages and channels with MODE\r   messages.\r\r   NOTE: channel topics are *NOT* exchanged here because the TOPIC\r   command overwrites any old topic information, so at best, the two\r   sides of the connection would exchange topics.\r\r   By passing the state information about servers first, any collisions\r   with servers that already exist occur before nickname collisions due\r   to a second server introducing a particular nickname.  Due to the IRC\r   network only being able to exist as an acyclic graph, it may be\r   possible that the network has already reconnected in another\r   location, the place where the collision occurs indicating where the\r   net needs to split.\r\r8.7 Terminating server-client connections\r\r   When a client connection closes, a QUIT message is generated on\r   behalf of the client by the server to which the client connected.  No\r   other message is to be generated or used.\r\r8.8 Terminating server-server connections\r\r   If a server-server connection is closed, either via a remotely\r   generated SQUIT or 'natural' causes, the rest of the connected IRC\r   network must have its information updated with by the server which\r   detected the closure.  The server then sends a list of SQUITs (one\r   for each server behind that connection) and a list of QUITs (again,\r   one for each client behind that connection).\r\r\r\r\r\r\r\rOikarinen & Reed                                               [Page 59]\r\f\rRFC 1459              Internet Relay Chat Protocol              May 1993\r\r\r8.9 Tracking nickname changes\r\r   All IRC servers are required to keep a history of recent nickname\r   changes.  This is required to allow the server to have a chance of\r   keeping in touch of things when nick-change race conditions occur\r   with commands which manipulate them.  Commands which must trace nick\r   changes are:\r\r        * KILL (the nick being killed)\r\r        * MODE (+/- o,v)\r\r        * KICK (the nick being kicked)\r\r   No other commands are to have nick changes checked for.\r\r   In the above cases, the server is required to first check for the\r   existence of the nickname, then check its history to see who that\r   nick currently belongs to (if anyone!).  This reduces the chances of\r   race conditions but they can still occur with the server ending up\r   affecting the wrong client.  When performing a change trace for an\r   above command it is recommended that a time range be given and\r   entries which are too old ignored.\r\r   For a reasonable history, a server should be able to keep previous\r   nickname for every client it knows about if they all decided to\r   change.  This size is limited by other factors (such as memory, etc).\r\r8.10 Flood control of clients\r\r   With a large network of interconnected IRC servers, it is quite easy\r   for any single client attached to the network to supply a continuous\r   stream of messages that result in not only flooding the network, but\r   also degrading the level of service provided to others.  Rather than\r   require every 'victim' to be provide their own protection, flood\r   protection was written into the server and is applied to all clients\r   except services.  The current algorithm is as follows:\r\r        * check to see if client's `message timer' is less than\r          current time (set to be equal if it is);\r\r        * read any data present from the client;\r\r        * while the timer is less than ten seconds ahead of the current\r          time, parse any present messages and penalize the client by\r          2 seconds for each message;\r\r   which in essence means that the client may send 1 message every 2\r\r\r\rOikarinen & Reed                                               [Page 60]\r\f\rRFC 1459              Internet Relay Chat Protocol              May 1993\r\r\r   seconds without being adversely affected.\r\r8.11 Non-blocking lookups\r\r   In a real-time environment, it is essential that a server process do\r   as little waiting as possible so that all the clients are serviced\r   fairly.  Obviously this requires non-blocking IO on all network\r   read/write operations.  For normal server connections, this was not\r   difficult, but there are other support operations that may cause the\r   server to block (such as disk reads).  Where possible, such activity\r   should be performed with a short timeout.\r\r8.11.1 Hostname (DNS) lookups\r\r   Using the standard resolver libraries from Berkeley and others has\r   meant large delays in some cases where replies have timed out.  To\r   avoid this, a separate set of DNS routines were written which were\r   setup for non-blocking IO operations and then polled from within the\r   main server IO loop.\r\r8.11.2 Username (Ident) lookups\r\r   Although there are numerous ident libraries for use and inclusion\r   into other programs, these caused problems since they operated in a\r   synchronous manner and resulted in frequent delays.  Again the\r   solution was to write a set of routines which would cooperate with\r   the rest of the server and work using non-blocking IO.\r\r8.12 Configuration File\r\r   To provide a flexible way of setting up and running the server, it is\r   recommended that a configuration file be used which contains\r   instructions to the server on the following:\r\r        * which hosts to accept client connections from;\r\r        * which hosts to allow to connect as servers;\r\r        * which hosts to connect to (both actively and\r          passively);\r\r        * information about where the server is (university,\r          city/state, company are examples of this);\r\r        * who is responsible for the server and an email address\r          at which they can be contacted;\r\r        * hostnames and passwords for clients which wish to be given\r\r\r\rOikarinen & Reed                                               [Page 61]\r\f\rRFC 1459              Internet Relay Chat Protocol              May 1993\r\r\r          access to restricted operator commands.\r\r   In specifying hostnames, both domain names and use of the 'dot'\r   notation (127.0.0.1) should both be accepted.  It must be possible to\r   specify the password to be used/accepted for all outgoing and\r   incoming connections (although the only outgoing connections are\r   those to other servers).\r\r   The above list is the minimum requirement for any server which wishes\r   to make a connection with another server.  Other items which may be\r   of use are:\r\r        * specifying which servers other server may introduce;\r\r        * how deep a server branch is allowed to become;\r\r        * hours during which clients may connect.\r\r8.12.1 Allowing clients to connect\r\r   A server should use some sort of 'access control list' (either in the\r   configuration file or elsewhere) that is read at startup and used to\r   decide what hosts clients may use to connect to it.\r\r   Both 'deny' and 'allow' should be implemented to provide the required\r   flexibility for host access control.\r\r8.12.2 Operators\r\r   The granting of operator privileges to a disruptive person can have\r   dire consequences for the well-being of the IRC net in general due to\r   the powers given to them.  Thus, the acquisition of such powers\r   should not be very easy.  The current setup requires two 'passwords'\r   to be used although one of them is usually easy guessed.  Storage of\r   oper passwords in configuration files is preferable to hard coding\r   them in and should be stored in a crypted format (ie using crypt(3)\r   from Unix) to prevent easy theft.\r\r8.12.3 Allowing servers to connect\r\r   The interconnection of server is not a trivial matter: a bad\r   connection can have a large impact on the usefulness of IRC.  Thus,\r   each server should have a list of servers to which it may connect and\r   which servers may connect to it.  Under no circumstances should a\r   server allow an arbitrary host to connect as a server.  In addition\r   to which servers may and may not connect, the configuration file\r   should also store the password and other characteristics of that\r   link.\r\r\r\rOikarinen & Reed                                               [Page 62]\r\f\rRFC 1459              Internet Relay Chat Protocol              May 1993\r\r\r8.12.4 Administrivia\r\r   To provide accurate and valid replies to the ADMIN command (see\r   section 4.3.7), the server should find the relevant details in the\r   configuration.\r\r8.13 Channel membership\r\r   The current server allows any registered local user to join upto 10\r   different channels.  There is no limit imposed on non-local users so\r   that the server remains (reasonably) consistant with all others on a\r   channel membership basis\r\r9. Current problems\r\r   There are a number of recognized problems with this protocol, all  of\r   which  hope to be solved sometime in the near future during its\r   rewrite.  Currently, work is underway to find working solutions to\r   these problems.\r\r9.1 Scalability\r\r   It is widely recognized that this protocol does not scale\r   sufficiently well when used in a large arena.  The main problem comes\r   from the requirement that all servers know about all other servers\r   and users and that information regarding them be updated as soon as\r   it changes.  It is also desirable to keep the number of servers low\r   so that the path length between any two points is kept minimal and\r   the spanning tree as strongly branched as possible.\r\r9.2 Labels\r\r   The current IRC protocol has 3 types of labels: the nickname, the\r   channel name and the server name.  Each of the three types has its\r   own domain and no duplicates are allowed inside that domain.\r   Currently, it is possible for users to pick the label for any of the\r   three, resulting in collisions.  It is widely recognized that this\r   needs reworking, with a plan for unique names for channels and nicks\r   that don't collide being desirable as well as a solution allowing a\r   cyclic tree.\r\r9.2.1 Nicknames\r\r   The idea of the nickname on IRC is very convenient for users to use\r   when talking to each other outside of a channel, but there is only a\r   finite nickname space and being what they are, its not uncommon for\r   several people to want to use the same nick.  If a nickname is chosen\r   by two people using this protocol, either one will not succeed or\r\r\r\rOikarinen & Reed                                               [Page 63]\r\f\rRFC 1459              Internet Relay Chat Protocol              May 1993\r\r\r   both will removed by use of KILL (4.6.1).\r\r9.2.2 Channels\r\r   The current channel layout requires that all servers know about all\r   channels, their inhabitants and properties.  Besides not scaling\r   well, the issue of privacy is also a concern.  A collision of\r   channels is treated as an inclusive event (both people who create the\r   new channel are considered to be members of it) rather than an\r   exclusive one such as used to solve nickname collisions.\r\r9.2.3 Servers\r\r   Although the number of servers is usually small relative to the\r   number of users and channels, they two currently required to be known\r   globally, either each one separately or hidden behind a mask.\r\r9.3 Algorithms\r\r   In some places within the server code, it has not  been  possible  to\r   avoid  N^2  algorithms  such  as  checking  the channel list of a set\r   of clients.\r\r   In current server versions, there are no database consistency checks,\r   each server assumes that a neighbouring server is correct.  This\r   opens the door to large problems if a connecting server is buggy or\r   otherwise tries to introduce contradictions to the existing net.\r\r   Currently, because of the lack of unique internal and global labels,\r   there are a multitude of race conditions that exist.  These race\r   conditions generally arise from the problem of it taking time for\r   messages to traverse and effect the IRC network.  Even by changing to\r   unique labels, there are problems with channel-related commands being\r   disrupted.\r\r10. Current support and availability\r\r           Mailing lists for IRC related discussion:\r                Future protocol: ircd-three-request@eff.org\r                General discussion: operlist-request@eff.org\r\r           Software implemenations\r                cs.bu.edu:/irc\r                nic.funet.fi:/pub/irc\r                coombs.anu.edu.au:/pub/irc\r\r           Newsgroup: alt.irc\r\r\r\r\rOikarinen & Reed                                               [Page 64]\r\f\rRFC 1459              Internet Relay Chat Protocol              May 1993\r\r\rSecurity Considerations\r\r   Security issues are discussed in sections 4.1, 4.1.1, 4.1.3, 5.5, and\r   7.\r\r12. Authors' Addresses\r\r   Jarkko Oikarinen\r   Tuirantie 17 as 9\r   90500 OULU\r   FINLAND\r\r   Email: jto@tolsun.oulu.fi\r\r\r   Darren Reed\r   4 Pateman Street\r   Watsonia, Victoria 3087\r   Australia\r\r   Email: avalon@coombs.anu.edu.au\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\rOikarinen & Reed                                               [Page 65]\r\f
\ No newline at end of file
+
+
+
+
+
+
+Network Working Group                                      J. Oikarinen
+Request for Comments: 1459                                      D. Reed
+                                                               May 1993
+
+
+                      Internet Relay Chat Protocol
+
+Status of This Memo
+
+   This memo defines an Experimental Protocol for the Internet
+   community.  Discussion and suggestions for improvement are requested.
+   Please refer to the current edition of the "IAB Official Protocol
+   Standards" for the standardization state and status of this protocol.
+   Distribution of this memo is unlimited.
+
+Abstract
+
+   The IRC protocol was developed over the last 4 years since it was
+   first implemented as a means for users on a BBS to chat amongst
+   themselves.  Now it supports a world-wide network of servers and
+   clients, and is stringing to cope with growth. Over the past 2 years,
+   the average number of users connected to the main IRC network has
+   grown by a factor of 10.
+
+   The IRC protocol is a text-based protocol, with the simplest client
+   being any socket program capable of connecting to the server.
+
+Table of Contents
+
+   1.  INTRODUCTION ...............................................    4
+      1.1  Servers ................................................    4
+      1.2  Clients ................................................    5
+         1.2.1 Operators ..........................................    5
+      1.3 Channels ................................................    5
+      1.3.1  Channel Operators ....................................    6
+   2. THE IRC SPECIFICATION .......................................    7
+      2.1 Overview ................................................    7
+      2.2 Character codes .........................................    7
+      2.3 Messages ................................................    7
+         2.3.1  Message format in 'pseudo' BNF ....................    8
+      2.4 Numeric replies .........................................   10
+   3. IRC Concepts ................................................   10
+      3.1 One-to-one communication ................................   10
+      3.2 One-to-many .............................................   11
+         3.2.1 To a list ..........................................   11
+         3.2.2 To a group (channel) ...............................   11
+         3.2.3 To a host/server mask ..............................   12
+      3.3 One to all ..............................................   12
+
+
+
+Oikarinen & Reed                                                [Page 1]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+         3.3.1 Client to Client ...................................   12
+         3.3.2 Clients to Server ..................................   12
+         3.3.3 Server to Server ...................................   12
+   4. MESSAGE DETAILS .............................................   13
+      4.1 Connection Registration .................................   13
+         4.1.1 Password message ...................................   14
+         4.1.2 Nickname message ...................................   14
+         4.1.3 User message .......................................   15
+         4.1.4 Server message .....................................   16
+         4.1.5 Operator message ...................................   17
+         4.1.6 Quit message .......................................   17
+         4.1.7 Server Quit message ................................   18
+      4.2 Channel operations ......................................   19
+         4.2.1 Join message .......................................   19
+         4.2.2 Part message .......................................   20
+         4.2.3 Mode message .......................................   21
+            4.2.3.1 Channel modes .................................   21
+            4.2.3.2 User modes ....................................   22
+         4.2.4 Topic message ......................................   23
+         4.2.5 Names message ......................................   24
+         4.2.6 List message .......................................   24
+         4.2.7 Invite message .....................................   25
+         4.2.8 Kick message .......................................   25
+      4.3 Server queries and commands .............................   26
+         4.3.1 Version message ....................................   26
+         4.3.2 Stats message ......................................   27
+         4.3.3 Links message ......................................   28
+         4.3.4 Time message .......................................   29
+         4.3.5 Connect message ....................................   29
+         4.3.6 Trace message ......................................   30
+         4.3.7 Admin message ......................................   31
+         4.3.8 Info message .......................................   31
+      4.4 Sending messages ........................................   32
+         4.4.1 Private messages ...................................   32
+         4.4.2 Notice messages ....................................   33
+      4.5 User-based queries ......................................   33
+         4.5.1 Who query ..........................................   33
+         4.5.2 Whois query ........................................   34
+         4.5.3 Whowas message .....................................   35
+      4.6 Miscellaneous messages ..................................   35
+         4.6.1 Kill message .......................................   36
+         4.6.2 Ping message .......................................   37
+         4.6.3 Pong message .......................................   37
+         4.6.4 Error message ......................................   38
+   5. OPTIONAL MESSAGES ...........................................   38
+      5.1 Away message ............................................   38
+      5.2 Rehash command ..........................................   39
+      5.3 Restart command .........................................   39
+
+
+
+Oikarinen & Reed                                                [Page 2]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+      5.4 Summon message ..........................................   40
+      5.5 Users message ...........................................   40
+      5.6 Operwall command ........................................   41
+      5.7 Userhost message ........................................   42
+      5.8 Ison message ............................................   42
+   6. REPLIES .....................................................   43
+      6.1 Error Replies ...........................................   43
+      6.2 Command responses .......................................   48
+      6.3 Reserved numerics .......................................   56
+   7. Client and server authentication ............................   56
+   8. Current Implementations Details .............................   56
+      8.1 Network protocol: TCP ...................................   57
+         8.1.1 Support of Unix sockets ............................   57
+      8.2 Command Parsing .........................................   57
+      8.3 Message delivery ........................................   57
+      8.4 Connection 'Liveness' ...................................   58
+      8.5 Establishing a server-client connection .................   58
+      8.6 Establishing a server-server connection .................   58
+         8.6.1 State information exchange when connecting .........   59
+      8.7 Terminating server-client connections ...................   59
+      8.8 Terminating server-server connections ...................   59
+      8.9 Tracking nickname changes ...............................   60
+      8.10 Flood control of clients ...............................   60
+      8.11 Non-blocking lookups ...................................   61
+         8.11.1 Hostname (DNS) lookups ............................   61
+         8.11.2 Username (Ident) lookups ..........................   61
+      8.12 Configuration file .....................................   61
+         8.12.1 Allowing clients to connect .......................   62
+         8.12.2 Operators .........................................   62
+         8.12.3 Allowing servers to connect .......................   62
+         8.12.4 Administrivia .....................................   63
+      8.13 Channel membership .....................................   63
+   9. Current problems ............................................   63
+      9.1 Scalability .............................................   63
+      9.2 Labels ..................................................   63
+         9.2.1 Nicknames ..........................................   63
+         9.2.2 Channels ...........................................   64
+         9.2.3 Servers ............................................   64
+      9.3 Algorithms ..............................................   64
+   10. Support and availability ...................................   64
+   11. Security Considerations ....................................   65
+   12. Authors' Addresses .........................................   65
+
+
+
+
+
+
+
+
+
+Oikarinen & Reed                                                [Page 3]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+1.  INTRODUCTION
+
+   The IRC (Internet Relay Chat) protocol has been designed over a
+   number of years for use with text based conferencing.  This document
+   describes the current IRC protocol.
+
+   The IRC protocol has been developed on systems using the TCP/IP
+   network protocol, although there is no requirement that this remain
+   the only sphere in which it operates.
+
+   IRC itself is a teleconferencing system, which (through the use of
+   the client-server model) is well-suited to running on many machines
+   in a distributed fashion.  A typical setup involves a single process
+   (the server) forming a central point for clients (or other servers)
+   to connect to, performing the required message delivery/multiplexing
+   and other functions.
+
+1.1 Servers
+
+   The server forms the backbone of IRC, providing a point to which
+   clients may connect to to talk to each other, and a point for other
+   servers to connect to, forming an IRC network.  The only network
+   configuration allowed for IRC servers is that of a spanning tree [see
+   Fig. 1] where each server acts as a central node for the rest of the
+   net it sees.
+
+
+                           [ Server 15 ]  [ Server 13 ] [ Server 14]
+                                 /                \         /
+                                /                  \       /
+        [ Server 11 ] ------ [ Server 1 ]       [ Server 12]
+                              /        \          /
+                             /          \        /
+                  [ Server 2 ]          [ Server 3 ]
+                    /       \                      \
+                   /         \                      \
+           [ Server 4 ]    [ Server 5 ]         [ Server 6 ]
+            /    |    \                           /
+           /     |     \                         /
+          /      |      \____                   /
+         /       |           \                 /
+ [ Server 7 ] [ Server 8 ] [ Server 9 ]   [ Server 10 ]
+
+                                  :
+                               [ etc. ]
+                                  :
+
+                 [ Fig. 1. Format of IRC server network ]
+
+
+
+Oikarinen & Reed                                                [Page 4]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+1.2 Clients
+
+   A client is anything connecting to a server that is not another
+   server.  Each client is distinguished from other clients by a unique
+   nickname having a maximum length of nine (9) characters.  See the
+   protocol grammar rules for what may and may not be used in a
+   nickname.  In addition to the nickname, all servers must have the
+   following information about all clients: the real name of the host
+   that the client is running on, the username of the client on that
+   host, and the server to which the client is connected.
+
+1.2.1 Operators
+
+   To allow a reasonable amount of order to be kept within the IRC
+   network, a special class of clients (operators) is allowed to perform
+   general maintenance functions on the network.  Although the powers
+   granted to an operator can be considered as 'dangerous', they are
+   nonetheless required.  Operators should be able to perform basic
+   network tasks such as disconnecting and reconnecting servers as
+   needed to prevent long-term use of bad network routing.  In
+   recognition of this need, the protocol discussed herein provides for
+   operators only to be able to perform such functions.  See sections
+   4.1.7 (SQUIT) and 4.3.5 (CONNECT).
+
+   A more controversial power of operators is the ability  to  remove  a
+   user  from  the connected network by 'force', i.e. operators are able
+   to close the connection between any client and server.   The
+   justification for  this  is delicate since its abuse is both
+   destructive and annoying.  For further details on this type of
+   action, see section 4.6.1 (KILL).
+
+1.3 Channels
+
+   A channel is a named group of one or more clients which will all
+   receive messages addressed to that channel.  The channel is created
+   implicitly when the first client joins it, and the channel ceases to
+   exist when the last client leaves it.  While channel exists, any
+   client can reference the channel using the name of the channel.
+
+   Channels names are strings (beginning with a '&' or '#' character) of
+   length up to 200 characters.  Apart from the the requirement that the
+   first character being either '&' or '#'; the only restriction on a
+   channel name is that it may not contain any spaces (' '), a control G
+   (^G or ASCII 7), or a comma (',' which is used as a list item
+   separator by the protocol).
+
+   There are two types of channels allowed by this protocol.  One is a
+   distributed channel which is known to all the servers that are
+
+
+
+Oikarinen & Reed                                                [Page 5]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+   connected to the network. These channels are marked by the first
+   character being a only clients on the server where it exists may join
+   it.  These are distinguished by a leading '&' character.  On top of
+   these two types, there are the various channel modes available to
+   alter the characteristics of individual channels.  See section 4.2.3
+   (MODE command) for more details on this.
+
+   To create a new channel or become part of an existing channel, a user
+   is required to JOIN the channel.  If the channel doesn't exist prior
+   to joining, the channel is created and the creating user becomes a
+   channel operator.  If the channel already exists, whether or not your
+   request to JOIN that channel is honoured depends on the current modes
+   of the channel. For example, if the channel is invite-only, (+i),
+   then you may only join if invited.  As part of the protocol, a user
+   may be a part of several channels at once, but a limit of ten (10)
+   channels is recommended as being ample for both experienced and
+   novice users.  See section 8.13 for more information on this.
+
+   If the IRC network becomes disjoint because of a split between two
+   servers, the channel on each side is only composed of those clients
+   which are connected to servers on the respective sides of the split,
+   possibly ceasing to exist on one side of the split.  When the split
+   is healed, the connecting servers announce to each other who they
+   think is in each channel and the mode of that channel.  If the
+   channel exists on both sides, the JOINs and MODEs are interpreted in
+   an inclusive manner so that both sides of the new connection will
+   agree about which clients are in the channel and what modes the
+   channel has.
+
+1.3.1 Channel Operators
+
+   The channel operator (also referred to as a "chop" or "chanop") on a
+   given channel is considered to 'own' that channel.  In recognition of
+   this status, channel operators are endowed with certain powers which
+   enable them to keep control and some sort of sanity in their channel.
+   As an owner of a channel, a channel operator is not required to have
+   reasons for their actions, although if their actions are generally
+   antisocial or otherwise abusive, it might be reasonable to ask an IRC
+   operator to intervene, or for the usersjust leave and go elsewhere
+   and form their own channel.
+
+   The commands which may only be used by channel operators are:
+
+        KICK    - Eject a client from the channel
+        MODE    - Change the channel's mode
+        INVITE  - Invite a client to an invite-only channel (mode +i)
+        TOPIC   - Change the channel topic in a mode +t channel
+
+
+
+
+Oikarinen & Reed                                                [Page 6]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+   A channel operator is identified by the '@' symbol next to their
+   nickname whenever it is associated with a channel (ie replies to the
+   NAMES, WHO and WHOIS commands).
+
+2. The IRC Specification
+
+2.1 Overview
+
+   The protocol as described herein is for use both with server to
+   server and client to server connections.  There are, however, more
+   restrictions on client connections (which are considered to be
+   untrustworthy) than on server connections.
+
+2.2 Character codes
+
+   No specific character set is specified. The protocol is based on a a
+   set of codes which are composed of eight (8) bits, making up an
+   octet.  Each message may be composed of any number of these octets;
+   however, some octet values are used for control codes which act as
+   message delimiters.
+
+   Regardless of being an 8-bit protocol, the delimiters and keywords
+   are such that protocol is mostly usable from USASCII terminal and a
+   telnet connection.
+
+   Because of IRC's scandanavian origin, the characters {}| are
+   considered to be the lower case equivalents of the characters []\,
+   respectively. This is a critical issue when determining the
+   equivalence of two nicknames.
+
+2.3 Messages
+
+   Servers and clients send eachother messages which may or may not
+   generate a reply.  If the message contains a valid command, as
+   described in later sections, the client should expect a reply as
+   specified but it is not advised to wait forever for the reply; client
+   to server and server to server communication is essentially
+   asynchronous in nature.
+
+   Each IRC message may consist of up to three main parts: the prefix
+   (optional), the command, and the command parameters (of which there
+   may be up to 15).  The prefix, command, and all parameters are
+   separated by one (or more) ASCII space character(s) (0x20).
+
+   The presence of a prefix is indicated with a single leading ASCII
+   colon character (':', 0x3b), which must be the first character of the
+   message itself.  There must be no gap (whitespace) between the colon
+   and the prefix.  The prefix is used by servers to indicate the true
+
+
+
+Oikarinen & Reed                                                [Page 7]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+   origin of the message.  If the prefix is missing from the message, it
+   is assumed to have originated from the connection from which it was
+   received.  Clients should not use prefix when sending a message from
+   themselves; if they use a prefix, the only valid prefix is the
+   registered nickname associated with the client.  If the source
+   identified by the prefix cannot be found from the server's internal
+   database, or if the source is registered from a different link than
+   from which the message arrived, the server must ignore the message
+   silently.
+
+   The command must either be a valid IRC command or a three (3) digit
+   number represented in ASCII text.
+
+   IRC messages are always lines of characters terminated with a CR-LF
+   (Carriage Return - Line Feed) pair, and these messages shall not
+   exceed 512 characters in length, counting all characters including
+   the trailing CR-LF. Thus, there are 510 characters maximum allowed
+   for the command and its parameters.  There is no provision for
+   continuation message lines.  See section 7 for more details about
+   current implementations.
+
+2.3.1 Message format in 'pseudo' BNF
+
+   The protocol messages must be extracted from the contiguous stream of
+   octets.  The current solution is to designate two characters, CR and
+   LF, as message separators.   Empty  messages  are  silently  ignored,
+   which permits  use  of  the  sequence  CR-LF  between  messages
+   without extra problems.
+
+   The extracted message is parsed into the components <prefix>,
+   <command> and list of parameters matched either by <middle> or
+   <trailing> components.
+
+   The BNF representation for this is:
+
+
+<message>  ::= [':' <prefix> <SPACE> ] <command> <params> <crlf>
+<prefix>   ::= <servername> | <nick> [ '!' <user> ] [ '@' <host> ]
+<command>  ::= <letter> { <letter> } | <number> <number> <number>
+<SPACE>    ::= ' ' { ' ' }
+<params>   ::= <SPACE> [ ':' <trailing> | <middle> <params> ]
+
+<middle>   ::= <Any *non-empty* sequence of octets not including SPACE
+               or NUL or CR or LF, the first of which may not be ':'>
+<trailing> ::= <Any, possibly *empty*, sequence of octets not including
+                 NUL or CR or LF>
+
+<crlf>     ::= CR LF
+
+
+
+Oikarinen & Reed                                                [Page 8]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+NOTES:
+
+  1)    <SPACE> is consists only of SPACE character(s) (0x20).
+        Specially notice that TABULATION, and all other control
+        characters are considered NON-WHITE-SPACE.
+
+  2)    After extracting the parameter list, all parameters are equal,
+        whether matched by <middle> or <trailing>. <Trailing> is just
+        a syntactic trick to allow SPACE within parameter.
+
+  3)    The fact that CR and LF cannot appear in parameter strings is
+        just artifact of the message framing. This might change later.
+
+  4)    The NUL character is not special in message framing, and
+        basically could end up inside a parameter, but as it would
+        cause extra complexities in normal C string handling. Therefore
+        NUL is not allowed within messages.
+
+  5)    The last parameter may be an empty string.
+
+  6)    Use of the extended prefix (['!' <user> ] ['@' <host> ]) must
+        not be used in server to server communications and is only
+        intended for server to client messages in order to provide
+        clients with more useful information about who a message is
+        from without the need for additional queries.
+
+   Most protocol messages specify additional semantics and syntax for
+   the extracted parameter strings dictated by their position in the
+   list.  For example, many server commands will assume that the first
+   parameter after the command is the list of targets, which can be
+   described with:
+
+   <target>     ::= <to> [ "," <target> ]
+   <to>         ::= <channel> | <user> '@' <servername> | <nick> | <mask>
+   <channel>    ::= ('#' | '&') <chstring>
+   <servername> ::= <host>
+   <host>       ::= see RFC 952 [DNS:4] for details on allowed hostnames
+   <nick>       ::= <letter> { <letter> | <number> | <special> }
+   <mask>       ::= ('#' | '$') <chstring>
+   <chstring>   ::= <any 8bit code except SPACE, BELL, NUL, CR, LF and
+                     comma (',')>
+
+   Other parameter syntaxes are:
+
+   <user>       ::= <nonwhite> { <nonwhite> }
+   <letter>     ::= 'a' ... 'z' | 'A' ... 'Z'
+   <number>     ::= '0' ... '9'
+   <special>    ::= '-' | '[' | ']' | '\' | '`' | '^' | '{' | '}'
+
+
+
+Oikarinen & Reed                                                [Page 9]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+   <nonwhite>   ::= <any 8bit code except SPACE (0x20), NUL (0x0), CR
+                     (0xd), and LF (0xa)>
+
+2.4 Numeric replies
+
+   Most of the messages sent to the server generate a reply of some
+   sort.  The most common reply is the numeric reply, used for both
+   errors and normal replies.  The numeric reply must be sent as one
+   message consisting of the sender prefix, the three digit numeric, and
+   the target of the reply.  A numeric reply is not allowed to originate
+   from a client; any such messages received by a server are silently
+   dropped. In all other respects, a numeric reply is just like a normal
+   message, except that the keyword is made up of 3 numeric digits
+   rather than a string of letters.  A list of different replies is
+   supplied in section 6.
+
+3. IRC Concepts.
+
+   This section is devoted to describing the actual concepts behind  the
+   organization  of  the  IRC  protocol and how the current
+   implementations deliver different classes of messages.
+
+
+
+                          1--\
+                              A        D---4
+                          2--/ \      /
+                                B----C
+                               /      \
+                              3        E
+
+   Servers: A, B, C, D, E         Clients: 1, 2, 3, 4
+
+                    [ Fig. 2. Sample small IRC network ]
+
+3.1 One-to-one communication
+
+   Communication on a one-to-one basis is usually only performed by
+   clients, since most server-server traffic is not a result of servers
+   talking only to each other.  To provide a secure means for clients to
+   talk to each other, it is required that all servers be able to send a
+   message in exactly one direction along the spanning tree in order to
+   reach any client.  The path of a message being delivered is the
+   shortest path between any two points on the spanning tree.
+
+   The following examples all refer to Figure 2 above.
+
+
+
+
+
+Oikarinen & Reed                                               [Page 10]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+Example 1:
+     A message between clients 1 and 2 is only seen by server A, which
+     sends it straight to client 2.
+
+Example 2:
+     A message between clients 1 and 3 is seen by servers A & B, and
+     client 3.  No other clients or servers are allowed see the message.
+
+Example 3:
+     A message between clients 2 and 4 is seen by servers A, B, C & D
+     and client 4 only.
+
+3.2 One-to-many
+
+   The main goal of IRC is to provide a  forum  which  allows  easy  and
+   efficient  conferencing (one to many conversations).  IRC offers
+   several means to achieve this, each serving its own purpose.
+
+3.2.1 To a list
+
+   The least efficient style of one-to-many conversation is through
+   clients talking to a 'list' of users.  How this is done is almost
+   self explanatory: the client gives a list of destinations to which
+   the message is to be delivered and the server breaks it up and
+   dispatches a separate copy of the message to each given destination.
+   This isn't as efficient as using a group since the destination list
+   is broken up and the dispatch sent without checking to make sure
+   duplicates aren't sent down each path.
+
+3.2.2 To a group (channel)
+
+   In IRC the channel has a role equivalent to that of the multicast
+   group; their existence is dynamic (coming and going as people join
+   and leave channels) and the actual conversation carried out on a
+   channel is only sent to servers which are supporting users on a given
+   channel.  If there are multiple users on a server in the same
+   channel, the message text is sent only once to that server and then
+   sent to each client on the channel.  This action is then repeated for
+   each client-server combination until the original message has fanned
+   out and reached each member of the channel.
+
+   The following examples all refer to Figure 2.
+
+Example 4:
+     Any channel with 1 client in it. Messages to the channel go to the
+     server and then nowhere else.
+
+
+
+
+
+Oikarinen & Reed                                               [Page 11]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+Example 5:
+     2 clients in a channel. All messages traverse a path as if they
+     were private messages between the two clients outside a channel.
+
+Example 6:
+     Clients 1, 2 and 3 in a channel.  All messages to the channel are
+     sent to all clients and only those servers which must be traversed
+     by the message if it were a private message to a single client.  If
+     client 1 sends a message, it goes back to client 2 and then via
+     server B to client 3.
+
+3.2.3 To a host/server mask
+
+   To provide IRC operators with some mechanism to send  messages  to  a
+   large body of related users, host and server mask messages are
+   provided.  These messages are sent to users whose host or server
+   information  match that  of  the mask.  The messages are only sent to
+   locations where users are, in a fashion similar to that of channels.
+
+3.3 One-to-all
+
+   The one-to-all type of message is better described as a broadcast
+   message, sent to all clients or servers or both.  On a large network
+   of users and servers, a single message can result in a lot of traffic
+   being sent over the network in an effort to reach all of the desired
+   destinations.
+
+   For some messages, there is no option but to broadcast it to all
+   servers so that the state information held by each server is
+   reasonably consistent between servers.
+
+3.3.1 Client-to-Client
+
+   There is no class of message which, from a single message, results in
+   a message being sent to every other client.
+
+3.3.2 Client-to-Server
+
+   Most of the commands which result in a change of state information
+   (such as channel membership, channel mode, user status, etc) must be
+   sent to all servers by default, and this distribution may not be
+   changed by the client.
+
+3.3.3 Server-to-Server.
+
+   While most messages between servers are distributed to all 'other'
+   servers, this is only required for any message that affects either a
+   user, channel or server.  Since these are the basic items found in
+
+
+
+Oikarinen & Reed                                               [Page 12]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+   IRC, nearly all messages originating from a server are broadcast to
+   all other connected servers.
+
+4. Message details
+
+   On the following pages are descriptions of each message recognized by
+   the IRC server and client.  All commands described in this section
+   must be implemented by any server for this protocol.
+
+   Where the reply ERR_NOSUCHSERVER is listed, it means that the
+   <server> parameter could not be found.  The server must not send any
+   other replies after this for that command.
+
+   The server to which a client is connected is required to parse the
+   complete message, returning any appropriate errors.  If the server
+   encounters a fatal error while parsing a message, an error must be
+   sent back to the client and the parsing terminated.  A fatal error
+   may be considered to be incorrect command, a destination which is
+   otherwise unknown to the server (server, nick or channel names fit
+   this category), not enough parameters or incorrect privileges.
+
+   If a full set of parameters is presented, then each must be checked
+   for validity and appropriate responses sent back to the client.  In
+   the case of messages which use parameter lists using the comma as an
+   item separator, a reply must be sent for each item.
+
+   In the examples below, some messages appear using the full format:
+
+   :Name COMMAND parameter list
+
+   Such examples represent a message from "Name" in transit between
+   servers, where it is essential to include the name of the original
+   sender of the message so remote servers may send back a reply along
+   the correct path.
+
+4.1 Connection Registration
+
+   The commands described here are used to register a connection with an
+   IRC server as either a user or a server as well as correctly
+   disconnect.
+
+   A "PASS" command is not required for either client or server
+   connection to be registered, but it must precede the server message
+   or the latter of the NICK/USER combination.  It is strongly
+   recommended that all server connections have a password in order to
+   give some level of security to the actual connections.  The
+   recommended order for a client to register is as follows:
+
+
+
+
+Oikarinen & Reed                                               [Page 13]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+           1. Pass message
+           2. Nick message
+           3. User message
+
+4.1.1 Password message
+
+
+      Command: PASS
+   Parameters: <password>
+
+   The PASS command is used to set a 'connection password'.  The
+   password can and must be set before any attempt to register the
+   connection is made.  Currently this requires that clients send a PASS
+   command before sending the NICK/USER combination and servers *must*
+   send a PASS command before any SERVER command.  The password supplied
+   must match the one contained in the C/N lines (for servers) or I
+   lines (for clients).  It is possible to send multiple PASS commands
+   before registering but only the last one sent is used for
+   verification and it may not be changed once registered.  Numeric
+   Replies:
+
+           ERR_NEEDMOREPARAMS              ERR_ALREADYREGISTRED
+
+   Example:
+
+           PASS secretpasswordhere
+
+4.1.2 Nick message
+
+      Command: NICK
+   Parameters: <nickname> [ <hopcount> ]
+
+   NICK message is used to give user a nickname or change the previous
+   one.  The <hopcount> parameter is only used by servers to indicate
+   how far away a nick is from its home server.  A local connection has
+   a hopcount of 0.  If supplied by a client, it must be ignored.
+
+   If a NICK message arrives at a server which already knows about an
+   identical nickname for another client, a nickname collision occurs.
+   As a result of a nickname collision, all instances of the nickname
+   are removed from the server's database, and a KILL command is issued
+   to remove the nickname from all other server's database. If the NICK
+   message causing the collision was a nickname change, then the
+   original (old) nick must be removed as well.
+
+   If the server recieves an identical NICK from a client which is
+   directly connected, it may issue an ERR_NICKCOLLISION to the local
+   client, drop the NICK command, and not generate any kills.
+
+
+
+Oikarinen & Reed                                               [Page 14]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+   Numeric Replies:
+
+           ERR_NONICKNAMEGIVEN             ERR_ERRONEUSNICKNAME
+           ERR_NICKNAMEINUSE               ERR_NICKCOLLISION
+
+   Example:
+
+   NICK Wiz                        ; Introducing new nick "Wiz".
+
+   :WiZ NICK Kilroy                ; WiZ changed his nickname to Kilroy.
+
+4.1.3 User message
+
+      Command: USER
+   Parameters: <username> <hostname> <servername> <realname>
+
+   The USER message is used at the beginning of connection to specify
+   the username, hostname, servername and realname of s new user.  It is
+   also used in communication between servers to indicate new user
+   arriving on IRC, since only after both USER and NICK have been
+   received from a client does a user become registered.
+
+   Between servers USER must to be prefixed with client's NICKname.
+   Note that hostname and servername are normally ignored by the IRC
+   server when the USER command comes from a directly connected client
+   (for security reasons), but they are used in server to server
+   communication.  This means that a NICK must always be sent to a
+   remote server when a new user is being introduced to the rest of the
+   network before the accompanying USER is sent.
+
+   It must be noted that realname parameter must be the last parameter,
+   because it may contain space characters and must be prefixed with a
+   colon (':') to make sure this is recognised as such.
+
+   Since it is easy for a client to lie about its username by relying
+   solely on the USER message, the use of an "Identity Server" is
+   recommended.  If the host which a user connects from has such a
+   server enabled the username is set to that as in the reply from the
+   "Identity Server".
+
+   Numeric Replies:
+
+           ERR_NEEDMOREPARAMS              ERR_ALREADYREGISTRED
+
+   Examples:
+
+
+   USER guest tolmoon tolsun :Ronnie Reagan
+
+
+
+Oikarinen & Reed                                               [Page 15]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+                                   ; User registering themselves with a
+                                   username of "guest" and real name
+                                   "Ronnie Reagan".
+
+
+   :testnick USER guest tolmoon tolsun :Ronnie Reagan
+                                   ; message between servers with the
+                                   nickname for which the USER command
+                                   belongs to
+
+4.1.4 Server message
+
+      Command: SERVER
+   Parameters: <servername> <hopcount> <info>
+
+   The server message is used to tell a server that the other end of a
+   new connection is a server. This message is also used to pass server
+   data over whole net.  When a new server is connected to net,
+   information about it be broadcast to the whole network.  <hopcount>
+   is used to give all servers some internal information on how far away
+   all servers are.  With a full server list, it would be possible to
+   construct a map of the entire server tree, but hostmasks prevent this
+   from being done.
+
+   The SERVER message must only be accepted from either (a) a connection
+   which is yet to be registered and is attempting to register as a
+   server, or (b) an existing connection to another server, in  which
+   case the SERVER message is introducing a new server behind that
+   server.
+
+   Most errors that occur with the receipt of a SERVER command result in
+   the connection being terminated by the destination host (target
+   SERVER).  Error replies are usually sent using the "ERROR" command
+   rather than the numeric since the ERROR command has several useful
+   properties which make it useful here.
+
+   If a SERVER message is parsed and attempts to introduce a server
+   which is already known to the receiving server, the connection from
+   which that message must be closed (following the correct procedures),
+   since a duplicate route to a server has formed and the acyclic nature
+   of the IRC tree broken.
+
+   Numeric Replies:
+
+           ERR_ALREADYREGISTRED
+
+   Example:
+
+
+
+
+Oikarinen & Reed                                               [Page 16]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+SERVER test.oulu.fi 1 :[tolsun.oulu.fi] Experimental server
+                                ; New server test.oulu.fi introducing
+                                itself and attempting to register.  The
+                                name in []'s is the hostname for the
+                                host running test.oulu.fi.
+
+
+:tolsun.oulu.fi SERVER csd.bu.edu 5 :BU Central Server
+                                ; Server tolsun.oulu.fi is our uplink
+                                for csd.bu.edu which is 5 hops away.
+
+4.1.5 Oper
+
+      Command: OPER
+   Parameters: <user> <password>
+
+   OPER message is used by a normal user to obtain operator privileges.
+   The combination of <user> and <password> are required to gain
+   Operator privileges.
+
+   If the client sending the OPER command supplies the correct password
+   for the given user, the server then informs the rest of the network
+   of the new operator by issuing a "MODE +o" for the clients nickname.
+
+   The OPER message is client-server only.
+
+   Numeric Replies:
+
+           ERR_NEEDMOREPARAMS              RPL_YOUREOPER
+           ERR_NOOPERHOST                  ERR_PASSWDMISMATCH
+
+   Example:
+
+   OPER foo bar                    ; Attempt to register as an operator
+                                   using a username of "foo" and "bar" as
+                                   the password.
+
+4.1.6 Quit
+
+      Command: QUIT
+   Parameters: [<Quit message>]
+
+   A client session is ended with a quit message.  The server must close
+   the connection to a client which sends a QUIT message. If a "Quit
+   Message" is given, this will be sent instead of the default message,
+   the nickname.
+
+   When netsplits (disconnecting of two servers) occur, the quit message
+
+
+
+Oikarinen & Reed                                               [Page 17]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+   is composed of the names of two servers involved, separated by a
+   space.  The first name is that of the server which is still connected
+   and the second name is that of the server that has become
+   disconnected.
+
+   If, for some other reason, a client connection is closed without  the
+   client  issuing  a  QUIT  command  (e.g.  client  dies and EOF occurs
+   on socket), the server is required to fill in the quit  message  with
+   some sort  of  message  reflecting the nature of the event which
+   caused it to happen.
+
+   Numeric Replies:
+
+           None.
+
+   Examples:
+
+   QUIT :Gone to have lunch        ; Preferred message format.
+
+4.1.7 Server quit message
+
+      Command: SQUIT
+   Parameters: <server> <comment>
+
+   The SQUIT message is needed to tell about quitting or dead servers.
+   If a server wishes to break the connection to another server it must
+   send a SQUIT message to the other server, using the the name of the
+   other server as the server parameter, which then closes its
+   connection to the quitting server.
+
+   This command is also available operators to help keep a network of
+   IRC servers connected in an orderly fashion.  Operators may also
+   issue an SQUIT message for a remote server connection.  In this case,
+   the SQUIT must be parsed by each server inbetween the operator and
+   the remote server, updating the view of the network held by each
+   server as explained below.
+
+   The <comment> should be supplied by all operators who execute a SQUIT
+   for a remote server (that is not connected to the server they are
+   currently on) so that other operators are aware for the reason of
+   this action.  The <comment> is also filled in by servers which may
+   place an error or similar message here.
+
+   Both of the servers which are on either side of the connection being
+   closed are required to to send out a SQUIT message (to all its other
+   server connections) for all other servers which are considered to be
+   behind that link.
+
+
+
+
+Oikarinen & Reed                                               [Page 18]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+   Similarly, a QUIT message must be sent to the other connected servers
+   rest of the network on behalf of all clients behind that link.  In
+   addition to this, all channel members of a channel which lost a
+   member due to the split must be sent a QUIT message.
+
+   If a server connection is terminated prematurely (e.g. the server  on
+   the  other  end  of  the  link  died),  the  server  which  detects
+   this disconnection is required to inform the rest of  the  network
+   that  the connection  has  closed  and  fill  in  the comment field
+   with something appropriate.
+
+   Numeric replies:
+
+           ERR_NOPRIVILEGES                ERR_NOSUCHSERVER
+
+   Example:
+
+   SQUIT tolsun.oulu.fi :Bad Link ? ; the server link tolson.oulu.fi has
+                                   been terminated because of "Bad Link".
+
+   :Trillian SQUIT cm22.eng.umd.edu :Server out of control
+                                    ; message from Trillian to disconnect
+                                   "cm22.eng.umd.edu" from the net
+                                    because "Server out of control".
+
+4.2 Channel operations
+
+   This group of messages is concerned with manipulating channels, their
+   properties (channel modes), and their contents (typically clients).
+   In implementing these, a number of race conditions are inevitable
+   when clients at opposing ends of a network send commands which will
+   ultimately clash.  It is also required that servers keep a nickname
+   history to ensure that wherever a <nick> parameter is given, the
+   server check its history in case it has recently been changed.
+
+4.2.1 Join message
+
+      Command: JOIN
+   Parameters: <channel>{,<channel>} [<key>{,<key>}]
+
+   The JOIN command is used by client to start listening a specific
+   channel. Whether or not a client is allowed to join a channel is
+   checked only by the server the client is connected to; all other
+   servers automatically add the user to the channel when it is received
+   from other servers.  The conditions which affect this are as follows:
+
+           1.  the user must be invited if the channel is invite-only;
+
+
+
+
+Oikarinen & Reed                                               [Page 19]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+           2.  the user's nick/username/hostname must not match any
+               active bans;
+
+           3.  the correct key (password) must be given if it is set.
+
+   These are discussed in more detail under the MODE command (see
+   section 4.2.3 for more details).
+
+   Once a user has joined a channel, they receive notice about all
+   commands their server receives which affect the channel.  This
+   includes MODE, KICK, PART, QUIT and of course PRIVMSG/NOTICE.  The
+   JOIN command needs to be broadcast to all servers so that each server
+   knows where to find the users who are on the channel.  This allows
+   optimal delivery of PRIVMSG/NOTICE messages to the channel.
+
+   If a JOIN is successful, the user is then sent the channel's topic
+   (using RPL_TOPIC) and the list of users who are on the channel (using
+   RPL_NAMREPLY), which must include the user joining.
+
+   Numeric Replies:
+
+           ERR_NEEDMOREPARAMS              ERR_BANNEDFROMCHAN
+           ERR_INVITEONLYCHAN              ERR_BADCHANNELKEY
+           ERR_CHANNELISFULL               ERR_BADCHANMASK
+           ERR_NOSUCHCHANNEL               ERR_TOOMANYCHANNELS
+           RPL_TOPIC
+
+   Examples:
+
+   JOIN #foobar                    ; join channel #foobar.
+
+   JOIN &foo fubar                 ; join channel &foo using key "fubar".
+
+   JOIN #foo,&bar fubar            ; join channel #foo using key "fubar"
+                                   and &bar using no key.
+
+   JOIN #foo,#bar fubar,foobar     ; join channel #foo using key "fubar".
+                                   and channel #bar using key "foobar".
+
+   JOIN #foo,#bar                  ; join channels #foo and #bar.
+
+   :WiZ JOIN #Twilight_zone        ; JOIN message from WiZ
+
+4.2.2 Part message
+
+      Command: PART
+   Parameters: <channel>{,<channel>}
+
+
+
+
+Oikarinen & Reed                                               [Page 20]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+   The PART message causes the client sending the message to be removed
+   from the list of active users for all given channels listed in the
+   parameter string.
+
+   Numeric Replies:
+
+           ERR_NEEDMOREPARAMS              ERR_NOSUCHCHANNEL
+           ERR_NOTONCHANNEL
+
+   Examples:
+
+   PART #twilight_zone             ; leave channel "#twilight_zone"
+
+   PART #oz-ops,&group5            ; leave both channels "&group5" and
+                                   "#oz-ops".
+
+4.2.3 Mode message
+
+      Command: MODE
+
+   The MODE command is a dual-purpose command in IRC.  It allows both
+   usernames and channels to have their mode changed.  The rationale for
+   this choice is that one day nicknames will be obsolete and the
+   equivalent property will be the channel.
+
+   When parsing MODE messages, it is recommended that the entire message
+   be parsed first and then the changes which resulted then passed on.
+
+4.2.3.1 Channel modes
+
+   Parameters: <channel> {[+|-]|o|p|s|i|t|n|b|v} [<limit>] [<user>]
+               [<ban mask>]
+
+   The MODE command is provided so that channel operators may change the
+   characteristics of `their' channel.  It is also required that servers
+   be able to change channel modes so that channel operators may be
+   created.
+
+   The various modes available for channels are as follows:
+
+           o - give/take channel operator privileges;
+           p - private channel flag;
+           s - secret channel flag;
+           i - invite-only channel flag;
+           t - topic settable by channel operator only flag;
+           n - no messages to channel from clients on the outside;
+           m - moderated channel;
+           l - set the user limit to channel;
+
+
+
+Oikarinen & Reed                                               [Page 21]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+           b - set a ban mask to keep users out;
+           v - give/take the ability to speak on a moderated channel;
+           k - set a channel key (password).
+
+   When using the 'o' and 'b' options, a restriction on a total of three
+   per mode command has been imposed.  That is, any combination of 'o'
+   and
+
+4.2.3.2 User modes
+
+   Parameters: <nickname> {[+|-]|i|w|s|o}
+
+   The user MODEs are typically changes which affect either how the
+   client is seen by others or what 'extra' messages the client is sent.
+   A user MODE command may only be accepted if both the sender of the
+   message and the nickname given as a parameter are both the same.
+
+   The available modes are as follows:
+
+           i - marks a users as invisible;
+           s - marks a user for receipt of server notices;
+           w - user receives wallops;
+           o - operator flag.
+
+   Additional modes may be available later on.
+
+   If a user attempts to make themselves an operator using the "+o"
+   flag, the attempt should be ignored.  There is no restriction,
+   however, on anyone `deopping' themselves (using "-o").  Numeric
+   Replies:
+
+           ERR_NEEDMOREPARAMS              RPL_CHANNELMODEIS
+           ERR_CHANOPRIVSNEEDED            ERR_NOSUCHNICK
+           ERR_NOTONCHANNEL                ERR_KEYSET
+           RPL_BANLIST                     RPL_ENDOFBANLIST
+           ERR_UNKNOWNMODE                 ERR_NOSUCHCHANNEL
+
+           ERR_USERSDONTMATCH              RPL_UMODEIS
+           ERR_UMODEUNKNOWNFLAG
+
+   Examples:
+
+           Use of Channel Modes:
+
+MODE #Finnish +im               ; Makes #Finnish channel moderated and
+                                'invite-only'.
+
+MODE #Finnish +o Kilroy         ; Gives 'chanop' privileges to Kilroy on
+
+
+
+Oikarinen & Reed                                               [Page 22]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+                                channel #Finnish.
+
+MODE #Finnish +v Wiz            ; Allow WiZ to speak on #Finnish.
+
+MODE #Fins -s                   ; Removes 'secret' flag from channel
+                                #Fins.
+
+MODE #42 +k oulu                ; Set the channel key to "oulu".
+
+MODE #eu-opers +l 10            ; Set the limit for the number of users
+                                on channel to 10.
+
+MODE &oulu +b                   ; list ban masks set for channel.
+
+MODE &oulu +b *!*@*             ; prevent all users from joining.
+
+MODE &oulu +b *!*@*.edu         ; prevent any user from a hostname
+                                matching *.edu from joining.
+
+        Use of user Modes:
+
+:MODE WiZ -w                    ; turns reception of WALLOPS messages
+                                off for WiZ.
+
+:Angel MODE Angel +i            ; Message from Angel to make themselves
+                                invisible.
+
+MODE WiZ -o                     ; WiZ 'deopping' (removing operator
+                                status).  The plain reverse of this
+                                command ("MODE WiZ +o") must not be
+                                allowed from users since would bypass
+                                the OPER command.
+
+4.2.4 Topic message
+
+      Command: TOPIC
+   Parameters: <channel> [<topic>]
+
+   The TOPIC message is used to change or view the topic of a channel.
+   The topic for channel <channel> is returned if there is no <topic>
+   given.  If the <topic> parameter is present, the topic for that
+   channel will be changed, if the channel modes permit this action.
+
+   Numeric Replies:
+
+           ERR_NEEDMOREPARAMS              ERR_NOTONCHANNEL
+           RPL_NOTOPIC                     RPL_TOPIC
+           ERR_CHANOPRIVSNEEDED
+
+
+
+Oikarinen & Reed                                               [Page 23]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+   Examples:
+
+   :Wiz TOPIC #test :New topic     ;User Wiz setting the topic.
+
+   TOPIC #test :another topic      ;set the topic on #test to "another
+                                   topic".
+
+   TOPIC #test                     ; check the topic for #test.
+
+4.2.5 Names message
+
+      Command: NAMES
+   Parameters: [<channel>{,<channel>}]
+
+   By using the NAMES command, a user can list all nicknames that are
+   visible to them on any channel that they can see.  Channel names
+   which they can see are those which aren't private (+p) or secret (+s)
+   or those which they are actually on.  The <channel> parameter
+   specifies which channel(s) to return information about if valid.
+   There is no error reply for bad channel names.
+
+   If no <channel> parameter is given, a list of all channels and their
+   occupants is returned.  At the end of this list, a list of users who
+   are visible but either not on any channel or not on a visible channel
+   are listed as being on `channel' "*".
+
+   Numerics:
+
+           RPL_NAMREPLY                    RPL_ENDOFNAMES
+
+   Examples:
+
+   NAMES #twilight_zone,#42        ; list visible users on #twilight_zone
+                                   and #42 if the channels are visible to
+                                   you.
+
+   NAMES                           ; list all visible channels and users
+
+4.2.6 List message
+
+      Command: LIST
+   Parameters: [<channel>{,<channel>} [<server>]]
+
+   The list message is used to list channels and their topics.  If  the
+   <channel>  parameter  is  used,  only  the  status  of  that  channel
+   is displayed.  Private  channels  are  listed  (without  their
+   topics)  as channel "Prv" unless the client generating the query is
+   actually on that channel.  Likewise, secret channels are not listed
+
+
+
+Oikarinen & Reed                                               [Page 24]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+   at  all  unless  the client is a member of the channel in question.
+
+   Numeric Replies:
+
+           ERR_NOSUCHSERVER                RPL_LISTSTART
+           RPL_LIST                        RPL_LISTEND
+
+   Examples:
+
+   LIST                            ; List all channels.
+
+   LIST #twilight_zone,#42         ; List channels #twilight_zone and #42
+
+4.2.7 Invite message
+
+      Command: INVITE
+   Parameters: <nickname> <channel>
+
+   The INVITE message is used to invite users to a channel.  The
+   parameter <nickname> is the nickname of the person to be invited to
+   the target channel <channel>.  There is no requirement that the
+   channel the target user is being invited to must exist or be a valid
+   channel.  To invite a user to a channel which is invite only (MODE
+   +i), the client sending the invite must be recognised as being a
+   channel operator on the given channel.
+
+   Numeric Replies:
+
+           ERR_NEEDMOREPARAMS              ERR_NOSUCHNICK
+           ERR_NOTONCHANNEL                ERR_USERONCHANNEL
+           ERR_CHANOPRIVSNEEDED
+           RPL_INVITING                    RPL_AWAY
+
+   Examples:
+
+   :Angel INVITE Wiz #Dust         ; User Angel inviting WiZ to channel
+                                   #Dust
+
+   INVITE Wiz #Twilight_Zone       ; Command to invite WiZ to
+                                   #Twilight_zone
+
+4.2.8 Kick command
+
+      Command: KICK
+   Parameters: <channel> <user> [<comment>]
+
+   The KICK command can be  used  to  forcibly  remove  a  user  from  a
+   channel.   It  'kicks  them  out'  of the channel (forced PART).
+
+
+
+Oikarinen & Reed                                               [Page 25]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+   Only a channel operator may kick another user out of a  channel.
+   Each  server that  receives  a KICK message checks that it is valid
+   (ie the sender is actually a  channel  operator)  before  removing
+   the  victim  from  the channel.
+
+   Numeric Replies:
+
+           ERR_NEEDMOREPARAMS              ERR_NOSUCHCHANNEL
+           ERR_BADCHANMASK                 ERR_CHANOPRIVSNEEDED
+           ERR_NOTONCHANNEL
+
+   Examples:
+
+KICK &Melbourne Matthew         ; Kick Matthew from &Melbourne
+
+KICK #Finnish John :Speaking English
+                                ; Kick John from #Finnish using
+                                "Speaking English" as the reason
+                                (comment).
+
+:WiZ KICK #Finnish John         ; KICK message from WiZ to remove John
+                                from channel #Finnish
+
+NOTE:
+     It is possible to extend the KICK command parameters to the
+following:
+
+<channel>{,<channel>} <user>{,<user>} [<comment>]
+
+4.3 Server queries and commands
+
+   The server query group of commands has been designed to return
+   information about any server which is connected to the network.  All
+   servers connected must respond to these queries and respond
+   correctly.  Any invalid response (or lack thereof) must be considered
+   a sign of a broken server and it must be disconnected/disabled as
+   soon as possible until the situation is remedied.
+
+   In these queries, where a parameter appears as "<server>", it will
+   usually mean it can be a nickname or a server or a wildcard name of
+   some sort.  For each parameter, however, only one query and set of
+   replies is to be generated.
+
+4.3.1 Version message
+
+      Command: VERSION
+   Parameters: [<server>]
+
+
+
+
+Oikarinen & Reed                                               [Page 26]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+   The VERSION message is used  to  query  the  version  of  the  server
+   program.  An optional parameter <server> is used to query the version
+   of the server program which a client is not directly connected to.
+
+   Numeric Replies:
+
+           ERR_NOSUCHSERVER                RPL_VERSION
+
+   Examples:
+
+   :Wiz VERSION *.se               ; message from Wiz to check the version
+                                   of a server matching "*.se"
+
+   VERSION tolsun.oulu.fi          ; check the version of server
+                                   "tolsun.oulu.fi".
+
+4.3.2 Stats message
+
+      Command: STATS
+   Parameters: [<query> [<server>]]
+
+   The stats message is used to query statistics of certain server.  If
+   <server> parameter is omitted, only the end of stats reply is sent
+   back.  The implementation of this command is highly dependent on the
+   server which replies, although the server must be able to supply
+   information as described by the queries below (or similar).
+
+   A query may be given by any single letter which is only checked by
+   the destination server (if given as the <server> parameter) and is
+   otherwise passed on by intermediate servers, ignored and unaltered.
+   The following queries are those found in the current IRC
+   implementation and provide a large portion of the setup information
+   for that server.  Although these may not be supported in the same way
+   by other versions, all servers should be able to supply a valid reply
+   to a STATS query which is consistent with the reply formats currently
+   used and the purpose of the query.
+
+   The currently supported queries are:
+
+           c - returns a list of servers which the server may connect
+               to or allow connections from;
+           h - returns a list of servers which are either forced to be
+               treated as leaves or allowed to act as hubs;
+           i - returns a list of hosts which the server allows a client
+               to connect from;
+           k - returns a list of banned username/hostname combinations
+               for that server;
+           l - returns a list of the server's connections, showing how
+
+
+
+Oikarinen & Reed                                               [Page 27]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+               long each connection has been established and the traffic
+               over that connection in bytes and messages for each
+               direction;
+           m - returns a list of commands supported by the server and
+               the usage count for each if the usage count is non zero;
+           o - returns a list of hosts from which normal clients may
+               become operators;
+           y - show Y (Class) lines from server's configuration file;
+           u - returns a string showing how long the server has been up.
+
+   Numeric Replies:
+
+           ERR_NOSUCHSERVER
+           RPL_STATSCLINE                  RPL_STATSNLINE
+           RPL_STATSILINE                  RPL_STATSKLINE
+           RPL_STATSQLINE                  RPL_STATSLLINE
+           RPL_STATSLINKINFO               RPL_STATSUPTIME
+           RPL_STATSCOMMANDS               RPL_STATSOLINE
+           RPL_STATSHLINE                  RPL_ENDOFSTATS
+
+   Examples:
+
+STATS m                         ; check the command usage for the server
+                                you are connected to
+
+:Wiz STATS c eff.org            ; request by WiZ for C/N line
+                                information from server eff.org
+
+4.3.3 Links message
+
+      Command: LINKS
+   Parameters: [[<remote server>] <server mask>]
+
+   With LINKS, a user can list all servers which are known by the server
+   answering the query.  The returned list of servers must match the
+   mask, or if no mask is given, the full list is returned.
+
+   If <remote server> is given in addition to <server mask>, the LINKS
+   command is forwarded to the first server found that matches that name
+   (if any), and that server is then required to answer the query.
+
+   Numeric Replies:
+
+           ERR_NOSUCHSERVER
+           RPL_LINKS                       RPL_ENDOFLINKS
+
+   Examples:
+
+
+
+
+Oikarinen & Reed                                               [Page 28]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+LINKS *.au                      ; list all servers which have a name
+                                that matches *.au;
+
+:WiZ LINKS *.bu.edu *.edu       ; LINKS message from WiZ to the first
+                                server matching *.edu for a list of
+                                servers matching *.bu.edu.
+
+4.3.4 Time message
+
+      Command: TIME
+   Parameters: [<server>]
+
+   The time message is used to query local time from the specified
+   server. If the server parameter is not given, the server handling the
+   command must reply to the query.
+
+   Numeric Replies:
+
+           ERR_NOSUCHSERVER                RPL_TIME
+
+   Examples:
+
+   TIME tolsun.oulu.fi             ; check the time on the server
+                                   "tolson.oulu.fi"
+
+   Angel TIME *.au                 ; user angel checking the time on a
+                                   server matching "*.au"
+
+4.3.5 Connect message
+
+      Command: CONNECT
+   Parameters: <target server> [<port> [<remote server>]]
+
+   The CONNECT command can be used to force a server to try to establish
+   a new connection to another server immediately.  CONNECT is a
+   privileged command and is to be available only to IRC Operators.  If
+   a remote server is given then the CONNECT attempt is made by that
+   server to <target server> and <port>.
+
+   Numeric Replies:
+
+           ERR_NOSUCHSERVER                ERR_NOPRIVILEGES
+           ERR_NEEDMOREPARAMS
+
+   Examples:
+
+CONNECT tolsun.oulu.fi          ; Attempt to connect a server to
+                                tolsun.oulu.fi
+
+
+
+Oikarinen & Reed                                               [Page 29]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+:WiZ CONNECT eff.org 6667 csd.bu.edu
+                                ; CONNECT attempt by WiZ to get servers
+                                eff.org and csd.bu.edu connected on port
+                                6667.
+
+4.3.6 Trace message
+
+      Command: TRACE
+   Parameters: [<server>]
+
+   TRACE command is used to find the route to specific server.  Each
+   server that processes this message must tell the sender about it by
+   sending a reply indicating it is a pass-through link, forming a chain
+   of replies similar to that gained from using "traceroute".  After
+   sending this reply back, it must then send the TRACE message to the
+   next server until given server is reached.  If the <server> parameter
+   is omitted, it is recommended that TRACE command send a message to
+   the sender telling which servers the current server has direct
+   connection to.
+
+   If the destination given by "<server>" is an actual server, then the
+   destination server is required to report all servers and users which
+   are connected to it, although only operators are permitted to see
+   users present.  If the destination given by <server> is a nickname,
+   they only a reply for that nickname is given.
+
+   Numeric Replies:
+
+           ERR_NOSUCHSERVER
+
+   If the TRACE message is destined for another server, all intermediate
+   servers must return a RPL_TRACELINK reply to indicate that the TRACE
+   passed through it and where its going next.
+
+           RPL_TRACELINK
+   A TRACE reply may be composed of any number of the following numeric
+   replies.
+
+           RPL_TRACECONNECTING             RPL_TRACEHANDSHAKE
+           RPL_TRACEUNKNOWN                RPL_TRACEOPERATOR
+           RPL_TRACEUSER                   RPL_TRACESERVER
+           RPL_TRACESERVICE                RPL_TRACENEWTYPE
+           RPL_TRACECLASS
+
+   Examples:
+
+TRACE *.oulu.fi                 ; TRACE to a server matching *.oulu.fi
+
+
+
+
+Oikarinen & Reed                                               [Page 30]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+:WiZ TRACE AngelDust            ; TRACE issued by WiZ to nick AngelDust
+
+4.3.7 Admin command
+
+      Command: ADMIN
+   Parameters: [<server>]
+
+   The admin message is used to find the name of the administrator of
+   the given server, or current server if <server> parameter is omitted.
+   Each server must have the ability to forward ADMIN messages to other
+   servers.
+
+   Numeric Replies:
+
+           ERR_NOSUCHSERVER
+           RPL_ADMINME                     RPL_ADMINLOC1
+           RPL_ADMINLOC2                   RPL_ADMINEMAIL
+
+   Examples:
+
+   ADMIN tolsun.oulu.fi            ; request an ADMIN reply from
+                                   tolsun.oulu.fi
+
+   :WiZ ADMIN *.edu                ; ADMIN request from WiZ for first
+                                   server found to match *.edu.
+
+4.3.8 Info command
+
+      Command: INFO
+   Parameters: [<server>]
+
+   The INFO command is required to return information which describes
+   the server: its version, when it was compiled, the patchlevel, when
+   it was started, and any other miscellaneous information which may be
+   considered to be relevant.
+
+   Numeric Replies:
+
+           ERR_NOSUCHSERVER
+           RPL_INFO                        RPL_ENDOFINFO
+
+   Examples:
+
+   INFO csd.bu.edu                 ; request an INFO reply from
+   csd.bu.edu
+
+   :Avalon INFO *.fi               ; INFO request from Avalon for first
+                                   server found to match *.fi.
+
+
+
+Oikarinen & Reed                                               [Page 31]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+   INFO Angel                      ; request info from the server that
+                                   Angel is connected to.
+
+4.4 Sending messages
+
+   The main purpose of the IRC protocol is to provide a base for clients
+   to communicate with each other.  PRIVMSG and NOTICE are the only
+   messages available which actually perform delivery of a text message
+   from one client to another - the rest just make it possible and try
+   to ensure it happens in a reliable and structured manner.
+
+4.4.1 Private messages
+
+      Command: PRIVMSG
+   Parameters: <receiver>{,<receiver>} <text to be sent>
+
+   PRIVMSG is used to send private messages between users.  <receiver>
+   is the nickname of the receiver of the message.  <receiver> can also
+   be a list of names or channels separated with commas.
+
+   The <receiver> parameter may also me a host mask  (#mask)  or  server
+   mask  ($mask).   In  both cases the server will only send the PRIVMSG
+   to those who have a server or host matching the mask.  The mask  must
+   have at  least  1  (one)  "."  in it and no wildcards following the
+   last ".".  This requirement exists to prevent people sending messages
+   to  "#*"  or "$*",  which  would  broadcast  to  all  users; from
+   experience, this is abused more than used responsibly and properly.
+   Wildcards are  the  '*' and  '?'   characters.   This  extension  to
+   the PRIVMSG command is only available to Operators.
+
+   Numeric Replies:
+
+           ERR_NORECIPIENT                 ERR_NOTEXTTOSEND
+           ERR_CANNOTSENDTOCHAN            ERR_NOTOPLEVEL
+           ERR_WILDTOPLEVEL                ERR_TOOMANYTARGETS
+           ERR_NOSUCHNICK
+           RPL_AWAY
+
+   Examples:
+
+:Angel PRIVMSG Wiz :Hello are you receiving this message ?
+                                ; Message from Angel to Wiz.
+
+PRIVMSG Angel :yes I'm receiving it !receiving it !'u>(768u+1n) .br ;
+                                Message to Angel.
+
+PRIVMSG jto@tolsun.oulu.fi :Hello !
+                                ; Message to a client on server
+
+
+
+Oikarinen & Reed                                               [Page 32]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+                                tolsun.oulu.fi with username of "jto".
+
+PRIVMSG $*.fi :Server tolsun.oulu.fi rebooting.
+                                ; Message to everyone on a server which
+                                has a name matching *.fi.
+
+PRIVMSG #*.edu :NSFNet is undergoing work, expect interruptions
+                                ; Message to all users who come from a
+                                host which has a name matching *.edu.
+
+4.4.2 Notice
+
+      Command: NOTICE
+   Parameters: <nickname> <text>
+
+   The NOTICE message is used similarly to PRIVMSG.  The difference
+   between NOTICE and PRIVMSG is that automatic replies must never be
+   sent in response to a NOTICE message.  This rule applies to servers
+   too - they must not send any error reply back to the client on
+   receipt of a notice.  The object of this rule is to avoid loops
+   between a client automatically sending something in response to
+   something it received.  This is typically used by automatons (clients
+   with either an AI or other interactive program controlling their
+   actions) which are always seen to be replying lest they end up in a
+   loop with another automaton.
+
+   See PRIVMSG for more details on replies and examples.
+
+4.5 User based queries
+
+   User queries are a group of commands which are primarily concerned
+   with finding details on a particular user or group users.  When using
+   wildcards with any of these commands, if they match, they will only
+   return information on users who are 'visible' to you.  The visibility
+   of a user is determined as a combination of the user's mode and the
+   common set of channels you are both on.
+
+4.5.1 Who query
+
+      Command: WHO
+   Parameters: [<name> [<o>]]
+
+   The WHO message is used by a client to generate a query which returns
+   a list of information which 'matches' the <name> parameter given by
+   the client.  In the absence of the <name> parameter, all visible
+   (users who aren't invisible (user mode +i) and who don't have a
+   common channel with the requesting client) are listed.  The same
+   result can be achieved by using a <name> of "0" or any wildcard which
+
+
+
+Oikarinen & Reed                                               [Page 33]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+   will end up matching every entry possible.
+
+   The <name> passed to WHO is matched against users' host, server, real
+   name and nickname if the channel <name> cannot be found.
+
+   If the "o" parameter is passed only operators are returned according
+   to the name mask supplied.
+
+   Numeric Replies:
+
+           ERR_NOSUCHSERVER
+           RPL_WHOREPLY                    RPL_ENDOFWHO
+
+   Examples:
+
+   WHO *.fi                        ; List all users who match against
+                                   "*.fi".
+
+   WHO jto* o                      ; List all users with a match against
+                                   "jto*" if they are an operator.
+
+4.5.2 Whois query
+
+      Command: WHOIS
+   Parameters: [<server>] <nickmask>[,<nickmask>[,...]]
+
+   This message is used to query information about particular user.  The
+   server will answer this message with several numeric messages
+   indicating different statuses of each user which matches the nickmask
+   (if you are entitled to see them).  If no wildcard is present in the
+   <nickmask>, any information about that nick which you are allowed to
+   see is presented.  A comma (',') separated list of nicknames may be
+   given.
+
+   The latter version sends the query to a specific server.  It is
+   useful if you want to know how long the user in question has been
+   idle as only local server (ie. the server the user is directly
+   connected to) knows that information, while everything else is
+   globally known.
+
+   Numeric Replies:
+
+           ERR_NOSUCHSERVER                ERR_NONICKNAMEGIVEN
+           RPL_WHOISUSER                   RPL_WHOISCHANNELS
+           RPL_WHOISCHANNELS               RPL_WHOISSERVER
+           RPL_AWAY                        RPL_WHOISOPERATOR
+           RPL_WHOISIDLE                   ERR_NOSUCHNICK
+           RPL_ENDOFWHOIS
+
+
+
+Oikarinen & Reed                                               [Page 34]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+   Examples:
+
+   WHOIS wiz                       ; return available user information
+                                   about nick WiZ
+
+   WHOIS eff.org trillian          ; ask server eff.org for user
+                                   information about trillian
+
+4.5.3 Whowas
+
+      Command: WHOWAS
+   Parameters: <nickname> [<count> [<server>]]
+
+   Whowas asks for information about a nickname which no longer exists.
+   This may either be due to a nickname change or the user leaving IRC.
+   In response to this query, the server searches through its nickname
+   history, looking for any nicks which are lexically the same (no wild
+   card matching here).  The history is searched backward, returning the
+   most recent entry first.  If there are multiple entries, up to
+   <count> replies will be returned (or all of them if no <count>
+   parameter is given).  If a non-positive number is passed as being
+   <count>, then a full search is done.
+
+   Numeric Replies:
+
+           ERR_NONICKNAMEGIVEN             ERR_WASNOSUCHNICK
+           RPL_WHOWASUSER                  RPL_WHOISSERVER
+           RPL_ENDOFWHOWAS
+
+   Examples:
+
+   WHOWAS Wiz                      ; return all information in the nick
+                                   history about nick "WiZ";
+
+   WHOWAS Mermaid 9                ; return at most, the 9 most recent
+                                   entries in the nick history for
+                                   "Mermaid";
+
+   WHOWAS Trillian 1 *.edu         ; return the most recent history for
+                                   "Trillian" from the first server found
+                                   to match "*.edu".
+
+4.6 Miscellaneous messages
+
+   Messages in this category do not fit into any of the above categories
+   but are nonetheless still a part of and required by the protocol.
+
+
+
+
+
+Oikarinen & Reed                                               [Page 35]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+4.6.1 Kill message
+
+      Command: KILL
+   Parameters: <nickname> <comment>
+
+   The KILL message is used to cause a client-server connection to be
+   closed by the server which has the actual connection.  KILL is used
+   by servers when they encounter a duplicate entry in the list of valid
+   nicknames and is used to remove both entries.  It is also available
+   to operators.
+
+   Clients which have automatic reconnect algorithms effectively make
+   this command useless since the disconnection is only brief.  It does
+   however break the flow of data and can be used to stop large amounts
+   of being abused, any user may elect to receive KILL messages
+   generated for others to keep an 'eye' on would be trouble spots.
+
+   In an arena where nicknames are required to be globally unique at all
+   times, KILL messages are sent whenever 'duplicates' are detected
+   (that is an attempt to register two users with the same nickname) in
+   the hope that both of them will disappear and only 1 reappear.
+
+   The comment given must reflect the actual reason for the KILL.  For
+   server-generated KILLs it usually is made up of details concerning
+   the origins of the two conflicting nicknames.  For users it is left
+   up to them to provide an adequate reason to satisfy others who see
+   it.  To prevent/discourage fake KILLs from being generated to hide
+   the identify of the KILLer, the comment also shows a 'kill-path'
+   which is updated by each server it passes through, each prepending
+   its name to the path.
+
+   Numeric Replies:
+
+           ERR_NOPRIVILEGES                ERR_NEEDMOREPARAMS
+           ERR_NOSUCHNICK                  ERR_CANTKILLSERVER
+
+
+   KILL David (csd.bu.edu <- tolsun.oulu.fi)
+                                   ; Nickname collision between csd.bu.edu
+                                   and tolson.oulu.fi
+
+
+   NOTE:
+   It is recommended that only Operators be allowed to kill other users
+   with KILL message.  In an ideal world not even operators would need
+   to do this and it would be left to servers to deal with.
+
+
+
+
+
+Oikarinen & Reed                                               [Page 36]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+4.6.2 Ping message
+
+      Command: PING
+   Parameters: <server1> [<server2>]
+
+   The PING message is used to test the presence of an active client at
+   the other end of the connection.  A PING message is sent at regular
+   intervals if no other activity detected coming from a connection.  If
+   a connection fails to respond to a PING command within a set amount
+   of time, that connection is closed.
+
+   Any client which receives a PING message must respond to <server1>
+   (server which sent the PING message out) as quickly as possible with
+   an appropriate PONG message to indicate it is still there and alive.
+   Servers should not respond to PING commands but rely on PINGs from
+   the other end of the connection to indicate the connection is alive.
+   If the <server2> parameter is specified, the PING message gets
+   forwarded there.
+
+   Numeric Replies:
+
+           ERR_NOORIGIN                    ERR_NOSUCHSERVER
+
+   Examples:
+
+   PING tolsun.oulu.fi             ; server sending a PING message to
+                                   another server to indicate it is still
+                                   alive.
+
+   PING WiZ                        ; PING message being sent to nick WiZ
+
+4.6.3 Pong message
+
+      Command: PONG
+   Parameters: <daemon> [<daemon2>]
+
+   PONG message is a reply to ping message.  If parameter <daemon2> is
+   given this message must be forwarded to given daemon.  The <daemon>
+   parameter is the name of the daemon who has responded to PING message
+   and generated this message.
+
+   Numeric Replies:
+
+           ERR_NOORIGIN                    ERR_NOSUCHSERVER
+
+   Examples:
+
+   PONG csd.bu.edu tolsun.oulu.fi  ; PONG message from csd.bu.edu to
+
+
+
+Oikarinen & Reed                                               [Page 37]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+                                   tolsun.oulu.fi
+
+4.6.4 Error
+
+      Command: ERROR
+   Parameters: <error message>
+
+   The ERROR command is for use by servers when reporting a serious or
+   fatal error to its operators.  It may also be sent from one server to
+   another but must not be accepted from any normal unknown clients.
+
+   An ERROR message is for use for reporting errors which occur with a
+   server-to-server link only.  An ERROR message is sent to the server
+   at the other end (which sends it to all of its connected operators)
+   and to all operators currently connected.  It is not to be passed
+   onto any other servers by a server if it is received from a server.
+
+   When a server sends a received ERROR message to its operators, the
+   message should be encapsulated inside a NOTICE message, indicating
+   that the client was not responsible for the error.
+
+   Numerics:
+
+           None.
+
+   Examples:
+
+   ERROR :Server *.fi already exists; ERROR message to the other server
+                                   which caused this error.
+
+   NOTICE WiZ :ERROR from csd.bu.edu -- Server *.fi already exists
+                                   ; Same ERROR message as above but sent
+                                   to user WiZ on the other server.
+
+5. OPTIONALS
+
+   This section describes OPTIONAL messages.  They are not required in a
+   working server implementation of the protocol described herein.  In
+   the absence of the option, an error reply message must be generated
+   or an unknown command error.  If the message is destined for another
+   server to answer then it must be passed on (elementary parsing
+   required) The allocated numerics for this are listed with the
+   messages below.
+
+5.1 Away
+
+      Command: AWAY
+   Parameters: [message]
+
+
+
+Oikarinen & Reed                                               [Page 38]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+   With the AWAY message, clients can set an automatic reply string for
+   any PRIVMSG commands directed at them (not to a channel they are on).
+   The automatic reply is sent by the server to client sending the
+   PRIVMSG command.  The only replying server is the one to which the
+   sending client is connected to.
+
+   The AWAY message is used either with one parameter (to set an AWAY
+   message) or with no parameters (to remove the AWAY message).
+
+   Numeric Replies:
+
+           RPL_UNAWAY                      RPL_NOWAWAY
+
+   Examples:
+
+   AWAY :Gone to lunch.  Back in 5 ; set away message to "Gone to lunch.
+                                   Back in 5".
+
+   :WiZ AWAY                       ; unmark WiZ as being away.
+
+
+5.2 Rehash message
+
+      Command: REHASH
+   Parameters: None
+
+   The rehash message can be used by the operator to force the server to
+   re-read and process its configuration file.
+
+   Numeric Replies:
+
+        RPL_REHASHING                   ERR_NOPRIVILEGES
+
+Examples:
+
+REHASH                          ; message from client with operator
+                                status to server asking it to reread its
+                                configuration file.
+
+5.3 Restart message
+
+      Command: RESTART
+   Parameters: None
+
+   The restart message can only be used by an operator to force a server
+   restart itself.  This message is optional since it may be viewed as a
+   risk to allow arbitrary people to connect to a server as an operator
+   and execute this command, causing (at least) a disruption to service.
+
+
+
+Oikarinen & Reed                                               [Page 39]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+   The RESTART command must always be fully processed by the server to
+   which the sending client is connected and not be passed onto other
+   connected servers.
+
+   Numeric Replies:
+
+           ERR_NOPRIVILEGES
+
+   Examples:
+
+   RESTART                         ; no parameters required.
+
+5.4 Summon message
+
+      Command: SUMMON
+   Parameters: <user> [<server>]
+
+   The SUMMON command can be used to give users who are on a host
+   running an IRC server a message asking them to please join IRC.  This
+   message is only sent if the target server (a) has SUMMON enabled, (b)
+   the user is logged in and (c) the server process can write to the
+   user's tty (or similar).
+
+   If no <server> parameter is given it tries to summon <user> from the
+   server the client is connected to is assumed as the target.
+
+   If summon is not enabled in a server, it must return the
+   ERR_SUMMONDISABLED numeric and pass the summon message onwards.
+
+   Numeric Replies:
+
+           ERR_NORECIPIENT                 ERR_FILEERROR
+           ERR_NOLOGIN                     ERR_NOSUCHSERVER
+           RPL_SUMMONING
+
+   Examples:
+
+   SUMMON jto                      ; summon user jto on the server's host
+
+   SUMMON jto tolsun.oulu.fi       ; summon user jto on the host which a
+                                   server named "tolsun.oulu.fi" is
+                                   running.
+
+
+5.5 Users
+
+      Command: USERS
+   Parameters: [<server>]
+
+
+
+Oikarinen & Reed                                               [Page 40]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+   The USERS command returns a list of users logged into the server in a
+   similar  format  to  who(1),  rusers(1)  and finger(1).  Some people
+   may disable this command on their server for security related
+   reasons.   If disabled, the correct numeric must be returned to
+   indicate this.
+
+   Numeric Replies:
+
+           ERR_NOSUCHSERVER                ERR_FILEERROR
+           RPL_USERSSTART                  RPL_USERS
+           RPL_NOUSERS                     RPL_ENDOFUSERS
+           ERR_USERSDISABLED
+
+   Disabled Reply:
+
+           ERR_USERSDISABLED
+
+   Examples:
+
+USERS eff.org                   ; request a list of users logged in on
+                                server eff.org
+
+:John USERS tolsun.oulu.fi      ; request from John for a list of users
+                                logged in on server tolsun.oulu.fi
+
+5.6 Operwall message
+
+      Command: WALLOPS
+   Parameters: Text to be sent to all operators currently online
+
+   Sends  a  message  to  all   operators   currently   online.    After
+   implementing  WALLOPS  as  a user command it was found that it was
+   often and commonly abused as a means of sending a message to a lot
+   of  people (much  similar to WALL).  Due to this it is recommended
+   that the current implementation of  WALLOPS  be  used  as  an
+   example  by  allowing  and recognising only servers as the senders of
+   WALLOPS.
+
+   Numeric Replies:
+
+           ERR_NEEDMOREPARAMS
+
+   Examples:
+
+   :csd.bu.edu WALLOPS :Connect '*.uiuc.edu 6667' from Joshua; WALLOPS
+                                   message from csd.bu.edu announcing a
+                                   CONNECT message it received and acted
+                                   upon from Joshua.
+
+
+
+Oikarinen & Reed                                               [Page 41]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+5.7 Userhost message
+
+      Command: USERHOST
+   Parameters: <nickname>{<space><nickname>}
+
+   The USERHOST command takes a list of up to 5 nicknames, each
+   separated by a space character and returns a list of information
+   about each nickname that it found.  The returned list has each reply
+   separated by a space.
+
+   Numeric Replies:
+
+           RPL_USERHOST                    ERR_NEEDMOREPARAMS
+
+   Examples:
+
+   USERHOST Wiz Michael Marty p    ;USERHOST request for information on
+                                   nicks "Wiz", "Michael", "Marty" and "p"
+
+5.8 Ison message
+
+      Command: ISON
+   Parameters: <nickname>{<space><nickname>}
+
+   The ISON command was implemented to provide  a  quick  and  efficient
+   means  to get a response about whether a given nickname was currently
+   on IRC. ISON only takes one (1) parameter: a space-separated list of
+   nicks.  For  each  nickname in the list that is present, the server
+   adds that to its reply string.  Thus the reply string may return
+   empty (none  of  the given  nicks are present), an exact copy of the
+   parameter string (all of them present) or as any other subset of the
+   set of nicks  given  in  the parameter.  The only limit on the number
+   of nicks that may be checked is that the combined length must not be
+   too large as to cause the server to chop it off so it fits in 512
+   characters.
+
+   ISON is only be processed by the server local to the client sending
+   the command and thus not passed onto other servers for further
+   processing.
+
+   Numeric Replies:
+
+           RPL_ISON                ERR_NEEDMOREPARAMS
+
+   Examples:
+
+   ISON phone trillian WiZ jarlek Avalon Angel Monstah
+                                   ; Sample ISON request for 7 nicks.
+
+
+
+Oikarinen & Reed                                               [Page 42]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+6. REPLIES
+
+   The following is a list of numeric replies which are generated in
+   response to the commands given above.  Each numeric is given with its
+   number, name and reply string.
+
+6.1 Error Replies.
+
+        401     ERR_NOSUCHNICK
+                        "<nickname> :No such nick/channel"
+
+                - Used to indicate the nickname parameter supplied to a
+                  command is currently unused.
+
+        402     ERR_NOSUCHSERVER
+                        "<server name> :No such server"
+
+                - Used to indicate the server name given currently
+                  doesn't exist.
+
+        403     ERR_NOSUCHCHANNEL
+                        "<channel name> :No such channel"
+
+                - Used to indicate the given channel name is invalid.
+
+        404     ERR_CANNOTSENDTOCHAN
+                        "<channel name> :Cannot send to channel"
+
+                - Sent to a user who is either (a) not on a channel
+                  which is mode +n or (b) not a chanop (or mode +v) on
+                  a channel which has mode +m set and is trying to send
+                  a PRIVMSG message to that channel.
+
+        405     ERR_TOOMANYCHANNELS
+                        "<channel name> :You have joined too many \
+                         channels"
+                - Sent to a user when they have joined the maximum
+                  number of allowed channels and they try to join
+                  another channel.
+
+        406     ERR_WASNOSUCHNICK
+                        "<nickname> :There was no such nickname"
+
+                - Returned by WHOWAS to indicate there is no history
+                  information for that nickname.
+
+        407     ERR_TOOMANYTARGETS
+                        "<target> :Duplicate recipients. No message \
+
+
+
+Oikarinen & Reed                                               [Page 43]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+                         delivered"
+
+                - Returned to a client which is attempting to send a
+                  PRIVMSG/NOTICE using the user@host destination format
+                  and for a user@host which has several occurrences.
+
+        409     ERR_NOORIGIN
+                        ":No origin specified"
+
+                - PING or PONG message missing the originator parameter
+                  which is required since these commands must work
+                  without valid prefixes.
+
+        411     ERR_NORECIPIENT
+                        ":No recipient given (<command>)"
+        412     ERR_NOTEXTTOSEND
+                        ":No text to send"
+        413     ERR_NOTOPLEVEL
+                        "<mask> :No toplevel domain specified"
+        414     ERR_WILDTOPLEVEL
+                        "<mask> :Wildcard in toplevel domain"
+
+                - 412 - 414 are returned by PRIVMSG to indicate that
+                  the message wasn't delivered for some reason.
+                  ERR_NOTOPLEVEL and ERR_WILDTOPLEVEL are errors that
+                  are returned when an invalid use of
+                  "PRIVMSG $<server>" or "PRIVMSG #<host>" is attempted.
+
+        421     ERR_UNKNOWNCOMMAND
+                        "<command> :Unknown command"
+
+                - Returned to a registered client to indicate that the
+                  command sent is unknown by the server.
+
+        422     ERR_NOMOTD
+                        ":MOTD File is missing"
+
+                - Server's MOTD file could not be opened by the server.
+
+        423     ERR_NOADMININFO
+                        "<server> :No administrative info available"
+
+                - Returned by a server in response to an ADMIN message
+                  when there is an error in finding the appropriate
+                  information.
+
+        424     ERR_FILEERROR
+                ":File error doing <file op> on <file>"
+
+
+
+Oikarinen & Reed                                               [Page 44]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+                - Generic error message used to report a failed file
+                  operation during the processing of a message.
+
+        431     ERR_NONICKNAMEGIVEN
+                        ":No nickname given"
+
+                - Returned when a nickname parameter expected for a
+                  command and isn't found.
+
+        432     ERR_ERRONEUSNICKNAME
+                        "<nick> :Erroneus nickname"
+
+                - Returned after receiving a NICK message which contains
+                  characters which do not fall in the defined set.  See
+                  section x.x.x for details on valid nicknames.
+
+        433     ERR_NICKNAMEINUSE
+                        "<nick> :Nickname is already in use"
+
+                - Returned when a NICK message is processed that results
+                  in an attempt to change to a currently existing
+                  nickname.
+
+        436     ERR_NICKCOLLISION
+                        "<nick> :Nickname collision KILL"
+
+                - Returned by a server to a client when it detects a
+                  nickname collision (registered of a NICK that
+                  already exists by another server).
+
+        441     ERR_USERNOTINCHANNEL
+                        "<nick> <channel> :They aren't on that channel"
+
+                - Returned by the server to indicate that the target
+                  user of the command is not on the given channel.
+
+        442     ERR_NOTONCHANNEL
+                        "<channel> :You're not on that channel"
+
+                - Returned by the server whenever a client tries to
+                  perform a channel effecting command for which the
+                  client isn't a member.
+
+        443     ERR_USERONCHANNEL
+                        "<user> <channel> :is already on channel"
+
+                - Returned when a client tries to invite a user to a
+                  channel they are already on.
+
+
+
+Oikarinen & Reed                                               [Page 45]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+        444     ERR_NOLOGIN
+                        "<user> :User not logged in"
+
+                - Returned by the summon after a SUMMON command for a
+                  user was unable to be performed since they were not
+                  logged in.
+
+        445     ERR_SUMMONDISABLED
+                        ":SUMMON has been disabled"
+
+                - Returned as a response to the SUMMON command.  Must be
+                  returned by any server which does not implement it.
+
+        446     ERR_USERSDISABLED
+                        ":USERS has been disabled"
+
+                - Returned as a response to the USERS command.  Must be
+                  returned by any server which does not implement it.
+
+        451     ERR_NOTREGISTERED
+                        ":You have not registered"
+
+                - Returned by the server to indicate that the client
+                  must be registered before the server will allow it
+                  to be parsed in detail.
+
+        461     ERR_NEEDMOREPARAMS
+                        "<command> :Not enough parameters"
+
+                - Returned by the server by numerous commands to
+                  indicate to the client that it didn't supply enough
+                  parameters.
+
+        462     ERR_ALREADYREGISTRED
+                        ":You may not reregister"
+
+                - Returned by the server to any link which tries to
+                  change part of the registered details (such as
+                  password or user details from second USER message).
+
+
+        463     ERR_NOPERMFORHOST
+                        ":Your host isn't among the privileged"
+
+                - Returned to a client which attempts to register with
+                  a server which does not been setup to allow
+                  connections from the host the attempted connection
+                  is tried.
+
+
+
+Oikarinen & Reed                                               [Page 46]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+        464     ERR_PASSWDMISMATCH
+                        ":Password incorrect"
+
+                - Returned to indicate a failed attempt at registering
+                  a connection for which a password was required and
+                  was either not given or incorrect.
+
+        465     ERR_YOUREBANNEDCREEP
+                        ":You are banned from this server"
+
+                - Returned after an attempt to connect and register
+                  yourself with a server which has been setup to
+                  explicitly deny connections to you.
+
+        467     ERR_KEYSET
+                        "<channel> :Channel key already set"
+        471     ERR_CHANNELISFULL
+                        "<channel> :Cannot join channel (+l)"
+        472     ERR_UNKNOWNMODE
+                        "<char> :is unknown mode char to me"
+        473     ERR_INVITEONLYCHAN
+                        "<channel> :Cannot join channel (+i)"
+        474     ERR_BANNEDFROMCHAN
+                        "<channel> :Cannot join channel (+b)"
+        475     ERR_BADCHANNELKEY
+                        "<channel> :Cannot join channel (+k)"
+        481     ERR_NOPRIVILEGES
+                        ":Permission Denied- You're not an IRC operator"
+
+                - Any command requiring operator privileges to operate
+                  must return this error to indicate the attempt was
+                  unsuccessful.
+
+        482     ERR_CHANOPRIVSNEEDED
+                        "<channel> :You're not channel operator"
+
+                - Any command requiring 'chanop' privileges (such as
+                  MODE messages) must return this error if the client
+                  making the attempt is not a chanop on the specified
+                  channel.
+
+        483     ERR_CANTKILLSERVER
+                        ":You cant kill a server!"
+
+                - Any attempts to use the KILL command on a server
+                  are to be refused and this error returned directly
+                  to the client.
+
+
+
+
+Oikarinen & Reed                                               [Page 47]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+        491     ERR_NOOPERHOST
+                        ":No O-lines for your host"
+
+                - If a client sends an OPER message and the server has
+                  not been configured to allow connections from the
+                  client's host as an operator, this error must be
+                  returned.
+
+        501     ERR_UMODEUNKNOWNFLAG
+                        ":Unknown MODE flag"
+
+                - Returned by the server to indicate that a MODE
+                  message was sent with a nickname parameter and that
+                  the a mode flag sent was not recognized.
+
+        502     ERR_USERSDONTMATCH
+                        ":Cant change mode for other users"
+
+                - Error sent to any user trying to view or change the
+                  user mode for a user other than themselves.
+
+6.2 Command responses.
+
+        300     RPL_NONE
+                        Dummy reply number. Not used.
+
+        302     RPL_USERHOST
+                        ":[<reply>{<space><reply>}]"
+
+                - Reply format used by USERHOST to list replies to
+                  the query list.  The reply string is composed as
+                  follows:
+
+                  <reply> ::= <nick>['*'] '=' <'+'|'-'><hostname>
+
+                  The '*' indicates whether the client has registered
+                  as an Operator.  The '-' or '+' characters represent
+                  whether the client has set an AWAY message or not
+                  respectively.
+
+        303     RPL_ISON
+                        ":[<nick> {<space><nick>}]"
+
+                - Reply format used by ISON to list replies to the
+                  query list.
+
+        301     RPL_AWAY
+                        "<nick> :<away message>"
+
+
+
+Oikarinen & Reed                                               [Page 48]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+        305     RPL_UNAWAY
+                        ":You are no longer marked as being away"
+        306     RPL_NOWAWAY
+                        ":You have been marked as being away"
+
+                - These replies are used with the AWAY command (if
+                  allowed).  RPL_AWAY is sent to any client sending a
+                  PRIVMSG to a client which is away.  RPL_AWAY is only
+                  sent by the server to which the client is connected.
+                  Replies RPL_UNAWAY and RPL_NOWAWAY are sent when the
+                  client removes and sets an AWAY message.
+
+        311     RPL_WHOISUSER
+                        "<nick> <user> <host> * :<real name>"
+        312     RPL_WHOISSERVER
+                        "<nick> <server> :<server info>"
+        313     RPL_WHOISOPERATOR
+                        "<nick> :is an IRC operator"
+        317     RPL_WHOISIDLE
+                        "<nick> <integer> :seconds idle"
+        318     RPL_ENDOFWHOIS
+                        "<nick> :End of /WHOIS list"
+        319     RPL_WHOISCHANNELS
+                        "<nick> :{[@|+]<channel><space>}"
+
+                - Replies 311 - 313, 317 - 319 are all replies
+                  generated in response to a WHOIS message.  Given that
+                  there are enough parameters present, the answering
+                  server must either formulate a reply out of the above
+                  numerics (if the query nick is found) or return an
+                  error reply.  The '*' in RPL_WHOISUSER is there as
+                  the literal character and not as a wild card.  For
+                  each reply set, only RPL_WHOISCHANNELS may appear
+                  more than once (for long lists of channel names).
+                  The '@' and '+' characters next to the channel name
+                  indicate whether a client is a channel operator or
+                  has been granted permission to speak on a moderated
+                  channel.  The RPL_ENDOFWHOIS reply is used to mark
+                  the end of processing a WHOIS message.
+
+        314     RPL_WHOWASUSER
+                        "<nick> <user> <host> * :<real name>"
+        369     RPL_ENDOFWHOWAS
+                        "<nick> :End of WHOWAS"
+
+                - When replying to a WHOWAS message, a server must use
+                  the replies RPL_WHOWASUSER, RPL_WHOISSERVER or
+                  ERR_WASNOSUCHNICK for each nickname in the presented
+
+
+
+Oikarinen & Reed                                               [Page 49]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+                  list.  At the end of all reply batches, there must
+                  be RPL_ENDOFWHOWAS (even if there was only one reply
+                  and it was an error).
+
+        321     RPL_LISTSTART
+                        "Channel :Users  Name"
+        322     RPL_LIST
+                        "<channel> <# visible> :<topic>"
+        323     RPL_LISTEND
+                        ":End of /LIST"
+
+                - Replies RPL_LISTSTART, RPL_LIST, RPL_LISTEND mark
+                  the start, actual replies with data and end of the
+                  server's response to a LIST command.  If there are
+                  no channels available to return, only the start
+                  and end reply must be sent.
+
+        324     RPL_CHANNELMODEIS
+                        "<channel> <mode> <mode params>"
+
+        331     RPL_NOTOPIC
+                        "<channel> :No topic is set"
+        332     RPL_TOPIC
+                        "<channel> :<topic>"
+
+                - When sending a TOPIC message to determine the
+                  channel topic, one of two replies is sent.  If
+                  the topic is set, RPL_TOPIC is sent back else
+                  RPL_NOTOPIC.
+
+        341     RPL_INVITING
+                        "<channel> <nick>"
+
+                - Returned by the server to indicate that the
+                  attempted INVITE message was successful and is
+                  being passed onto the end client.
+
+        342     RPL_SUMMONING
+                        "<user> :Summoning user to IRC"
+
+                - Returned by a server answering a SUMMON message to
+                  indicate that it is summoning that user.
+
+        351     RPL_VERSION
+                        "<version>.<debuglevel> <server> :<comments>"
+
+                - Reply by the server showing its version details.
+                  The <version> is the version of the software being
+
+
+
+Oikarinen & Reed                                               [Page 50]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+                  used (including any patchlevel revisions) and the
+                  <debuglevel> is used to indicate if the server is
+                  running in "debug mode".
+
+                  The "comments" field may contain any comments about
+                  the version or further version details.
+
+        352     RPL_WHOREPLY
+                        "<channel> <user> <host> <server> <nick> \
+                         <H|G>[*][@|+] :<hopcount> <real name>"
+        315     RPL_ENDOFWHO
+                        "<name> :End of /WHO list"
+
+                - The RPL_WHOREPLY and RPL_ENDOFWHO pair are used
+                  to answer a WHO message.  The RPL_WHOREPLY is only
+                  sent if there is an appropriate match to the WHO
+                  query.  If there is a list of parameters supplied
+                  with a WHO message, a RPL_ENDOFWHO must be sent
+                  after processing each list item with <name> being
+                  the item.
+
+        353     RPL_NAMREPLY
+                        "<channel> :[[@|+]<nick> [[@|+]<nick> [...]]]"
+        366     RPL_ENDOFNAMES
+                        "<channel> :End of /NAMES list"
+
+                - To reply to a NAMES message, a reply pair consisting
+                  of RPL_NAMREPLY and RPL_ENDOFNAMES is sent by the
+                  server back to the client.  If there is no channel
+                  found as in the query, then only RPL_ENDOFNAMES is
+                  returned.  The exception to this is when a NAMES
+                  message is sent with no parameters and all visible
+                  channels and contents are sent back in a series of
+                  RPL_NAMEREPLY messages with a RPL_ENDOFNAMES to mark
+                  the end.
+
+        364     RPL_LINKS
+                        "<mask> <server> :<hopcount> <server info>"
+        365     RPL_ENDOFLINKS
+                        "<mask> :End of /LINKS list"
+
+                - In replying to the LINKS message, a server must send
+                  replies back using the RPL_LINKS numeric and mark the
+                  end of the list using an RPL_ENDOFLINKS reply.
+
+        367     RPL_BANLIST
+                        "<channel> <banid>"
+        368     RPL_ENDOFBANLIST
+
+
+
+Oikarinen & Reed                                               [Page 51]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+                        "<channel> :End of channel ban list"
+
+                - When listing the active 'bans' for a given channel,
+                  a server is required to send the list back using the
+                  RPL_BANLIST and RPL_ENDOFBANLIST messages.  A separate
+                  RPL_BANLIST is sent for each active banid.  After the
+                  banids have been listed (or if none present) a
+                  RPL_ENDOFBANLIST must be sent.
+
+        371     RPL_INFO
+                        ":<string>"
+        374     RPL_ENDOFINFO
+                        ":End of /INFO list"
+
+                - A server responding to an INFO message is required to
+                  send all its 'info' in a series of RPL_INFO messages
+                  with a RPL_ENDOFINFO reply to indicate the end of the
+                  replies.
+
+        375     RPL_MOTDSTART
+                        ":- <server> Message of the day - "
+        372     RPL_MOTD
+                        ":- <text>"
+        376     RPL_ENDOFMOTD
+                        ":End of /MOTD command"
+
+                - When responding to the MOTD message and the MOTD file
+                  is found, the file is displayed line by line, with
+                  each line no longer than 80 characters, using
+                  RPL_MOTD format replies.  These should be surrounded
+                  by a RPL_MOTDSTART (before the RPL_MOTDs) and an
+                  RPL_ENDOFMOTD (after).
+
+        381     RPL_YOUREOPER
+                        ":You are now an IRC operator"
+
+                - RPL_YOUREOPER is sent back to a client which has
+                  just successfully issued an OPER message and gained
+                  operator status.
+
+        382     RPL_REHASHING
+                        "<config file> :Rehashing"
+
+                - If the REHASH option is used and an operator sends
+                  a REHASH message, an RPL_REHASHING is sent back to
+                  the operator.
+
+        391     RPL_TIME
+
+
+
+Oikarinen & Reed                                               [Page 52]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+                        "<server> :<string showing server's local time>"
+
+                - When replying to the TIME message, a server must send
+                  the reply using the RPL_TIME format above.  The string
+                  showing the time need only contain the correct day and
+                  time there.  There is no further requirement for the
+                  time string.
+
+        392     RPL_USERSSTART
+                        ":UserID   Terminal  Host"
+        393     RPL_USERS
+                        ":%-8s %-9s %-8s"
+        394     RPL_ENDOFUSERS
+                        ":End of users"
+        395     RPL_NOUSERS
+                        ":Nobody logged in"
+
+                - If the USERS message is handled by a server, the
+                  replies RPL_USERSTART, RPL_USERS, RPL_ENDOFUSERS and
+                  RPL_NOUSERS are used.  RPL_USERSSTART must be sent
+                  first, following by either a sequence of RPL_USERS
+                  or a single RPL_NOUSER.  Following this is
+                  RPL_ENDOFUSERS.
+
+        200     RPL_TRACELINK
+                        "Link <version & debug level> <destination> \
+                         <next server>"
+        201     RPL_TRACECONNECTING
+                        "Try. <class> <server>"
+        202     RPL_TRACEHANDSHAKE
+                        "H.S. <class> <server>"
+        203     RPL_TRACEUNKNOWN
+                        "???? <class> [<client IP address in dot form>]"
+        204     RPL_TRACEOPERATOR
+                        "Oper <class> <nick>"
+        205     RPL_TRACEUSER
+                        "User <class> <nick>"
+        206     RPL_TRACESERVER
+                        "Serv <class> <int>S <int>C <server> \
+                         <nick!user|*!*>@<host|server>"
+        208     RPL_TRACENEWTYPE
+                        "<newtype> 0 <client name>"
+        261     RPL_TRACELOG
+                        "File <logfile> <debug level>"
+
+                - The RPL_TRACE* are all returned by the server in
+                  response to the TRACE message.  How many are
+                  returned is dependent on the the TRACE message and
+
+
+
+Oikarinen & Reed                                               [Page 53]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+                  whether it was sent by an operator or not.  There
+                  is no predefined order for which occurs first.
+                  Replies RPL_TRACEUNKNOWN, RPL_TRACECONNECTING and
+                  RPL_TRACEHANDSHAKE are all used for connections
+                  which have not been fully established and are either
+                  unknown, still attempting to connect or in the
+                  process of completing the 'server handshake'.
+                  RPL_TRACELINK is sent by any server which handles
+                  a TRACE message and has to pass it on to another
+                  server.  The list of RPL_TRACELINKs sent in
+                  response to a TRACE command traversing the IRC
+                  network should reflect the actual connectivity of
+                  the servers themselves along that path.
+                  RPL_TRACENEWTYPE is to be used for any connection
+                  which does not fit in the other categories but is
+                  being displayed anyway.
+
+        211     RPL_STATSLINKINFO
+                        "<linkname> <sendq> <sent messages> \
+                         <sent bytes> <received messages> \
+                         <received bytes> <time open>"
+        212     RPL_STATSCOMMANDS
+                        "<command> <count>"
+        213     RPL_STATSCLINE
+                        "C <host> * <name> <port> <class>"
+        214     RPL_STATSNLINE
+                        "N <host> * <name> <port> <class>"
+        215     RPL_STATSILINE
+                        "I <host> * <host> <port> <class>"
+        216     RPL_STATSKLINE
+                        "K <host> * <username> <port> <class>"
+        218     RPL_STATSYLINE
+                        "Y <class> <ping frequency> <connect \
+                         frequency> <max sendq>"
+        219     RPL_ENDOFSTATS
+                        "<stats letter> :End of /STATS report"
+        241     RPL_STATSLLINE
+                        "L <hostmask> * <servername> <maxdepth>"
+        242     RPL_STATSUPTIME
+                        ":Server Up %d days %d:%02d:%02d"
+        243     RPL_STATSOLINE
+                        "O <hostmask> * <name>"
+        244     RPL_STATSHLINE
+                        "H <hostmask> * <servername>"
+
+        221     RPL_UMODEIS
+                        "<user mode string>"
+
+
+
+
+Oikarinen & Reed                                               [Page 54]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+                        - To answer a query about a client's own mode,
+                          RPL_UMODEIS is sent back.
+
+        251     RPL_LUSERCLIENT
+                        ":There are <integer> users and <integer> \
+                         invisible on <integer> servers"
+        252     RPL_LUSEROP
+                        "<integer> :operator(s) online"
+        253     RPL_LUSERUNKNOWN
+                        "<integer> :unknown connection(s)"
+        254     RPL_LUSERCHANNELS
+                        "<integer> :channels formed"
+        255     RPL_LUSERME
+                        ":I have <integer> clients and <integer> \
+                          servers"
+
+                        - In processing an LUSERS message, the server
+                          sends a set of replies from RPL_LUSERCLIENT,
+                          RPL_LUSEROP, RPL_USERUNKNOWN,
+                          RPL_LUSERCHANNELS and RPL_LUSERME.  When
+                          replying, a server must send back
+                          RPL_LUSERCLIENT and RPL_LUSERME.  The other
+                          replies are only sent back if a non-zero count
+                          is found for them.
+
+        256     RPL_ADMINME
+                        "<server> :Administrative info"
+        257     RPL_ADMINLOC1
+                        ":<admin info>"
+        258     RPL_ADMINLOC2
+                        ":<admin info>"
+        259     RPL_ADMINEMAIL
+                        ":<admin info>"
+
+                        - When replying to an ADMIN message, a server
+                          is expected to use replies RLP_ADMINME
+                          through to RPL_ADMINEMAIL and provide a text
+                          message with each.  For RPL_ADMINLOC1 a
+                          description of what city, state and country
+                          the server is in is expected, followed by
+                          details of the university and department
+                          (RPL_ADMINLOC2) and finally the administrative
+                          contact for the server (an email address here
+                          is required) in RPL_ADMINEMAIL.
+
+
+
+
+
+
+
+Oikarinen & Reed                                               [Page 55]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+6.3 Reserved numerics.
+
+   These numerics are not described above since they fall into one of
+   the following categories:
+
+        1. no longer in use;
+
+        2. reserved for future planned use;
+
+        3. in current use but are part of a non-generic 'feature' of
+           the current IRC server.
+
+        209     RPL_TRACECLASS          217     RPL_STATSQLINE
+        231     RPL_SERVICEINFO         232     RPL_ENDOFSERVICES
+        233     RPL_SERVICE             234     RPL_SERVLIST
+        235     RPL_SERVLISTEND
+        316     RPL_WHOISCHANOP         361     RPL_KILLDONE
+        362     RPL_CLOSING             363     RPL_CLOSEEND
+        373     RPL_INFOSTART           384     RPL_MYPORTIS
+        466     ERR_YOUWILLBEBANNED     476     ERR_BADCHANMASK
+        492     ERR_NOSERVICEHOST
+
+7. Client and server authentication
+
+   Clients and servers are both subject to the same level of
+   authentication.  For both, an IP number to hostname lookup (and
+   reverse check on this) is performed for all connections made to the
+   server.  Both connections are then subject to a password check (if
+   there is a password set for that connection).  These checks are
+   possible on all connections although the password check is only
+   commonly used with servers.
+
+   An additional check that is becoming of more and more common is that
+   of the username responsible for making the connection.  Finding the
+   username of the other end of the connection typically involves
+   connecting to an authentication server such as IDENT as described in
+   RFC 1413.
+
+   Given that without passwords it is not easy to reliably determine who
+   is on the other end of a network connection, use of passwords is
+   strongly recommended on inter-server connections in addition to any
+   other measures such as using an ident server.
+
+8. Current implementations
+
+   The only current implementation of this protocol is the IRC server,
+   version 2.8. Earlier versions may implement some or all of the
+   commands described by this document with NOTICE messages replacing
+
+
+
+Oikarinen & Reed                                               [Page 56]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+   many of the numeric replies.  Unfortunately, due to backward
+   compatibility requirements, the implementation of some parts of this
+   document varies with what is laid out.  On notable difference is:
+
+        * recognition that any LF or CR anywhere in a message marks the
+          end of that message (instead of requiring CR-LF);
+
+   The rest of this section deals with issues that are mostly of
+   importance to those who wish to implement a server but some parts
+   also apply directly to clients as well.
+
+8.1 Network protocol: TCP - why it is best used here.
+
+   IRC has been implemented on top of TCP since TCP supplies a reliable
+   network protocol which is well suited to this scale of conferencing.
+   The use of multicast IP is an alternative, but it is not widely
+   available or supported at the present time.
+
+8.1.1 Support of Unix sockets
+
+   Given that Unix domain sockets allow listen/connect operations, the
+   current implementation can be configured to listen and accept both
+   client and server connections on a Unix domain socket.  These are
+   recognized as sockets where the hostname starts with a '/'.
+
+   When providing any information about the connections on a Unix domain
+   socket, the server is required to supplant the actual hostname in
+   place of the pathname unless the actual socket name is being asked
+   for.
+
+8.2 Command Parsing
+
+   To provide useful 'non-buffered' network IO for clients and servers,
+   each connection is given its own private 'input buffer' in which the
+   results of the most recent read and parsing are kept.  A buffer size
+   of 512 bytes is used so as to hold 1 full message, although, this
+   will usually hold several commands.  The private buffer is parsed
+   after every read operation for valid messages.  When dealing with
+   multiple messages from one client in the buffer, care should be taken
+   in case one happens to cause the client to be 'removed'.
+
+8.3 Message delivery
+
+   It is common to find network links saturated or hosts to which you
+   are sending data unable to send data.  Although Unix typically
+   handles this through the TCP window and internal buffers, the server
+   often has large amounts of data to send (especially when a new
+   server-server link forms) and the small buffers provided in the
+
+
+
+Oikarinen & Reed                                               [Page 57]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+   kernel are not enough for the outgoing queue.  To alleviate this
+   problem, a "send queue" is used as a FIFO queue for data to be sent.
+   A typical "send queue" may grow to 200 Kbytes on a large IRC network
+   with a slow network connection when a new server connects.
+
+   When polling its connections, a server will first read and parse all
+   incoming data, queuing any data to be sent out. When all available
+   input is processed, the queued data is sent. This reduces the number
+   of write() system calls and helps TCP make bigger packets.
+
+8.4 Connection 'Liveness'
+
+   To detect when a connection has died or become unresponsive, the
+   server must ping each of its connections that it doesn't get a
+   response from in a given amount of time.
+
+   If a connection doesn't respond in time, its connection is closed
+   using the appropriate procedures.  A connection is also dropped if
+   its sendq grows beyond the maximum allowed, because it is better to
+   close a slow connection than have a server process block.
+
+8.5 Establishing a server to client connection
+
+   Upon connecting to an IRC server, a client is sent the MOTD (if
+   present) as well as the current user/server count (as per the LUSER
+   command).  The server is also required to give an unambiguous message
+   to the client which states its name and version as well as any other
+   introductory messages which may be deemed appropriate.
+
+   After dealing with this, the server must then send out the new user's
+   nickname and other information as supplied by itself (USER command)
+   and as the server could discover (from DNS/authentication servers).
+   The server must send this information out with NICK first followed by
+   USER.
+
+8.6 Establishing a server-server connection.
+
+   The process of establishing of a server-to-server connection is
+   fraught with danger since there are many possible areas where
+   problems can occur - the least of which are race conditions.
+
+   After a server has received a connection following by a PASS/SERVER
+   pair which were recognised as being valid, the server should then
+   reply with its own PASS/SERVER information for that connection as
+   well as all of the other state information it knows about as
+   described below.
+
+   When the initiating server receives a PASS/SERVER pair, it too then
+
+
+
+Oikarinen & Reed                                               [Page 58]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+   checks that the server responding is authenticated properly before
+   accepting the connection to be that server.
+
+8.6.1 Server exchange of state information when connecting
+
+   The order of state information being exchanged between servers is
+   essential.  The required order is as follows:
+
+        * all known other servers;
+
+        * all known user information;
+
+        * all known channel information.
+
+   Information regarding servers is sent via extra SERVER messages, user
+   information with NICK/USER/MODE/JOIN messages and channels with MODE
+   messages.
+
+   NOTE: channel topics are *NOT* exchanged here because the TOPIC
+   command overwrites any old topic information, so at best, the two
+   sides of the connection would exchange topics.
+
+   By passing the state information about servers first, any collisions
+   with servers that already exist occur before nickname collisions due
+   to a second server introducing a particular nickname.  Due to the IRC
+   network only being able to exist as an acyclic graph, it may be
+   possible that the network has already reconnected in another
+   location, the place where the collision occurs indicating where the
+   net needs to split.
+
+8.7 Terminating server-client connections
+
+   When a client connection closes, a QUIT message is generated on
+   behalf of the client by the server to which the client connected.  No
+   other message is to be generated or used.
+
+8.8 Terminating server-server connections
+
+   If a server-server connection is closed, either via a remotely
+   generated SQUIT or 'natural' causes, the rest of the connected IRC
+   network must have its information updated with by the server which
+   detected the closure.  The server then sends a list of SQUITs (one
+   for each server behind that connection) and a list of QUITs (again,
+   one for each client behind that connection).
+
+
+
+
+
+
+
+Oikarinen & Reed                                               [Page 59]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+8.9 Tracking nickname changes
+
+   All IRC servers are required to keep a history of recent nickname
+   changes.  This is required to allow the server to have a chance of
+   keeping in touch of things when nick-change race conditions occur
+   with commands which manipulate them.  Commands which must trace nick
+   changes are:
+
+        * KILL (the nick being killed)
+
+        * MODE (+/- o,v)
+
+        * KICK (the nick being kicked)
+
+   No other commands are to have nick changes checked for.
+
+   In the above cases, the server is required to first check for the
+   existence of the nickname, then check its history to see who that
+   nick currently belongs to (if anyone!).  This reduces the chances of
+   race conditions but they can still occur with the server ending up
+   affecting the wrong client.  When performing a change trace for an
+   above command it is recommended that a time range be given and
+   entries which are too old ignored.
+
+   For a reasonable history, a server should be able to keep previous
+   nickname for every client it knows about if they all decided to
+   change.  This size is limited by other factors (such as memory, etc).
+
+8.10 Flood control of clients
+
+   With a large network of interconnected IRC servers, it is quite easy
+   for any single client attached to the network to supply a continuous
+   stream of messages that result in not only flooding the network, but
+   also degrading the level of service provided to others.  Rather than
+   require every 'victim' to be provide their own protection, flood
+   protection was written into the server and is applied to all clients
+   except services.  The current algorithm is as follows:
+
+        * check to see if client's `message timer' is less than
+          current time (set to be equal if it is);
+
+        * read any data present from the client;
+
+        * while the timer is less than ten seconds ahead of the current
+          time, parse any present messages and penalize the client by
+          2 seconds for each message;
+
+   which in essence means that the client may send 1 message every 2
+
+
+
+Oikarinen & Reed                                               [Page 60]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+   seconds without being adversely affected.
+
+8.11 Non-blocking lookups
+
+   In a real-time environment, it is essential that a server process do
+   as little waiting as possible so that all the clients are serviced
+   fairly.  Obviously this requires non-blocking IO on all network
+   read/write operations.  For normal server connections, this was not
+   difficult, but there are other support operations that may cause the
+   server to block (such as disk reads).  Where possible, such activity
+   should be performed with a short timeout.
+
+8.11.1 Hostname (DNS) lookups
+
+   Using the standard resolver libraries from Berkeley and others has
+   meant large delays in some cases where replies have timed out.  To
+   avoid this, a separate set of DNS routines were written which were
+   setup for non-blocking IO operations and then polled from within the
+   main server IO loop.
+
+8.11.2 Username (Ident) lookups
+
+   Although there are numerous ident libraries for use and inclusion
+   into other programs, these caused problems since they operated in a
+   synchronous manner and resulted in frequent delays.  Again the
+   solution was to write a set of routines which would cooperate with
+   the rest of the server and work using non-blocking IO.
+
+8.12 Configuration File
+
+   To provide a flexible way of setting up and running the server, it is
+   recommended that a configuration file be used which contains
+   instructions to the server on the following:
+
+        * which hosts to accept client connections from;
+
+        * which hosts to allow to connect as servers;
+
+        * which hosts to connect to (both actively and
+          passively);
+
+        * information about where the server is (university,
+          city/state, company are examples of this);
+
+        * who is responsible for the server and an email address
+          at which they can be contacted;
+
+        * hostnames and passwords for clients which wish to be given
+
+
+
+Oikarinen & Reed                                               [Page 61]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+          access to restricted operator commands.
+
+   In specifying hostnames, both domain names and use of the 'dot'
+   notation (127.0.0.1) should both be accepted.  It must be possible to
+   specify the password to be used/accepted for all outgoing and
+   incoming connections (although the only outgoing connections are
+   those to other servers).
+
+   The above list is the minimum requirement for any server which wishes
+   to make a connection with another server.  Other items which may be
+   of use are:
+
+        * specifying which servers other server may introduce;
+
+        * how deep a server branch is allowed to become;
+
+        * hours during which clients may connect.
+
+8.12.1 Allowing clients to connect
+
+   A server should use some sort of 'access control list' (either in the
+   configuration file or elsewhere) that is read at startup and used to
+   decide what hosts clients may use to connect to it.
+
+   Both 'deny' and 'allow' should be implemented to provide the required
+   flexibility for host access control.
+
+8.12.2 Operators
+
+   The granting of operator privileges to a disruptive person can have
+   dire consequences for the well-being of the IRC net in general due to
+   the powers given to them.  Thus, the acquisition of such powers
+   should not be very easy.  The current setup requires two 'passwords'
+   to be used although one of them is usually easy guessed.  Storage of
+   oper passwords in configuration files is preferable to hard coding
+   them in and should be stored in a crypted format (ie using crypt(3)
+   from Unix) to prevent easy theft.
+
+8.12.3 Allowing servers to connect
+
+   The interconnection of server is not a trivial matter: a bad
+   connection can have a large impact on the usefulness of IRC.  Thus,
+   each server should have a list of servers to which it may connect and
+   which servers may connect to it.  Under no circumstances should a
+   server allow an arbitrary host to connect as a server.  In addition
+   to which servers may and may not connect, the configuration file
+   should also store the password and other characteristics of that
+   link.
+
+
+
+Oikarinen & Reed                                               [Page 62]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+8.12.4 Administrivia
+
+   To provide accurate and valid replies to the ADMIN command (see
+   section 4.3.7), the server should find the relevant details in the
+   configuration.
+
+8.13 Channel membership
+
+   The current server allows any registered local user to join upto 10
+   different channels.  There is no limit imposed on non-local users so
+   that the server remains (reasonably) consistant with all others on a
+   channel membership basis
+
+9. Current problems
+
+   There are a number of recognized problems with this protocol, all  of
+   which  hope to be solved sometime in the near future during its
+   rewrite.  Currently, work is underway to find working solutions to
+   these problems.
+
+9.1 Scalability
+
+   It is widely recognized that this protocol does not scale
+   sufficiently well when used in a large arena.  The main problem comes
+   from the requirement that all servers know about all other servers
+   and users and that information regarding them be updated as soon as
+   it changes.  It is also desirable to keep the number of servers low
+   so that the path length between any two points is kept minimal and
+   the spanning tree as strongly branched as possible.
+
+9.2 Labels
+
+   The current IRC protocol has 3 types of labels: the nickname, the
+   channel name and the server name.  Each of the three types has its
+   own domain and no duplicates are allowed inside that domain.
+   Currently, it is possible for users to pick the label for any of the
+   three, resulting in collisions.  It is widely recognized that this
+   needs reworking, with a plan for unique names for channels and nicks
+   that don't collide being desirable as well as a solution allowing a
+   cyclic tree.
+
+9.2.1 Nicknames
+
+   The idea of the nickname on IRC is very convenient for users to use
+   when talking to each other outside of a channel, but there is only a
+   finite nickname space and being what they are, its not uncommon for
+   several people to want to use the same nick.  If a nickname is chosen
+   by two people using this protocol, either one will not succeed or
+
+
+
+Oikarinen & Reed                                               [Page 63]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+   both will removed by use of KILL (4.6.1).
+
+9.2.2 Channels
+
+   The current channel layout requires that all servers know about all
+   channels, their inhabitants and properties.  Besides not scaling
+   well, the issue of privacy is also a concern.  A collision of
+   channels is treated as an inclusive event (both people who create the
+   new channel are considered to be members of it) rather than an
+   exclusive one such as used to solve nickname collisions.
+
+9.2.3 Servers
+
+   Although the number of servers is usually small relative to the
+   number of users and channels, they two currently required to be known
+   globally, either each one separately or hidden behind a mask.
+
+9.3 Algorithms
+
+   In some places within the server code, it has not  been  possible  to
+   avoid  N^2  algorithms  such  as  checking  the channel list of a set
+   of clients.
+
+   In current server versions, there are no database consistency checks,
+   each server assumes that a neighbouring server is correct.  This
+   opens the door to large problems if a connecting server is buggy or
+   otherwise tries to introduce contradictions to the existing net.
+
+   Currently, because of the lack of unique internal and global labels,
+   there are a multitude of race conditions that exist.  These race
+   conditions generally arise from the problem of it taking time for
+   messages to traverse and effect the IRC network.  Even by changing to
+   unique labels, there are problems with channel-related commands being
+   disrupted.
+
+10. Current support and availability
+
+           Mailing lists for IRC related discussion:
+                Future protocol: ircd-three-request@eff.org
+                General discussion: operlist-request@eff.org
+
+           Software implemenations
+                cs.bu.edu:/irc
+                nic.funet.fi:/pub/irc
+                coombs.anu.edu.au:/pub/irc
+
+           Newsgroup: alt.irc
+
+
+
+
+Oikarinen & Reed                                               [Page 64]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+Security Considerations
+
+   Security issues are discussed in sections 4.1, 4.1.1, 4.1.3, 5.5, and
+   7.
+
+12. Authors' Addresses
+
+   Jarkko Oikarinen
+   Tuirantie 17 as 9
+   90500 OULU
+   FINLAND
+
+   Email: jto@tolsun.oulu.fi
+
+
+   Darren Reed
+   4 Pateman Street
+   Watsonia, Victoria 3087
+   Australia
+
+   Email: avalon@coombs.anu.edu.au
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Oikarinen & Reed                                               [Page 65]
+\f
\ No newline at end of file
index ce413bf8260f9e4519635141a7a3c7880bdb4f5e..0793b0543beb833dcf5e3d898dbce654b8ed7f41 100644 (file)
@@ -1 +1,78 @@
--- MySQL dump 9.11\r--\r-- Host: localhost    Database: brain\r-- ------------------------------------------------------\r-- Server version        4.0.20\r\r--\r-- Table structure for table `ircd_log`\r--\r\rCREATE TABLE ircd_log (\r  id bigint(20) NOT NULL auto_increment,\r  category_id bigint(20) NOT NULL default '0',\r  nick bigint(20) default NULL,\r  host bigint(20) default NULL,\r  source bigint(20) default NULL,\r  dtime bigint(20) NOT NULL default '0',\r  PRIMARY KEY  (id)\r) TYPE=MyISAM;\r\r--\r-- Dumping data for table `ircd_log`\r--\r\r\r--\r-- Table structure for table `ircd_log_categories`\r--\r\rCREATE TABLE ircd_log_categories (\r  category_id bigint(20) NOT NULL default '0',\r  category text NOT NULL,\r  PRIMARY KEY  (category_id)\r) TYPE=MyISAM;\r\r--\r-- Dumping data for table `ircd_log_categories`\r--\r\rINSERT INTO ircd_log_categories VALUES (1,'Oper');\rINSERT INTO ircd_log_categories VALUES (2,'Kill');\rINSERT INTO ircd_log_categories VALUES (3,'Server Link');\rINSERT INTO ircd_log_categories VALUES (4,'G/Z/K/E Line');\rINSERT INTO ircd_log_categories VALUES (5,'Connect');\rINSERT INTO ircd_log_categories VALUES (6,'Disconnect');\rINSERT INTO ircd_log_categories VALUES (7,'Flooding');\rINSERT INTO ircd_log_categories VALUES (8,'Load Module');\r\r--\r-- Table structure for table `ircd_log_actors`\r--\r\rCREATE TABLE ircd_log_actors (\r  id bigint(20) NOT NULL auto_increment,\r  actor text,\r  PRIMARY KEY  (id)\r) TYPE=MyISAM;\r\r--\r-- Dumping data for table `ircd_log_actors`\r--\r\r\r--\r-- Table structure for table `ircd_log_hosts`\r--\r\rCREATE TABLE ircd_log_hosts (\r  id bigint(20) NOT NULL auto_increment,\r  hostname text,\r  PRIMARY KEY  (id)\r) TYPE=MyISAM;\r\r--\r-- Dumping data for table `ircd_log_hosts`\r--\r\r\r
\ No newline at end of file
+-- MySQL dump 9.11
+--
+-- Host: localhost    Database: brain
+-- ------------------------------------------------------
+-- Server version      4.0.20
+
+--
+-- Table structure for table `ircd_log`
+--
+
+CREATE TABLE ircd_log (
+  id bigint(20) NOT NULL auto_increment,
+  category_id bigint(20) NOT NULL default '0',
+  nick bigint(20) default NULL,
+  host bigint(20) default NULL,
+  source bigint(20) default NULL,
+  dtime bigint(20) NOT NULL default '0',
+  PRIMARY KEY  (id)
+) TYPE=MyISAM;
+
+--
+-- Dumping data for table `ircd_log`
+--
+
+
+--
+-- Table structure for table `ircd_log_categories`
+--
+
+CREATE TABLE ircd_log_categories (
+  category_id bigint(20) NOT NULL default '0',
+  category text NOT NULL,
+  PRIMARY KEY  (category_id)
+) TYPE=MyISAM;
+
+--
+-- Dumping data for table `ircd_log_categories`
+--
+
+INSERT INTO ircd_log_categories VALUES (1,'Oper');
+INSERT INTO ircd_log_categories VALUES (2,'Kill');
+INSERT INTO ircd_log_categories VALUES (3,'Server Link');
+INSERT INTO ircd_log_categories VALUES (4,'G/Z/K/E Line');
+INSERT INTO ircd_log_categories VALUES (5,'Connect');
+INSERT INTO ircd_log_categories VALUES (6,'Disconnect');
+INSERT INTO ircd_log_categories VALUES (7,'Flooding');
+INSERT INTO ircd_log_categories VALUES (8,'Load Module');
+
+--
+-- Table structure for table `ircd_log_actors`
+--
+
+CREATE TABLE ircd_log_actors (
+  id bigint(20) NOT NULL auto_increment,
+  actor text,
+  PRIMARY KEY  (id)
+) TYPE=MyISAM;
+
+--
+-- Dumping data for table `ircd_log_actors`
+--
+
+
+--
+-- Table structure for table `ircd_log_hosts`
+--
+
+CREATE TABLE ircd_log_hosts (
+  id bigint(20) NOT NULL auto_increment,
+  hostname text,
+  PRIMARY KEY  (id)
+) TYPE=MyISAM;
+
+--
+-- Dumping data for table `ircd_log_hosts`
+--
+
+
index 561dba16d001985039726d1f9e1e8b8108de62cb..2e40dd90d1670b16e5b92737b24f9ef113abaae5 100644 (file)
@@ -1 +1,51 @@
---\r-- PostgreSQL database dump\r--\r\rCREATE TABLE ircd_log (\r    id serial NOT NULL,\r    category_id bigint,\r    nick bigint,\r    host bigint,\r    source bigint,\r    dtime bigint DEFAULT 0 NOT NULL\r);\rALTER TABLE ONLY ircd_log\r    ADD CONSTRAINT ircd_log_pkey PRIMARY KEY (id);\r\r\r\rCREATE TABLE ircd_log_actors (\r    id serial NOT NULL,\r    actor text\r);\rALTER TABLE ONLY ircd_log_actors\r    ADD CONSTRAINT ircd_log_actors_pkey PRIMARY KEY (id);\r\r\r\rCREATE TABLE ircd_log_categories (\r    category_id serial NOT NULL,\r    category text NOT NULL\r);\r\rINSERT INTO ircd_log_categories VALUES (1, 'Oper');\rINSERT INTO ircd_log_categories VALUES (2, 'Kill');\rINSERT INTO ircd_log_categories VALUES (3, 'Server Link');\rINSERT INTO ircd_log_categories VALUES (4, 'G/Z/K/E Line');\rINSERT INTO ircd_log_categories VALUES (5, 'Connect');\rINSERT INTO ircd_log_categories VALUES (6, 'Disconnect');\rINSERT INTO ircd_log_categories VALUES (7, 'Flooding');\rINSERT INTO ircd_log_categories VALUES (8, 'Load Module');\r\rALTER TABLE ONLY ircd_log_categories\r    ADD CONSTRAINT ircd_log_categories_pkey PRIMARY KEY (category_id);\r\r\r\rCREATE TABLE ircd_log_hosts (\r    id serial NOT NULL,\r    hostname text\r);\rALTER TABLE ONLY ircd_log_hosts\r    ADD CONSTRAINT ircd_log_hosts_pkey PRIMARY KEY (id);\r
\ No newline at end of file
+--
+-- PostgreSQL database dump
+--
+
+CREATE TABLE ircd_log (
+    id serial NOT NULL,
+    category_id bigint,
+    nick bigint,
+    host bigint,
+    source bigint,
+    dtime bigint DEFAULT 0 NOT NULL
+);
+ALTER TABLE ONLY ircd_log
+    ADD CONSTRAINT ircd_log_pkey PRIMARY KEY (id);
+
+
+
+CREATE TABLE ircd_log_actors (
+    id serial NOT NULL,
+    actor text
+);
+ALTER TABLE ONLY ircd_log_actors
+    ADD CONSTRAINT ircd_log_actors_pkey PRIMARY KEY (id);
+
+
+
+CREATE TABLE ircd_log_categories (
+    category_id serial NOT NULL,
+    category text NOT NULL
+);
+
+INSERT INTO ircd_log_categories VALUES (1, 'Oper');
+INSERT INTO ircd_log_categories VALUES (2, 'Kill');
+INSERT INTO ircd_log_categories VALUES (3, 'Server Link');
+INSERT INTO ircd_log_categories VALUES (4, 'G/Z/K/E Line');
+INSERT INTO ircd_log_categories VALUES (5, 'Connect');
+INSERT INTO ircd_log_categories VALUES (6, 'Disconnect');
+INSERT INTO ircd_log_categories VALUES (7, 'Flooding');
+INSERT INTO ircd_log_categories VALUES (8, 'Load Module');
+
+ALTER TABLE ONLY ircd_log_categories
+    ADD CONSTRAINT ircd_log_categories_pkey PRIMARY KEY (category_id);
+
+
+
+CREATE TABLE ircd_log_hosts (
+    id serial NOT NULL,
+    hostname text
+);
+ALTER TABLE ONLY ircd_log_hosts
+    ADD CONSTRAINT ircd_log_hosts_pkey PRIMARY KEY (id);
index 020cda1d387dc37ab354bd70d815447391224b43..a0772e5e32210193acd01b9fd7cca71938ce50a3 100644 (file)
@@ -1 +1,34 @@
-CREATE TABLE ircd_log (\rid integer primary key,\rcategory_id integer,\rnick integer,\rhost integer,\rsource integer,\rdtime integer);\r\r\rCREATE TABLE ircd_log_categories (\r  category_id integer primary key,\r  category text NOT NULL\r);\rINSERT INTO "ircd_log_categories" VALUES(1, 'Oper');\rINSERT INTO "ircd_log_categories" VALUES(2, 'Kill');\rINSERT INTO "ircd_log_categories" VALUES(3, 'Server Link');\rINSERT INTO "ircd_log_categories" VALUES(4, 'G/Z/K/E Line');\rINSERT INTO "ircd_log_categories" VALUES(5, 'Connect');\rINSERT INTO "ircd_log_categories" VALUES(6, 'Disconnect');\rINSERT INTO "ircd_log_categories" VALUES(7, 'Flooding');\rINSERT INTO "ircd_log_categories" VALUES(8, 'Load Module');\r\r\rCREATE TABLE ircd_log_actors (\r  id integer primary key,\r  actor text\r);\r\r\rCREATE TABLE ircd_log_hosts (\r  id integer primary key,\r  hostname text\r);\r\r
\ No newline at end of file
+CREATE TABLE ircd_log (
+id integer primary key,
+category_id integer,
+nick integer,
+host integer,
+source integer,
+dtime integer);
+
+
+CREATE TABLE ircd_log_categories (
+  category_id integer primary key,
+  category text NOT NULL
+);
+INSERT INTO "ircd_log_categories" VALUES(1, 'Oper');
+INSERT INTO "ircd_log_categories" VALUES(2, 'Kill');
+INSERT INTO "ircd_log_categories" VALUES(3, 'Server Link');
+INSERT INTO "ircd_log_categories" VALUES(4, 'G/Z/K/E Line');
+INSERT INTO "ircd_log_categories" VALUES(5, 'Connect');
+INSERT INTO "ircd_log_categories" VALUES(6, 'Disconnect');
+INSERT INTO "ircd_log_categories" VALUES(7, 'Flooding');
+INSERT INTO "ircd_log_categories" VALUES(8, 'Load Module');
+
+
+CREATE TABLE ircd_log_actors (
+  id integer primary key,
+  actor text
+);
+
+
+CREATE TABLE ircd_log_hosts (
+  id integer primary key,
+  hostname text
+);
+
index ee993c7719fa98d07ffbddd5c14fcd837b2e6e19..293a2aa7041c8faf4ccf669ff3652ffd9dc1d29e 100644 (file)
@@ -1 +1,24 @@
--- MySQL dump 9.11\r--\r-- Host: localhost    Database: brain\r-- ------------------------------------------------------\r-- Server version        4.0.20\r\r--\r-- Table structure for table `ircd_opers`\r--\r\rCREATE TABLE ircd_opers (\r  id bigint(20) NOT NULL auto_increment,\r  username text,\r  password text,\r  hostname text,\r  type text,\r  PRIMARY KEY  (id)\r) TYPE=MyISAM;\r\r--\r-- Dumping data for table `ircd_opers`\r--\r\r\r
\ No newline at end of file
+-- MySQL dump 9.11
+--
+-- Host: localhost    Database: brain
+-- ------------------------------------------------------
+-- Server version      4.0.20
+
+--
+-- Table structure for table `ircd_opers`
+--
+
+CREATE TABLE ircd_opers (
+  id bigint(20) NOT NULL auto_increment,
+  username text,
+  password text,
+  hostname text,
+  type text,
+  PRIMARY KEY  (id)
+) TYPE=MyISAM;
+
+--
+-- Dumping data for table `ircd_opers`
+--
+
+
index 199a656f6c639ff5bb56d9bff6f74e4bb47411b1..fd640949fc182cfec7421c1ffd603f5fbecc04a5 100644 (file)
@@ -1 +1,14 @@
---\r-- PostgreSQL database dump\r--\r\rCREATE TABLE ircd_opers (\r    id serial NOT NULL,\r    username text,\r    "password" text,\r    hostname text,\r    "type" text\r);\rALTER TABLE ONLY ircd_opers\r    ADD CONSTRAINT ircd_opers_pkey PRIMARY KEY (id);\r\r
\ No newline at end of file
+--
+-- PostgreSQL database dump
+--
+
+CREATE TABLE ircd_opers (
+    id serial NOT NULL,
+    username text,
+    "password" text,
+    hostname text,
+    "type" text
+);
+ALTER TABLE ONLY ircd_opers
+    ADD CONSTRAINT ircd_opers_pkey PRIMARY KEY (id);
+
index e33f77a934dca5702adb74c66e9fa3d8b0fedbb5..1bb2937b8d146ea208016f652f9ef45d87b6bf9a 100644 (file)
@@ -1 +1,7 @@
-CREATE TABLE ircd_opers (\rid integer primary key,\rusername text,\rpassword text,\rhostname text,\rtype text);\r\r
\ No newline at end of file
+CREATE TABLE ircd_opers (
+id integer primary key,
+username text,
+password text,
+hostname text,
+type text);
+
index 0831e74afd7176dddc78f563a6949101819a24e6..305c40a2f2b05f97feb31de0f8ad40f7e1c53e53 100644 (file)
@@ -1 +1,12 @@
-<html>\r        <head>\r         <title>\r                        InspIRCd m_httpd.so Module\r             </title>\r       </head>\r        <body>\r         <h1>Nothing to see here folks, Move along...</h1>\r              <h4>This is a placeholder page provided by the InspIRCd m_httpd.so module. Please replace this page with better content.</h4>\r          <small>Powered by <a href="http://www.inspircd.org">InspIRCd</a></small>\r       </body>\r</html>\r
\ No newline at end of file
+<html>
+       <head>
+               <title>
+                       InspIRCd m_httpd.so Module
+               </title>
+       </head>
+       <body>
+               <h1>Nothing to see here folks, Move along...</h1>
+               <h4>This is a placeholder page provided by the InspIRCd m_httpd.so module. Please replace this page with better content.</h4>
+               <small>Powered by <a href="http://www.inspircd.org">InspIRCd</a></small>
+       </body>
+</html>
index 594e5bfe48dc3b8d2927beba0820ac81483a6c0c..ba8184c3c29773ca04922fedd9ba636c0d43ed4b 100644 (file)
@@ -1 +1,228 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __BASE_H__ \r#define __BASE_H__ \r\r#include "inspircd_config.h"\r#include <time.h>\r#include <map>\r#include <deque>\r#include <string>\r\r/** Do we use this? -- Brain */\rtypedef void* VoidPointer;\r\r/** A private data store for an Extensible class */\rtypedef std::map<std::string,char*> ExtensibleStore;\r\r/** Needed */\rclass InspIRCd;\r\r/** The base class for all inspircd classes.\r * Wherever possible, all classes you create should inherit from this,\r * giving them the ability to be passed to various core functions\r * as 'anonymous' classes.\r*/ \rclass CoreExport classbase\r{\r public:\r        /** Time that the object was instantiated (used for TS calculation etc)\r        */\r     time_t age;\r\r   /** Constructor.\r        * Sets the object's time\r       */\r    classbase();\r\r  /** Destructor.\r         * Does sweet FA.\r       */\r    ~classbase() { }\r};\r\r/** class Extensible is the parent class of many classes such as userrec and chanrec.\r * class Extensible implements a system which allows modules to 'extend' the class by attaching data within\r * a map associated with the object. In this way modules can store their own custom information within user\r * objects, channel objects and server objects, without breaking other modules (this is more sensible than using\r * a flags variable, and each module defining bits within the flag as 'theirs' as it is less prone to conflict and\r * supports arbitary data storage).\r */\rclass CoreExport Extensible : public classbase\r{\r        /** Private data store.\r         * Holds all extensible metadata for the class.\r         */\r    ExtensibleStore Extension_Items;\r       \rpublic:\r\r      /** Extend an Extensible class.\r         *\r      * @param key The key parameter is an arbitary string which identifies the extension data\r       * @param p This parameter is a pointer to any data you wish to associate with the object\r       *\r      * You must provide a key to store the data as via the parameter 'key' and store the data\r       * in the templated parameter 'p'.\r      * The data will be inserted into the map. If the data already exists, you may not insert it\r    * twice, Extensible::Extend will return false in this case.\r    *\r      * @return Returns true on success, false if otherwise\r  */\r    template<typename T> bool Extend(const std::string &key, T* p)\r {\r              /* This will only add an item if it doesnt already exist,\r               * the return value is a std::pair of an iterator to the\r                * element, and a bool saying if it was actually inserted.\r              */\r            return this->Extension_Items.insert(std::make_pair(key, (char*)p)).second;\r     }\r\r     /** Extend an Extensible class.\r         *\r      * @param key The key parameter is an arbitary string which identifies the extension data\r       *\r      * You must provide a key to store the data as via the parameter 'key', this single-parameter\r   * version takes no 'data' parameter, this is used purely for boolean values.\r   * The key will be inserted into the map with a NULL 'data' pointer. If the key already exists\r  * then you may not insert it twice, Extensible::Extend will return false in this case.\r         *\r      * @return Returns true on success, false if otherwise\r  */\r    bool Extend(const std::string &key)\r    {\r              /* This will only add an item if it doesnt already exist,\r               * the return value is a std::pair of an iterator to the\r                * element, and a bool saying if it was actually inserted.\r              */\r            return this->Extension_Items.insert(std::make_pair(key, (char*)NULL)).second;\r  }\r\r     /** Shrink an Extensible class.\r         *\r      * @param key The key parameter is an arbitary string which identifies the extension data\r       *\r      * You must provide a key name. The given key name will be removed from the classes data. If\r    * you provide a nonexistent key (case is important) then the function will return false.\r       * @return Returns true on success.\r     */\r    bool Shrink(const std::string &key);\r   \r       /** Get an extension item.\r      *\r      * @param key The key parameter is an arbitary string which identifies the extension data\r       * @param p If you provide a non-existent key, this value will be NULL. Otherwise a pointer to the item you requested will be placed in this templated parameter.\r       * @return Returns true if the item was found and false if it was nor, regardless of wether 'p' is NULL. This allows you to store NULL values in Extensible.\r    */\r    template<typename T> bool GetExt(const std::string &key, T* &p)\r        {\r              ExtensibleStore::iterator iter = this->Extension_Items.find(key); /* Find the item */\r          if(iter != this->Extension_Items.end())\r                {\r                      p = (T*)iter->second;   /* Item found */\r                       return true;\r           }\r              else\r           {\r                      p = NULL;               /* Item not found */\r                   return false;\r          }\r      }\r      \r       /** Get an extension item.\r      *\r      * @param key The key parameter is an arbitary string which identifies the extension data\r       * @return Returns true if the item was found and false if it was not.\r  * \r     * This single-parameter version only checks if the key exists, it does nothing with\r    * the 'data' field and is probably only useful in conjunction with the single-parameter\r        * version of Extend().\r         */\r    bool GetExt(const std::string &key)\r    {\r              return (this->Extension_Items.find(key) != this->Extension_Items.end());\r       }\r\r     /** Get a list of all extension items names.\r    * @param list A deque of strings to receive the list\r   * @return This function writes a list of all extension items stored in this object by name into the given deque and returns void.\r      */\r    void GetExtList(std::deque<std::string> &list);\r};\r\r/** BoolSet is a utility class designed to hold eight bools in a bitmask.\r * Use BoolSet::Set and BoolSet::Get to set and get bools in the bitmask,\r * and Unset and Invert for special operations upon them.\r */\rclass CoreExport BoolSet : public classbase\r{\r    /** Actual bit values */\r       char bits;\r\r public:\r\r  /** The default constructor initializes the BoolSet to all values unset.\r        */\r    BoolSet();\r\r    /** This constructor copies the default bitmask from a char\r     */\r    BoolSet(char bitmask);\r\r        /** The Set method sets one bool in the set.\r    *\r      * @param number The number of the item to set. This must be between 0 and 7.\r   */\r    void Set(int number);\r\r /** The Get method returns the value of one bool in the set\r     *\r      * @param number The number of the item to retrieve. This must be between 0 and 7.\r      *\r      * @return True if the item is set, false if it is unset.\r       */\r    bool Get(int number);\r\r /** The Unset method unsets one value in the set\r        *\r      * @param number The number of the item to set. This must be between 0 and 7.\r   */\r    void Unset(int number);\r\r       /** The Unset method inverts (flips) one value in the set\r       *\r      * @param number The number of the item to invert. This must be between 0 and 7.\r        */\r    void Invert(int number);\r\r      /** Compare two BoolSets\r        */\r    bool operator==(BoolSet other);\r\r       /** OR two BoolSets together\r    */\r    BoolSet operator|(BoolSet other);\r      \r       /** AND two BoolSets together\r   */\r    BoolSet operator&(BoolSet other);\r\r     /** Assign one BoolSet to another\r       */\r    bool operator=(BoolSet other);\r};\r\r\r#endif\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __BASE_H__ 
+#define __BASE_H__ 
+
+#include "inspircd_config.h"
+#include <time.h>
+#include <map>
+#include <deque>
+#include <string>
+
+/** Do we use this? -- Brain */
+typedef void* VoidPointer;
+
+/** A private data store for an Extensible class */
+typedef std::map<std::string,char*> ExtensibleStore;
+
+/** Needed */
+class InspIRCd;
+
+/** The base class for all inspircd classes.
+ * Wherever possible, all classes you create should inherit from this,
+ * giving them the ability to be passed to various core functions
+ * as 'anonymous' classes.
+*/ 
+class CoreExport classbase
+{
+ public:
+       /** Time that the object was instantiated (used for TS calculation etc)
+       */
+       time_t age;
+
+       /** Constructor.
+        * Sets the object's time
+        */
+       classbase();
+
+       /** Destructor.
+        * Does sweet FA.
+        */
+       ~classbase() { }
+};
+
+/** class Extensible is the parent class of many classes such as userrec and chanrec.
+ * class Extensible implements a system which allows modules to 'extend' the class by attaching data within
+ * a map associated with the object. In this way modules can store their own custom information within user
+ * objects, channel objects and server objects, without breaking other modules (this is more sensible than using
+ * a flags variable, and each module defining bits within the flag as 'theirs' as it is less prone to conflict and
+ * supports arbitary data storage).
+ */
+class CoreExport Extensible : public classbase
+{
+       /** Private data store.
+        * Holds all extensible metadata for the class.
+        */
+       ExtensibleStore Extension_Items;
+       
+public:
+
+       /** Extend an Extensible class.
+        *
+        * @param key The key parameter is an arbitary string which identifies the extension data
+        * @param p This parameter is a pointer to any data you wish to associate with the object
+        *
+        * You must provide a key to store the data as via the parameter 'key' and store the data
+        * in the templated parameter 'p'.
+        * The data will be inserted into the map. If the data already exists, you may not insert it
+        * twice, Extensible::Extend will return false in this case.
+        *
+        * @return Returns true on success, false if otherwise
+        */
+       template<typename T> bool Extend(const std::string &key, T* p)
+       {
+               /* This will only add an item if it doesnt already exist,
+                * the return value is a std::pair of an iterator to the
+                * element, and a bool saying if it was actually inserted.
+                */
+               return this->Extension_Items.insert(std::make_pair(key, (char*)p)).second;
+       }
+
+       /** Extend an Extensible class.
+        *
+        * @param key The key parameter is an arbitary string which identifies the extension data
+        *
+        * You must provide a key to store the data as via the parameter 'key', this single-parameter
+        * version takes no 'data' parameter, this is used purely for boolean values.
+        * The key will be inserted into the map with a NULL 'data' pointer. If the key already exists
+        * then you may not insert it twice, Extensible::Extend will return false in this case.
+        *
+        * @return Returns true on success, false if otherwise
+        */
+       bool Extend(const std::string &key)
+       {
+               /* This will only add an item if it doesnt already exist,
+                * the return value is a std::pair of an iterator to the
+                * element, and a bool saying if it was actually inserted.
+                */
+               return this->Extension_Items.insert(std::make_pair(key, (char*)NULL)).second;
+       }
+
+       /** Shrink an Extensible class.
+        *
+        * @param key The key parameter is an arbitary string which identifies the extension data
+        *
+        * You must provide a key name. The given key name will be removed from the classes data. If
+        * you provide a nonexistent key (case is important) then the function will return false.
+        * @return Returns true on success.
+        */
+       bool Shrink(const std::string &key);
+       
+       /** Get an extension item.
+        *
+        * @param key The key parameter is an arbitary string which identifies the extension data
+        * @param p If you provide a non-existent key, this value will be NULL. Otherwise a pointer to the item you requested will be placed in this templated parameter.
+        * @return Returns true if the item was found and false if it was nor, regardless of wether 'p' is NULL. This allows you to store NULL values in Extensible.
+        */
+       template<typename T> bool GetExt(const std::string &key, T* &p)
+       {
+               ExtensibleStore::iterator iter = this->Extension_Items.find(key); /* Find the item */
+               if(iter != this->Extension_Items.end())
+               {
+                       p = (T*)iter->second;   /* Item found */
+                       return true;
+               }
+               else
+               {
+                       p = NULL;               /* Item not found */
+                       return false;
+               }
+       }
+       
+       /** Get an extension item.
+        *
+        * @param key The key parameter is an arbitary string which identifies the extension data
+        * @return Returns true if the item was found and false if it was not.
+        * 
+        * This single-parameter version only checks if the key exists, it does nothing with
+        * the 'data' field and is probably only useful in conjunction with the single-parameter
+        * version of Extend().
+        */
+       bool GetExt(const std::string &key)
+       {
+               return (this->Extension_Items.find(key) != this->Extension_Items.end());
+       }
+
+       /** Get a list of all extension items names.
+        * @param list A deque of strings to receive the list
+        * @return This function writes a list of all extension items stored in this object by name into the given deque and returns void.
+        */
+       void GetExtList(std::deque<std::string> &list);
+};
+
+/** BoolSet is a utility class designed to hold eight bools in a bitmask.
+ * Use BoolSet::Set and BoolSet::Get to set and get bools in the bitmask,
+ * and Unset and Invert for special operations upon them.
+ */
+class CoreExport BoolSet : public classbase
+{
+       /** Actual bit values */
+       char bits;
+
+ public:
+
+       /** The default constructor initializes the BoolSet to all values unset.
+        */
+       BoolSet();
+
+       /** This constructor copies the default bitmask from a char
+        */
+       BoolSet(char bitmask);
+
+       /** The Set method sets one bool in the set.
+        *
+        * @param number The number of the item to set. This must be between 0 and 7.
+        */
+       void Set(int number);
+
+       /** The Get method returns the value of one bool in the set
+        *
+        * @param number The number of the item to retrieve. This must be between 0 and 7.
+        *
+        * @return True if the item is set, false if it is unset.
+        */
+       bool Get(int number);
+
+       /** The Unset method unsets one value in the set
+        *
+        * @param number The number of the item to set. This must be between 0 and 7.
+        */
+       void Unset(int number);
+
+       /** The Unset method inverts (flips) one value in the set
+        *
+        * @param number The number of the item to invert. This must be between 0 and 7.
+        */
+       void Invert(int number);
+
+       /** Compare two BoolSets
+        */
+       bool operator==(BoolSet other);
+
+       /** OR two BoolSets together
+        */
+       BoolSet operator|(BoolSet other);
+       
+       /** AND two BoolSets together
+        */
+       BoolSet operator&(BoolSet other);
+
+       /** Assign one BoolSet to another
+        */
+       bool operator=(BoolSet other);
+};
+
+
+#endif
+
index ce7935c2d15965c36ba3398f60ecc3b999855411..b4fa1ca3064d430f3aeb67eb1e4a40260c198ec1 100644 (file)
@@ -1 +1,551 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __CHANNELS_H__\r#define __CHANNELS_H__\r\r#include "inspircd_config.h"\r#include "base.h"\r#include <time.h>\r#include <vector>\r#include <string>\r#include <map>\r\r/** RFC1459 channel modes\r */\renum ChannelModes {\r     CM_TOPICLOCK = 't'-65,  /* +t: Only operators can change topic */\r      CM_NOEXTERNAL = 'n'-65, /* +n: Only users in the channel can message it */\r     CM_INVITEONLY = 'i'-65, /* +i: Invite only */\r  CM_MODERATED = 'm'-65,  /* +m: Only voices and above can talk */\r       CM_SECRET = 's'-65,     /* +s: Secret channel */\r       CM_PRIVATE = 'p'-65,    /* +p: Private channel */\r      CM_KEY = 'k'-65,        /* +k: Keyed channel */\r        CM_LIMIT = 'l'-65       /* +l: Maximum user limit */\r};\r\r/* Forward declarations - needed */\rclass userrec;\rclass chanrec;\r\r/** Holds an entry for a ban list, exemption list, or invite list.\r * This class contains a single element in a channel list, such as a banlist.\r */\rclass HostItem : public classbase\r{\r public:\r  /** Time the item was added\r     */\r    time_t set_time;\r       /** Who added the item\r  */\r    char set_by[NICKMAX];\r  /** The actual item data\r        */\r    char data[MAXBUF];\r\r    HostItem() { /* stub */ }\r      virtual ~HostItem() { /* stub */ }\r};\r\r/** A subclass of HostItem designed to hold channel bans (+b)\r */\rclass BanItem : public HostItem\r{\r};\r\r/** Holds a complete ban list\r */\rtypedef std::vector<BanItem>   BanList;\r\r/** A list of users on a channel\r */\rtypedef std::map<userrec*,std::string> CUList;\r\r/** Shorthand for CUList::iterator\r */\rtypedef CUList::iterator CUListIter;\r\r/** Shorthand for CUList::const_iterator\r */\rtypedef CUList::const_iterator CUListConstIter;\r\r/** A list of custom modes parameters on a channel\r */\rtypedef std::map<char,char*> CustomModeList;\r\r\r/** used to hold a channel and a users modes on that channel, e.g. +v, +h, +o\r */\renum UserChannelModes {\r      UCMODE_OP       = 1,    /* Opped user */\r       UCMODE_VOICE    = 2,    /* Voiced user */\r      UCMODE_HOP      = 4     /* Halfopped user */\r};\r\r/* Forward declaration -- required */\rclass InspIRCd;\r\r/** A stored prefix and its rank\r */\rtypedef std::pair<char, unsigned int> prefixtype;\r\r/** A list of prefixes set on a user in a channel\r */\rtypedef std::vector<prefixtype> pfxcontainer;\r\r/** A list of users with zero or more prefixes set on them\r */\rtypedef std::map<userrec*, std::vector<prefixtype> > prefixlist;\r\r/** Holds all relevent information for a channel.\r * This class represents a channel, and contains its name, modes, time created, topic, topic set time,\r * etc, and an instance of the BanList type.\r */\rclass CoreExport chanrec : public Extensible\r{\r private:\r\r      /** Pointer to creator object\r   */\r    InspIRCd* ServerInstance;\r\r     /** Connect a chanrec to a userrec\r      */\r    static chanrec* ForceChan(InspIRCd* Instance, chanrec* Ptr, userrec* user, const std::string &privs);\r\r /** Set default modes for the channel on creation\r       */\r    void SetDefaultModes();\r\r       /** A list of prefixes associated with each user in the channel\r         * (e.g. &%+ etc)\r       */\r    prefixlist prefixes;\r\r  /** Maximum number of bans (cached)\r     */\r    int maxbans;\r\r public:\r /** The channel's name.\r         */\r    char name[CHANMAX];\r\r   /** Modes for the channel.\r      * This is not a null terminated string! It is a hash where\r     * each item in it represents if a mode is set. For example\r     * for mode +A, index 0. Use modechar-65 to calculate which\r     * field to check.\r      */\r    char modes[64];\r\r       /** User lists.\r         * There are four user lists, one for \r  * all the users, one for the ops, one for\r      * the halfops and another for the voices.\r      */\r    CUList internal_userlist;\r\r     /** Opped users.\r        * There are four user lists, one for \r  * all the users, one for the ops, one for\r      * the halfops and another for the voices.\r      */\r    CUList internal_op_userlist;\r\r  /** Halfopped users.\r    * There are four user lists, one for \r  * all the users, one for the ops, one for\r      * the halfops and another for the voices.\r      */\r    CUList internal_halfop_userlist;\r\r      /** Voiced users.\r       * There are four user lists, one for\r   * all the users, one for the ops, one for\r      * the halfops and another for the voices.\r      */\r    CUList internal_voice_userlist;\r\r       /** Parameters for custom modes.\r        * One for each custom mode letter.\r     */\r    CustomModeList custom_mode_params;\r\r    /** Channel topic.\r      * If this is an empty string, no channel topic is set.\r         */\r    char topic[MAXTOPIC];\r\r /** Creation time.\r      * This is a timestamp (TS) value.\r      */\r    time_t created;\r\r       /** Time topic was set.\r         * If no topic was ever set, this will be equal to chanrec::created\r     */\r    time_t topicset;\r\r      /** The last user to set the topic.\r     * If this member is an empty string, no topic was ever set.\r    */\r    char setby[128];\r\r      /** Contains the channel user limit.\r    * If this value is zero, there is no limit in place.\r   */\r    short int limit;\r       \r       /** Contains the channel key.\r   * If this value is an empty string, there is no channel key in place.\r  */\r    char key[32];\r\r /** The list of all bans set on the channel.\r    */\r    BanList bans;\r  \r       /** Sets or unsets a custom mode in the channels info\r   * @param mode The mode character to set or unset\r       * @param mode_on True if you want to set the mode or false if you want to remove it\r    */\r    void SetMode(char mode,bool mode_on);\r\r /** Sets or unsets the parameters for a custom mode in a channels info\r  * @param mode The mode character to set or unset\r       * @param parameter The parameter string to associate with this mode character\r  * @param mode_on True if you want to set the mode or false if you want to remove it\r    */\r    void SetModeParam(char mode,const char* parameter,bool mode_on);\r \r     /** Returns true if a mode is set on a channel\r   * @param mode The mode character you wish to query\r     * @return True if the custom mode is set, false if otherwise\r   */\r   bool IsModeSet(char mode);\r\r    /** Returns the parameter for a custom mode on a channel.\r        * @param mode The mode character you wish to query\r     *\r      * For example if "+L #foo" is set, and you pass this method\r    * 'L', it will return '#foo'. If the mode is not set on the\r    * channel, or the mode has no parameters associated with it,\r   * it will return an empty string.\r      *\r      * @return The parameter for this mode is returned, or an empty string\r          */\r   std::string GetModeParameter(char mode);\r\r      /** Obtain the channel "user counter"\r   * This returns the channel reference counter, which is initialized\r     * to 0 when the channel is created and incremented/decremented\r         * upon joins, parts quits and kicks.\r   *\r      * @return The number of users on this channel\r  */\r    long GetUserCounter();\r\r        /** Add a user pointer to the internal reference list\r   * @param user The user to add\r  *\r      * The data inserted into the reference list is a table as it is\r        * an arbitary pointer compared to other users by its memory address,\r   * as this is a very fast 32 or 64 bit integer comparison.\r      */\r    void AddUser(userrec* user);\r\r  /** Add a user pointer to the internal reference list of opped users\r    * @param user The user to add\r  */\r    void AddOppedUser(userrec* user);\r\r     /** Add a user pointer to the internal reference list of halfopped users\r        * @param user The user to add\r  */\r    void AddHalfoppedUser(userrec* user);\r\r /** Add a user pointer to the internal reference list of voiced users\r   * @param user The user to add\r  */\r    void AddVoicedUser(userrec* user);\r\r    /** Delete a user pointer to the internal reference list\r        * @param user The user to delete\r       * @return number of users left on the channel after deletion of the user\r       */\r    unsigned long DelUser(userrec* user);\r\r /** Delete a user pointer to the internal reference list of opped users\r         * @param user The user to delete\r       */\r    void DelOppedUser(userrec* user);\r\r     /** Delete a user pointer to the internal reference list of halfopped users\r     * @param user The user to delete\r       */\r    void DelHalfoppedUser(userrec* user);\r\r /** Delete a user pointer to the internal reference list of voiced users\r        * @param user The user to delete\r       */\r    void DelVoicedUser(userrec* user);\r\r    /** Obtain the internal reference list\r  * The internal reference list contains a list of userrec*.\r     * These are used for rapid comparison to determine\r     * channel membership for PRIVMSG, NOTICE, QUIT, PART etc.\r      * The resulting pointer to the vector should be considered\r     * readonly and only modified via AddUser and DelUser.\r  *\r      * @return This function returns pointer to a map of userrec pointers (CUList*).\r        */\r    CUList* GetUsers();\r\r   /** Obtain the internal reference list of opped users\r   * @return This function returns pointer to a map of userrec pointers (CUList*).\r        */\r    CUList* GetOppedUsers();\r\r      /** Obtain the internal reference list of halfopped users\r       * @return This function returns pointer to a map of userrec pointers (CUList*).\r        */\r    CUList* GetHalfoppedUsers();\r\r  /** Obtain the internal reference list of voiced users\r  * @return This function returns pointer to a map of userrec pointers (CUList*).\r        */\r    CUList* GetVoicedUsers();\r\r     /** Returns true if the user given is on the given channel.\r     * @param The user to look for\r  * @return True if the user is on this channel\r  */\r    bool HasUser(userrec* user);\r\r  /** Creates a channel record and initialises it with default values\r     * @throw Nothing at present.\r   */\r    chanrec(InspIRCd* Instance);\r\r  /** Make src kick user from this channel with the given reason.\r         * @param src The source of the kick\r    * @param user The user being kicked (must be on this channel)\r  * @param reason The reason for the kick\r        * @return The number of users left on the channel. If this is zero\r     * when the method returns, you MUST delete the chanrec immediately!\r    */\r    long KickUser(userrec *src, userrec *user, const char* reason);\r\r       /** Make the server kick user from this channel with the given reason.\r  * @param user The user being kicked (must be on this channel)\r  * @param reason The reason for the kick\r        * @param triggerevents True if you wish this kick to trigger module events\r     * @return The number of users left on the channel. If this is zero\r     * when the method returns, you MUST delete the chanrec immediately!\r    */\r    long ServerKickUser(userrec* user, const char* reason, bool triggerevents);\r\r   /** Part a user from this channel with the given reason.\r        * If the reason field is NULL, no reason will be sent.\r         * @param user The user who is parting (must be on this channel)\r        * @param reason The (optional) part reason\r     * @return The number of users left on the channel. If this is zero\r     * when the method returns, you MUST delete the chanrec immediately!\r    */\r    long PartUser(userrec *user, const char* reason = NULL);\r\r      /* Join a user to a channel. May be a channel that doesnt exist yet.\r    * @param user The user to join to the channel.\r         * @param cn The channel name to join to. Does not have to exist.\r       * @param key The key of the channel, if given\r  * @param override If true, override all join restrictions such as +bkil\r        * @return A pointer to the chanrec the user was joined to. A new chanrec may have\r      * been created if the channel did not exist before the user was joined to it.\r  * If the user could not be joined to a channel, the return value may be NULL.\r  */\r    static chanrec* JoinUser(InspIRCd* ServerInstance, userrec *user, const char* cn, bool override, const char* key, time_t TS = 0);\r\r     /** Write to a channel, from a user, using va_args for text\r     * @param user User whos details to prefix the line with\r        * @param text A printf-style format string which builds the output line without prefix\r         * @param ... Zero or more POD types\r    */\r    void WriteChannel(userrec* user, char* text, ...);\r\r    /** Write to a channel, from a user, using std::string for text\r         * @param user User whos details to prefix the line with\r        * @param text A std::string containing the output line without prefix\r  */\r    void WriteChannel(userrec* user, const std::string &text);\r\r    /** Write to a channel, from a server, using va_args for text\r   * @param ServName Server name to prefix the line with\r  * @param text A printf-style format string which builds the output line without prefix\r         * @param ... Zero or more POD type\r     */\r    void WriteChannelWithServ(const char* ServName, const char* text, ...);\r\r       /** Write to a channel, from a server, using std::string for text\r       * @param ServName Server name to prefix the line with\r  * @param text A std::string containing the output line without prefix\r  */\r    void WriteChannelWithServ(const char* ServName, const std::string &text);\r\r     /** Write to all users on a channel except a specific user, using va_args for text.\r     * Internally, this calls WriteAllExcept().\r     * @param user User whos details to prefix the line with, and to omit from receipt of the message\r       * @param serversource If this parameter is true, use the local server name as the source of the text, otherwise,\r       * use the nick!user@host of the user.\r  * @param status The status of the users to write to, e.g. '@' or '%'. Use a value of 0 to write to everyone\r    * @param text A printf-style format string which builds the output line without prefix\r         * @param ... Zero or more POD type\r     */\r    void WriteAllExceptSender(userrec* user, bool serversource, char status, char* text, ...);\r\r    /** Write to all users on a channel except a list of users, using va_args for text\r      * @param user User whos details to prefix the line with, and to omit from receipt of the message\r       * @param serversource If this parameter is true, use the local server name as the source of the text, otherwise,\r       * use the nick!user@host of the user.\r  * @param status The status of the users to write to, e.g. '@' or '%'. Use a value of 0 to write to everyone\r    * @param except_list A list of users NOT to send the text to\r   * @param text A printf-style format string which builds the output line without prefix\r         * @param ... Zero or more POD type\r     */\r    void WriteAllExcept(userrec* user, bool serversource, char status, CUList &except_list, char* text, ...);\r\r     /** Write to all users on a channel except a specific user, using std::string for text.\r         * Internally, this calls WriteAllExcept().\r     * @param user User whos details to prefix the line with, and to omit from receipt of the message\r       * @param serversource If this parameter is true, use the local server name as the source of the text, otherwise,\r       * use the nick!user@host of the user.\r  * @param status The status of the users to write to, e.g. '@' or '%'. Use a value of 0 to write to everyone\r    * @param text A std::string containing the output line without prefix\r  */\r    void WriteAllExceptSender(userrec* user, bool serversource, char status, const std::string& text);\r\r    /** Write to all users on a channel except a list of users, using std::string for text\r  * @param user User whos details to prefix the line with, and to omit from receipt of the message\r       * @param serversource If this parameter is true, use the local server name as the source of the text, otherwise,\r       * use the nick!user@host of the user.\r  * @param status The status of the users to write to, e.g. '@' or '%'. Use a value of 0 to write to everyone\r    * @param except_list A list of users NOT to send the text to\r   * @param text A std::string containing the output line without prefix\r  */\r    void WriteAllExcept(userrec* user, bool serversource, char status, CUList &except_list, const std::string& text);\r\r     /** Returns the maximum number of bans allowed to be set on this channel\r        * @return The maximum number of bans allowed\r   */\r    long GetMaxBans();\r\r    /** Return the channel's modes with parameters.\r         * @param showkey If this is set to true, the actual key is shown,\r      * otherwise it is replaced with '&lt;KEY&gt;'\r  * @return The channel mode string\r      */\r    char* ChanModes(bool showkey);\r\r        /** Spool the NAMES list for this channel to the given user\r     * @param user The user to spool the NAMES list to\r      * @param ulist The user list to send, NULL to use the\r  * channel's default names list of everyone\r     */\r    void UserList(userrec *user, CUList* ulist = NULL);\r\r   /** Get the number of invisible users on this channel\r   * @return Number of invisible users\r    */\r    int CountInvisible();\r\r /** Get a users status on this channel\r  * @param user The user to look up\r      * @return One of STATUS_OP, STATUS_HOP, STATUS_VOICE, or zero.\r         */\r    int GetStatus(userrec *user);\r\r /** Get a users status on this channel in a bitmask\r     * @param user The user to look up\r      * @return A bitmask containing zero or more of STATUS_OP, STATUS_HOP, STATUS_VOICE\r     */\r    int GetStatusFlags(userrec *user);\r\r    /** Get a users prefix on this channel in a string.\r     * @param user The user to look up\r      * @return A character array containing the prefix string.\r      * Unlike GetStatus and GetStatusFlags which will only return the\r       * core specified modes @, % and + (op, halfop and voice), GetPrefixChar\r        * will also return module-defined prefixes. If the user has to prefix,\r         * an empty but non-null string is returned. If the user has multiple\r   * prefixes, the highest is returned. If you do not recognise the prefix\r        * character you can get, you can deal with it in a 'proprtional' manner\r        * compared to known prefixes, using GetPrefixValue().\r  */\r    const char* GetPrefixChar(userrec *user);\r\r     /** Return all of a users mode prefixes into a char* string.\r    * @param user The user to look up\r      * @return A list of all prefix characters. The prefixes will always\r    * be in rank order, greatest first, as certain IRC clients require\r     * this when multiple prefixes are used names lists.\r    */\r    const char* GetAllPrefixChars(userrec* user);\r\r /** Get the value of a users prefix on this channel.\r    * @param user The user to look up\r      * @return The module or core-defined value of the users prefix.\r        * The values for op, halfop and voice status are constants in\r  * mode.h, and are OP_VALUE, HALFOP_VALUE, and VOICE_VALUE respectively.\r        * If the value you are given does not match one of these three, it is\r  * a module-defined mode, and it should be compared in proportion to\r    * these three constants. For example a value greater than OP_VALUE\r     * is a prefix of greater 'worth' than ops, and a value less than\r       * VOICE_VALUE is of lesser 'worth' than a voice.\r       */\r    unsigned int GetPrefixValue(userrec* user);\r\r   /** This method removes all prefix characters from a user.\r      * It will not inform the user or the channel of the removal of prefixes,\r       * and should be used when the user parts or quits.\r     * @param user The user to remove all prefixes from\r     */\r    void RemoveAllPrefixes(userrec* user);\r\r        /** Add a prefix character to a user.\r   * Only the core should call this method, usually  from\r         * within the mode parser or when the first user joins\r  * the channel (to grant ops to them)\r   * @param user The user to associate the privilage with\r         * @param prefix The prefix character to associate\r      * @param prefix_rank The rank (value) of this prefix character\r         * @param adding True if adding the prefix, false when removing\r         */\r    void SetPrefix(userrec* user, char prefix, unsigned int prefix_rank, bool adding);\r\r    /** Check if a user is banned on this channel\r   * @param user A user to check against the banlist\r      * @returns True if the user given is banned\r    */\r    bool IsBanned(userrec* user);\r\r /** Clears the cached max bans value\r    */\r    void ResetMaxBans();\r\r  /** Destructor for chanrec\r      */\r    virtual ~chanrec() { /* stub */ }\r};\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __CHANNELS_H__
+#define __CHANNELS_H__
+
+#include "inspircd_config.h"
+#include "base.h"
+#include <time.h>
+#include <vector>
+#include <string>
+#include <map>
+
+/** RFC1459 channel modes
+ */
+enum ChannelModes {
+       CM_TOPICLOCK = 't'-65,  /* +t: Only operators can change topic */
+       CM_NOEXTERNAL = 'n'-65, /* +n: Only users in the channel can message it */
+       CM_INVITEONLY = 'i'-65, /* +i: Invite only */
+       CM_MODERATED = 'm'-65,  /* +m: Only voices and above can talk */
+       CM_SECRET = 's'-65,     /* +s: Secret channel */
+       CM_PRIVATE = 'p'-65,    /* +p: Private channel */
+       CM_KEY = 'k'-65,        /* +k: Keyed channel */
+       CM_LIMIT = 'l'-65       /* +l: Maximum user limit */
+};
+
+/* Forward declarations - needed */
+class userrec;
+class chanrec;
+
+/** Holds an entry for a ban list, exemption list, or invite list.
+ * This class contains a single element in a channel list, such as a banlist.
+ */
+class HostItem : public classbase
+{
+ public:
+       /** Time the item was added
+        */
+       time_t set_time;
+       /** Who added the item
+        */
+       char set_by[NICKMAX];
+       /** The actual item data
+        */
+       char data[MAXBUF];
+
+       HostItem() { /* stub */ }
+       virtual ~HostItem() { /* stub */ }
+};
+
+/** A subclass of HostItem designed to hold channel bans (+b)
+ */
+class BanItem : public HostItem
+{
+};
+
+/** Holds a complete ban list
+ */
+typedef std::vector<BanItem>   BanList;
+
+/** A list of users on a channel
+ */
+typedef std::map<userrec*,std::string> CUList;
+
+/** Shorthand for CUList::iterator
+ */
+typedef CUList::iterator CUListIter;
+
+/** Shorthand for CUList::const_iterator
+ */
+typedef CUList::const_iterator CUListConstIter;
+
+/** A list of custom modes parameters on a channel
+ */
+typedef std::map<char,char*> CustomModeList;
+
+
+/** used to hold a channel and a users modes on that channel, e.g. +v, +h, +o
+ */
+enum UserChannelModes {
+       UCMODE_OP       = 1,    /* Opped user */
+       UCMODE_VOICE    = 2,    /* Voiced user */
+       UCMODE_HOP      = 4     /* Halfopped user */
+};
+
+/* Forward declaration -- required */
+class InspIRCd;
+
+/** A stored prefix and its rank
+ */
+typedef std::pair<char, unsigned int> prefixtype;
+
+/** A list of prefixes set on a user in a channel
+ */
+typedef std::vector<prefixtype> pfxcontainer;
+
+/** A list of users with zero or more prefixes set on them
+ */
+typedef std::map<userrec*, std::vector<prefixtype> > prefixlist;
+
+/** Holds all relevent information for a channel.
+ * This class represents a channel, and contains its name, modes, time created, topic, topic set time,
+ * etc, and an instance of the BanList type.
+ */
+class CoreExport chanrec : public Extensible
+{
+ private:
+
+       /** Pointer to creator object
+        */
+       InspIRCd* ServerInstance;
+
+       /** Connect a chanrec to a userrec
+        */
+       static chanrec* ForceChan(InspIRCd* Instance, chanrec* Ptr, userrec* user, const std::string &privs);
+
+       /** Set default modes for the channel on creation
+        */
+       void SetDefaultModes();
+
+       /** A list of prefixes associated with each user in the channel
+        * (e.g. &%+ etc)
+        */
+       prefixlist prefixes;
+
+       /** Maximum number of bans (cached)
+        */
+       int maxbans;
+
+ public:
+       /** The channel's name.
+        */
+       char name[CHANMAX];
+
+       /** Modes for the channel.
+        * This is not a null terminated string! It is a hash where
+        * each item in it represents if a mode is set. For example
+        * for mode +A, index 0. Use modechar-65 to calculate which
+        * field to check.
+        */
+       char modes[64];
+
+       /** User lists.
+        * There are four user lists, one for 
+        * all the users, one for the ops, one for
+        * the halfops and another for the voices.
+        */
+       CUList internal_userlist;
+
+       /** Opped users.
+        * There are four user lists, one for 
+        * all the users, one for the ops, one for
+        * the halfops and another for the voices.
+        */
+       CUList internal_op_userlist;
+
+       /** Halfopped users.
+        * There are four user lists, one for 
+        * all the users, one for the ops, one for
+        * the halfops and another for the voices.
+        */
+       CUList internal_halfop_userlist;
+
+       /** Voiced users.
+        * There are four user lists, one for
+        * all the users, one for the ops, one for
+        * the halfops and another for the voices.
+        */
+       CUList internal_voice_userlist;
+
+       /** Parameters for custom modes.
+        * One for each custom mode letter.
+        */
+       CustomModeList custom_mode_params;
+
+       /** Channel topic.
+        * If this is an empty string, no channel topic is set.
+        */
+       char topic[MAXTOPIC];
+
+       /** Creation time.
+        * This is a timestamp (TS) value.
+        */
+       time_t created;
+
+       /** Time topic was set.
+        * If no topic was ever set, this will be equal to chanrec::created
+        */
+       time_t topicset;
+
+       /** The last user to set the topic.
+        * If this member is an empty string, no topic was ever set.
+        */
+       char setby[128];
+
+       /** Contains the channel user limit.
+        * If this value is zero, there is no limit in place.
+        */
+       short int limit;
+       
+       /** Contains the channel key.
+        * If this value is an empty string, there is no channel key in place.
+        */
+       char key[32];
+
+       /** The list of all bans set on the channel.
+        */
+       BanList bans;
+       
+       /** Sets or unsets a custom mode in the channels info
+        * @param mode The mode character to set or unset
+        * @param mode_on True if you want to set the mode or false if you want to remove it
+        */
+       void SetMode(char mode,bool mode_on);
+
+       /** Sets or unsets the parameters for a custom mode in a channels info
+        * @param mode The mode character to set or unset
+        * @param parameter The parameter string to associate with this mode character
+        * @param mode_on True if you want to set the mode or false if you want to remove it
+        */
+       void SetModeParam(char mode,const char* parameter,bool mode_on);
+       /** Returns true if a mode is set on a channel
+         * @param mode The mode character you wish to query
+         * @return True if the custom mode is set, false if otherwise
+         */
+       bool IsModeSet(char mode);
+
+       /** Returns the parameter for a custom mode on a channel.
+         * @param mode The mode character you wish to query
+         *
+         * For example if "+L #foo" is set, and you pass this method
+         * 'L', it will return '#foo'. If the mode is not set on the
+         * channel, or the mode has no parameters associated with it,
+         * it will return an empty string.
+         *
+         * @return The parameter for this mode is returned, or an empty string
+         */
+       std::string GetModeParameter(char mode);
+
+       /** Obtain the channel "user counter"
+        * This returns the channel reference counter, which is initialized
+        * to 0 when the channel is created and incremented/decremented
+        * upon joins, parts quits and kicks.
+        *
+        * @return The number of users on this channel
+        */
+       long GetUserCounter();
+
+       /** Add a user pointer to the internal reference list
+        * @param user The user to add
+        *
+        * The data inserted into the reference list is a table as it is
+        * an arbitary pointer compared to other users by its memory address,
+        * as this is a very fast 32 or 64 bit integer comparison.
+        */
+       void AddUser(userrec* user);
+
+       /** Add a user pointer to the internal reference list of opped users
+        * @param user The user to add
+        */
+       void AddOppedUser(userrec* user);
+
+       /** Add a user pointer to the internal reference list of halfopped users
+        * @param user The user to add
+        */
+       void AddHalfoppedUser(userrec* user);
+
+       /** Add a user pointer to the internal reference list of voiced users
+        * @param user The user to add
+        */
+       void AddVoicedUser(userrec* user);
+
+       /** Delete a user pointer to the internal reference list
+        * @param user The user to delete
+        * @return number of users left on the channel after deletion of the user
+        */
+       unsigned long DelUser(userrec* user);
+
+       /** Delete a user pointer to the internal reference list of opped users
+        * @param user The user to delete
+        */
+       void DelOppedUser(userrec* user);
+
+       /** Delete a user pointer to the internal reference list of halfopped users
+        * @param user The user to delete
+        */
+       void DelHalfoppedUser(userrec* user);
+
+       /** Delete a user pointer to the internal reference list of voiced users
+        * @param user The user to delete
+        */
+       void DelVoicedUser(userrec* user);
+
+       /** Obtain the internal reference list
+        * The internal reference list contains a list of userrec*.
+        * These are used for rapid comparison to determine
+        * channel membership for PRIVMSG, NOTICE, QUIT, PART etc.
+        * The resulting pointer to the vector should be considered
+        * readonly and only modified via AddUser and DelUser.
+        *
+        * @return This function returns pointer to a map of userrec pointers (CUList*).
+        */
+       CUList* GetUsers();
+
+       /** Obtain the internal reference list of opped users
+        * @return This function returns pointer to a map of userrec pointers (CUList*).
+        */
+       CUList* GetOppedUsers();
+
+       /** Obtain the internal reference list of halfopped users
+        * @return This function returns pointer to a map of userrec pointers (CUList*).
+        */
+       CUList* GetHalfoppedUsers();
+
+       /** Obtain the internal reference list of voiced users
+        * @return This function returns pointer to a map of userrec pointers (CUList*).
+        */
+       CUList* GetVoicedUsers();
+
+       /** Returns true if the user given is on the given channel.
+        * @param The user to look for
+        * @return True if the user is on this channel
+        */
+       bool HasUser(userrec* user);
+
+       /** Creates a channel record and initialises it with default values
+        * @throw Nothing at present.
+        */
+       chanrec(InspIRCd* Instance);
+
+       /** Make src kick user from this channel with the given reason.
+        * @param src The source of the kick
+        * @param user The user being kicked (must be on this channel)
+        * @param reason The reason for the kick
+        * @return The number of users left on the channel. If this is zero
+        * when the method returns, you MUST delete the chanrec immediately!
+        */
+       long KickUser(userrec *src, userrec *user, const char* reason);
+
+       /** Make the server kick user from this channel with the given reason.
+        * @param user The user being kicked (must be on this channel)
+        * @param reason The reason for the kick
+        * @param triggerevents True if you wish this kick to trigger module events
+        * @return The number of users left on the channel. If this is zero
+        * when the method returns, you MUST delete the chanrec immediately!
+        */
+       long ServerKickUser(userrec* user, const char* reason, bool triggerevents);
+
+       /** Part a user from this channel with the given reason.
+        * If the reason field is NULL, no reason will be sent.
+        * @param user The user who is parting (must be on this channel)
+        * @param reason The (optional) part reason
+        * @return The number of users left on the channel. If this is zero
+        * when the method returns, you MUST delete the chanrec immediately!
+        */
+       long PartUser(userrec *user, const char* reason = NULL);
+
+       /* Join a user to a channel. May be a channel that doesnt exist yet.
+        * @param user The user to join to the channel.
+        * @param cn The channel name to join to. Does not have to exist.
+        * @param key The key of the channel, if given
+        * @param override If true, override all join restrictions such as +bkil
+        * @return A pointer to the chanrec the user was joined to. A new chanrec may have
+        * been created if the channel did not exist before the user was joined to it.
+        * If the user could not be joined to a channel, the return value may be NULL.
+        */
+       static chanrec* JoinUser(InspIRCd* ServerInstance, userrec *user, const char* cn, bool override, const char* key, time_t TS = 0);
+
+       /** Write to a channel, from a user, using va_args for text
+        * @param user User whos details to prefix the line with
+        * @param text A printf-style format string which builds the output line without prefix
+        * @param ... Zero or more POD types
+        */
+       void WriteChannel(userrec* user, char* text, ...);
+
+       /** Write to a channel, from a user, using std::string for text
+        * @param user User whos details to prefix the line with
+        * @param text A std::string containing the output line without prefix
+        */
+       void WriteChannel(userrec* user, const std::string &text);
+
+       /** Write to a channel, from a server, using va_args for text
+        * @param ServName Server name to prefix the line with
+        * @param text A printf-style format string which builds the output line without prefix
+        * @param ... Zero or more POD type
+        */
+       void WriteChannelWithServ(const char* ServName, const char* text, ...);
+
+       /** Write to a channel, from a server, using std::string for text
+        * @param ServName Server name to prefix the line with
+        * @param text A std::string containing the output line without prefix
+        */
+       void WriteChannelWithServ(const char* ServName, const std::string &text);
+
+       /** Write to all users on a channel except a specific user, using va_args for text.
+        * Internally, this calls WriteAllExcept().
+        * @param user User whos details to prefix the line with, and to omit from receipt of the message
+        * @param serversource If this parameter is true, use the local server name as the source of the text, otherwise,
+        * use the nick!user@host of the user.
+        * @param status The status of the users to write to, e.g. '@' or '%'. Use a value of 0 to write to everyone
+        * @param text A printf-style format string which builds the output line without prefix
+        * @param ... Zero or more POD type
+        */
+       void WriteAllExceptSender(userrec* user, bool serversource, char status, char* text, ...);
+
+       /** Write to all users on a channel except a list of users, using va_args for text
+        * @param user User whos details to prefix the line with, and to omit from receipt of the message
+        * @param serversource If this parameter is true, use the local server name as the source of the text, otherwise,
+        * use the nick!user@host of the user.
+        * @param status The status of the users to write to, e.g. '@' or '%'. Use a value of 0 to write to everyone
+        * @param except_list A list of users NOT to send the text to
+        * @param text A printf-style format string which builds the output line without prefix
+        * @param ... Zero or more POD type
+        */
+       void WriteAllExcept(userrec* user, bool serversource, char status, CUList &except_list, char* text, ...);
+
+       /** Write to all users on a channel except a specific user, using std::string for text.
+        * Internally, this calls WriteAllExcept().
+        * @param user User whos details to prefix the line with, and to omit from receipt of the message
+        * @param serversource If this parameter is true, use the local server name as the source of the text, otherwise,
+        * use the nick!user@host of the user.
+        * @param status The status of the users to write to, e.g. '@' or '%'. Use a value of 0 to write to everyone
+        * @param text A std::string containing the output line without prefix
+        */
+       void WriteAllExceptSender(userrec* user, bool serversource, char status, const std::string& text);
+
+       /** Write to all users on a channel except a list of users, using std::string for text
+        * @param user User whos details to prefix the line with, and to omit from receipt of the message
+        * @param serversource If this parameter is true, use the local server name as the source of the text, otherwise,
+        * use the nick!user@host of the user.
+        * @param status The status of the users to write to, e.g. '@' or '%'. Use a value of 0 to write to everyone
+        * @param except_list A list of users NOT to send the text to
+        * @param text A std::string containing the output line without prefix
+        */
+       void WriteAllExcept(userrec* user, bool serversource, char status, CUList &except_list, const std::string& text);
+
+       /** Returns the maximum number of bans allowed to be set on this channel
+        * @return The maximum number of bans allowed
+        */
+       long GetMaxBans();
+
+       /** Return the channel's modes with parameters.
+        * @param showkey If this is set to true, the actual key is shown,
+        * otherwise it is replaced with '&lt;KEY&gt;'
+        * @return The channel mode string
+        */
+       char* ChanModes(bool showkey);
+
+       /** Spool the NAMES list for this channel to the given user
+        * @param user The user to spool the NAMES list to
+        * @param ulist The user list to send, NULL to use the
+        * channel's default names list of everyone
+        */
+       void UserList(userrec *user, CUList* ulist = NULL);
+
+       /** Get the number of invisible users on this channel
+        * @return Number of invisible users
+        */
+       int CountInvisible();
+
+       /** Get a users status on this channel
+        * @param user The user to look up
+        * @return One of STATUS_OP, STATUS_HOP, STATUS_VOICE, or zero.
+        */
+       int GetStatus(userrec *user);
+
+       /** Get a users status on this channel in a bitmask
+        * @param user The user to look up
+        * @return A bitmask containing zero or more of STATUS_OP, STATUS_HOP, STATUS_VOICE
+        */
+       int GetStatusFlags(userrec *user);
+
+       /** Get a users prefix on this channel in a string.
+        * @param user The user to look up
+        * @return A character array containing the prefix string.
+        * Unlike GetStatus and GetStatusFlags which will only return the
+        * core specified modes @, % and + (op, halfop and voice), GetPrefixChar
+        * will also return module-defined prefixes. If the user has to prefix,
+        * an empty but non-null string is returned. If the user has multiple
+        * prefixes, the highest is returned. If you do not recognise the prefix
+        * character you can get, you can deal with it in a 'proprtional' manner
+        * compared to known prefixes, using GetPrefixValue().
+        */
+       const char* GetPrefixChar(userrec *user);
+
+       /** Return all of a users mode prefixes into a char* string.
+        * @param user The user to look up
+        * @return A list of all prefix characters. The prefixes will always
+        * be in rank order, greatest first, as certain IRC clients require
+        * this when multiple prefixes are used names lists.
+        */
+       const char* GetAllPrefixChars(userrec* user);
+
+       /** Get the value of a users prefix on this channel.
+        * @param user The user to look up
+        * @return The module or core-defined value of the users prefix.
+        * The values for op, halfop and voice status are constants in
+        * mode.h, and are OP_VALUE, HALFOP_VALUE, and VOICE_VALUE respectively.
+        * If the value you are given does not match one of these three, it is
+        * a module-defined mode, and it should be compared in proportion to
+        * these three constants. For example a value greater than OP_VALUE
+        * is a prefix of greater 'worth' than ops, and a value less than
+        * VOICE_VALUE is of lesser 'worth' than a voice.
+        */
+       unsigned int GetPrefixValue(userrec* user);
+
+       /** This method removes all prefix characters from a user.
+        * It will not inform the user or the channel of the removal of prefixes,
+        * and should be used when the user parts or quits.
+        * @param user The user to remove all prefixes from
+        */
+       void RemoveAllPrefixes(userrec* user);
+
+       /** Add a prefix character to a user.
+        * Only the core should call this method, usually  from
+        * within the mode parser or when the first user joins
+        * the channel (to grant ops to them)
+        * @param user The user to associate the privilage with
+        * @param prefix The prefix character to associate
+        * @param prefix_rank The rank (value) of this prefix character
+        * @param adding True if adding the prefix, false when removing
+        */
+       void SetPrefix(userrec* user, char prefix, unsigned int prefix_rank, bool adding);
+
+       /** Check if a user is banned on this channel
+        * @param user A user to check against the banlist
+        * @returns True if the user given is banned
+        */
+       bool IsBanned(userrec* user);
+
+       /** Clears the cached max bans value
+        */
+       void ResetMaxBans();
+
+       /** Destructor for chanrec
+        */
+       virtual ~chanrec() { /* stub */ }
+};
+
+#endif
index ab567642e93812e1454597fb7ce30324d4cef6e0..e8240fcf9bf1a57a501947ab39a46e79ae3d6795 100644 (file)
@@ -1 +1,244 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __COMMAND_PARSE_H\r#define __COMMAND_PARSE_H\r\r#include <string>\r#include "users.h"\r#include "ctables.h"\r#include "typedefs.h"\r\r/** Required forward declaration\r */\rclass InspIRCd;\r\r/** A list of dll/so files containing the command handlers for the core\r */\rtypedef std::map<std::string, void*> SharedObjectList;\r\r/** This class handles command management and parsing.\r * It allows you to add and remove commands from the map,\r * call command handlers by name, and chop up comma seperated\r * parameters into multiple calls.\r */\rclass CoreExport CommandParser : public classbase\r{\r private:\r       /** The creator of this class\r   */\r    InspIRCd* ServerInstance;\r\r     /** Parameter buffer\r    */\r    std::vector<std::string> para;\r\r        /** Process a parameter string into a list of items\r     * @param command_p The output list of items\r    * @param parameters The input string\r   * @return The number of parameters parsed into command_p\r       */\r    int ProcessParameters(char **command_p,char *parameters);\r\r     /** Process a command from a user.\r      * @param user The user to parse the command for\r        * @param cmd The command string to process\r     */\r    void ProcessCommand(userrec *user, std::string &cmd);\r\r /** Insert the default RFC1459 commands into the command hash.\r  */\r    void SetupCommandTable();\r\r     /** Finds the init_command symbol in a .so file\r         * @param v A function pointer to be initialized\r        * @param h A valid shared object handle\r        * @return True if the symbol could be found\r    */\r    bool FindSym(void** v, void* h);\r\r      /** A list of core-implemented modes and their shared object handles\r    */\r    SharedObjectList RFCCommands;\r\r /** Load a command from a shared object on disk.\r        * @param name The shared object to load (without path)\r         */\r    void LoadCommand(const char* name);\r\r   /** Removes a command if the sources match. Used as a helper for\r        *  safe hash_map delete while iter in RemoveCommands(const char* source).\r      */\r    void RemoveCommand(nspace::hash_map<std::string,command_t*>::iterator safei, const char* source);\r\r\r public:\r   /** Command list, a hash_map of command names to command_t*\r     */\r    command_table cmdlist;\r\r        /** Reload a core command.\r      * This will only reload commands implemented by the core,\r      * to reload a modular command, you must reload that module.\r    * @param cmd The command to reload. This will cause the shared\r         * object which implements this command to be closed, and then reloaded.\r        * @return True if the command was reloaded, false if it could not be found\r     * or another error occured\r     */\r    bool ReloadCommand(const char* cmd);\r\r  /** Default constructor.\r        * @param Instance The creator of this class\r    */\r    CommandParser(InspIRCd* Instance);\r\r    /** Calls the handler for a given command.\r      * @param commandname The command to find. This should be in uppercase.\r         * @param parameters Parameter list as an array of array of char (that's not a typo).\r   * @param pcnt The number of items in the parameters list\r       * @param user The user to call the handler on behalf of\r        * @return This method will return CMD_SUCCESS if the command handler was found and called,\r     * and the command completeld successfully. It will return CMD_FAILURE if the command handler was found\r         * and called, but the command did not complete successfully, and it will return CMD_INVALID if the\r     * command simply did not exist at all or the wrong number of parameters were given, or the user\r        * was not privilaged enough to execute the command.\r    */\r    CmdResult CallHandler(const std::string &commandname,const char** parameters, int pcnt, userrec *user);\r\r       /** Get the handler function for a command.\r     * @param commandname The command required. Always use uppercase for this parameter.\r    * @return a pointer to the command handler, or NULL\r    */\r    command_t* GetHandler(const std::string &commandname);\r\r        /** This function returns true if a command is valid with the given number of parameters and user.\r      * @param commandname The command name to check\r         * @param pcnt The parameter count\r      * @param user The user to check against\r        * @return If the user given has permission to execute the command, and the parameter count is\r  * equal to or greater than the minimum number of parameters to the given command, then this\r    * function will return true, otherwise it will return false.\r   */\r    bool IsValidCommand(const std::string &commandname, int pcnt, userrec * user);\r \r       /** LoopCall is used to call a command classes handler repeatedly based on the contents of a comma seperated list.\r      * There are two overriden versions of this method, one of which takes two potential lists and the other takes one.\r     * We need a version which takes two potential lists for JOIN, because a JOIN may contain two lists of items at once,\r   * the channel names and their keys as follows:\r         *\r      * JOIN #chan1,#chan2,#chan3 key1,,key3\r         *\r      * Therefore, we need to deal with both lists concurrently. The first instance of this method does that by creating\r     * two instances of irc::commasepstream and reading them both together until the first runs out of tokens.\r      * The second version is much simpler and just has the one stream to read, and is used in NAMES, WHOIS, PRIVMSG etc.\r    * Both will only parse until they reach ServerInstance->Config->MaxTargets number of targets, to stop abuse via spam.\r  *\r      * @param user The user who sent the command\r    * @param CommandObj the command object to call for each parameter in the list\r  * @param parameters Parameter list as an array of array of char (that's not a typo).\r   * @param The number of items in the parameters list\r    * @param splithere The first parameter index to split as a comma seperated list\r        * @param extra The second parameter index to split as a comma seperated list\r   * @return This function will return 1 when there are no more parameters to process. When this occurs, its\r      * caller should return without doing anything, otherwise it should continue into its main section of code.\r     */\r    int LoopCall(userrec* user, command_t* CommandObj, const char** parameters, int pcnt, unsigned int splithere, unsigned int extra);\r\r    /** LoopCall is used to call a command classes handler repeatedly based on the contents of a comma seperated list.\r      * There are two overriden versions of this method, one of which takes two potential lists and the other takes one.\r     * We need a version which takes two potential lists for JOIN, because a JOIN may contain two lists of items at once,\r   * the channel names and their keys as follows:\r         *\r      * JOIN #chan1,#chan2,#chan3 key1,,key3\r         *\r      * Therefore, we need to deal with both lists concurrently. The first instance of this method does that by creating\r     * two instances of irc::commasepstream and reading them both together until the first runs out of tokens.\r      * The second version is much simpler and just has the one stream to read, and is used in NAMES, WHOIS, PRIVMSG etc.\r    * Both will only parse until they reach ServerInstance->Config->MaxTargets number of targets, to stop abuse via spam.\r  *\r      * @param user The user who sent the command\r    * @param CommandObj the command object to call for each parameter in the list\r  * @param parameters Parameter list as an array of array of char (that's not a typo).\r   * @param The number of items in the parameters list\r    * @param splithere The first parameter index to split as a comma seperated list\r        * @param extra The second parameter index to split as a comma seperated list\r   * @return This function will return 1 when there are no more parameters to process. When this occurs, its\r      * caller should return without doing anything, otherwise it should continue into its main section of code.\r     */\r    int LoopCall(userrec* user, command_t* CommandObj, const char** parameters, int pcnt, unsigned int splithere);\r\r        /** Take a raw input buffer from a recvq, and process it on behalf of a user.\r   * @param buffer The buffer line to process\r     * @param user The user to whom this line belongs\r       */\r    void ProcessBuffer(std::string &buffer,userrec *user);\r\r        /** Remove all commands relating to module 'source'.\r    * @param source A module name which has introduced new commands\r        * @return True This function returns true if commands were removed\r     */\r    bool RemoveCommands(const char* source);\r\r      /** Add a new command to the commands hash\r      * @param f The new command_t to add to the list\r        * @param so_handle The handle to the shared object where the command can be found.\r     * Only core commands loaded via cmd_*.so files should set this parameter to anything\r   * meaningful. Module authors should leave this parameter at its default of NULL.\r       * @return True if the command was added\r        */\r    bool CreateCommand(command_t *f, void* so_handle = NULL);\r};\r\r/** Command handler class for the RELOAD command.\r * A command cant really reload itself, so this has to be in here.\r */\rclass cmd_reload : public command_t\r{\r public:\r  /** Standard constructor\r        */\r    cmd_reload (InspIRCd* Instance) : command_t(Instance,"RELOAD",'o',1) { syntax = "<core-command>"; }\r    /** Handle RELOAD\r       */\r    CmdResult Handle(const char** parameters, int pcnt, userrec *user);\r};\r\r/** A lookup table of values for multiplier characters used by\r * InspIRCd::Duration(). In this lookup table, the indexes for\r * the ascii values 'm' and 'M' have the value '60', the indexes\r * for the ascii values 'D' and 'd' have a value of '86400', etc.\r */\rconst int duration_multi[] =\r{\r    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r   1, 1, 1, 1, 1, 1, 1, 1, 86400, 1, 1, 1, 3600,\r  1, 1, 1, 1, 60, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r     604800, 1, 31536000, 1, 1, 1, 1, 1, 1, 1, 1,\r   1, 1, 86400, 1, 1, 1, 3600, 1, 1, 1, 1, 60,\r    1, 1, 1, 1, 1, 1, 1, 1, 1, 604800, 1, 31536000,\r        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1\r};\r\r#endif\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __COMMAND_PARSE_H
+#define __COMMAND_PARSE_H
+
+#include <string>
+#include "users.h"
+#include "ctables.h"
+#include "typedefs.h"
+
+/** Required forward declaration
+ */
+class InspIRCd;
+
+/** A list of dll/so files containing the command handlers for the core
+ */
+typedef std::map<std::string, void*> SharedObjectList;
+
+/** This class handles command management and parsing.
+ * It allows you to add and remove commands from the map,
+ * call command handlers by name, and chop up comma seperated
+ * parameters into multiple calls.
+ */
+class CoreExport CommandParser : public classbase
+{
+ private:
+       /** The creator of this class
+        */
+       InspIRCd* ServerInstance;
+
+       /** Parameter buffer
+        */
+       std::vector<std::string> para;
+
+       /** Process a parameter string into a list of items
+        * @param command_p The output list of items
+        * @param parameters The input string
+        * @return The number of parameters parsed into command_p
+        */
+       int ProcessParameters(char **command_p,char *parameters);
+
+       /** Process a command from a user.
+        * @param user The user to parse the command for
+        * @param cmd The command string to process
+        */
+       void ProcessCommand(userrec *user, std::string &cmd);
+
+       /** Insert the default RFC1459 commands into the command hash.
+        */
+       void SetupCommandTable();
+
+       /** Finds the init_command symbol in a .so file
+        * @param v A function pointer to be initialized
+        * @param h A valid shared object handle
+        * @return True if the symbol could be found
+        */
+       bool FindSym(void** v, void* h);
+
+       /** A list of core-implemented modes and their shared object handles
+        */
+       SharedObjectList RFCCommands;
+
+       /** Load a command from a shared object on disk.
+        * @param name The shared object to load (without path)
+        */
+       void LoadCommand(const char* name);
+
+       /** Removes a command if the sources match. Used as a helper for
+        *  safe hash_map delete while iter in RemoveCommands(const char* source).
+        */
+       void RemoveCommand(nspace::hash_map<std::string,command_t*>::iterator safei, const char* source);
+
+
+ public:
+       /** Command list, a hash_map of command names to command_t*
+        */
+       command_table cmdlist;
+
+       /** Reload a core command.
+        * This will only reload commands implemented by the core,
+        * to reload a modular command, you must reload that module.
+        * @param cmd The command to reload. This will cause the shared
+        * object which implements this command to be closed, and then reloaded.
+        * @return True if the command was reloaded, false if it could not be found
+        * or another error occured
+        */
+       bool ReloadCommand(const char* cmd);
+
+       /** Default constructor.
+        * @param Instance The creator of this class
+        */
+       CommandParser(InspIRCd* Instance);
+
+       /** Calls the handler for a given command.
+        * @param commandname The command to find. This should be in uppercase.
+        * @param parameters Parameter list as an array of array of char (that's not a typo).
+        * @param pcnt The number of items in the parameters list
+        * @param user The user to call the handler on behalf of
+        * @return This method will return CMD_SUCCESS if the command handler was found and called,
+        * and the command completeld successfully. It will return CMD_FAILURE if the command handler was found
+        * and called, but the command did not complete successfully, and it will return CMD_INVALID if the
+        * command simply did not exist at all or the wrong number of parameters were given, or the user
+        * was not privilaged enough to execute the command.
+        */
+       CmdResult CallHandler(const std::string &commandname,const char** parameters, int pcnt, userrec *user);
+
+       /** Get the handler function for a command.
+        * @param commandname The command required. Always use uppercase for this parameter.
+        * @return a pointer to the command handler, or NULL
+        */
+       command_t* GetHandler(const std::string &commandname);
+
+       /** This function returns true if a command is valid with the given number of parameters and user.
+        * @param commandname The command name to check
+        * @param pcnt The parameter count
+        * @param user The user to check against
+        * @return If the user given has permission to execute the command, and the parameter count is
+        * equal to or greater than the minimum number of parameters to the given command, then this
+        * function will return true, otherwise it will return false.
+        */
+       bool IsValidCommand(const std::string &commandname, int pcnt, userrec * user);
+       
+       /** LoopCall is used to call a command classes handler repeatedly based on the contents of a comma seperated list.
+        * There are two overriden versions of this method, one of which takes two potential lists and the other takes one.
+        * We need a version which takes two potential lists for JOIN, because a JOIN may contain two lists of items at once,
+        * the channel names and their keys as follows:
+        *
+        * JOIN #chan1,#chan2,#chan3 key1,,key3
+        *
+        * Therefore, we need to deal with both lists concurrently. The first instance of this method does that by creating
+        * two instances of irc::commasepstream and reading them both together until the first runs out of tokens.
+        * The second version is much simpler and just has the one stream to read, and is used in NAMES, WHOIS, PRIVMSG etc.
+        * Both will only parse until they reach ServerInstance->Config->MaxTargets number of targets, to stop abuse via spam.
+        *
+        * @param user The user who sent the command
+        * @param CommandObj the command object to call for each parameter in the list
+        * @param parameters Parameter list as an array of array of char (that's not a typo).
+        * @param The number of items in the parameters list
+        * @param splithere The first parameter index to split as a comma seperated list
+        * @param extra The second parameter index to split as a comma seperated list
+        * @return This function will return 1 when there are no more parameters to process. When this occurs, its
+        * caller should return without doing anything, otherwise it should continue into its main section of code.
+        */
+       int LoopCall(userrec* user, command_t* CommandObj, const char** parameters, int pcnt, unsigned int splithere, unsigned int extra);
+
+       /** LoopCall is used to call a command classes handler repeatedly based on the contents of a comma seperated list.
+        * There are two overriden versions of this method, one of which takes two potential lists and the other takes one.
+        * We need a version which takes two potential lists for JOIN, because a JOIN may contain two lists of items at once,
+        * the channel names and their keys as follows:
+        *
+        * JOIN #chan1,#chan2,#chan3 key1,,key3
+        *
+        * Therefore, we need to deal with both lists concurrently. The first instance of this method does that by creating
+        * two instances of irc::commasepstream and reading them both together until the first runs out of tokens.
+        * The second version is much simpler and just has the one stream to read, and is used in NAMES, WHOIS, PRIVMSG etc.
+        * Both will only parse until they reach ServerInstance->Config->MaxTargets number of targets, to stop abuse via spam.
+        *
+        * @param user The user who sent the command
+        * @param CommandObj the command object to call for each parameter in the list
+        * @param parameters Parameter list as an array of array of char (that's not a typo).
+        * @param The number of items in the parameters list
+        * @param splithere The first parameter index to split as a comma seperated list
+        * @param extra The second parameter index to split as a comma seperated list
+        * @return This function will return 1 when there are no more parameters to process. When this occurs, its
+        * caller should return without doing anything, otherwise it should continue into its main section of code.
+        */
+       int LoopCall(userrec* user, command_t* CommandObj, const char** parameters, int pcnt, unsigned int splithere);
+
+       /** Take a raw input buffer from a recvq, and process it on behalf of a user.
+        * @param buffer The buffer line to process
+        * @param user The user to whom this line belongs
+        */
+       void ProcessBuffer(std::string &buffer,userrec *user);
+
+       /** Remove all commands relating to module 'source'.
+        * @param source A module name which has introduced new commands
+        * @return True This function returns true if commands were removed
+        */
+       bool RemoveCommands(const char* source);
+
+       /** Add a new command to the commands hash
+        * @param f The new command_t to add to the list
+        * @param so_handle The handle to the shared object where the command can be found.
+        * Only core commands loaded via cmd_*.so files should set this parameter to anything
+        * meaningful. Module authors should leave this parameter at its default of NULL.
+        * @return True if the command was added
+        */
+       bool CreateCommand(command_t *f, void* so_handle = NULL);
+};
+
+/** Command handler class for the RELOAD command.
+ * A command cant really reload itself, so this has to be in here.
+ */
+class cmd_reload : public command_t
+{
+ public:
+       /** Standard constructor
+        */
+       cmd_reload (InspIRCd* Instance) : command_t(Instance,"RELOAD",'o',1) { syntax = "<core-command>"; }
+       /** Handle RELOAD
+        */
+       CmdResult Handle(const char** parameters, int pcnt, userrec *user);
+};
+
+/** A lookup table of values for multiplier characters used by
+ * InspIRCd::Duration(). In this lookup table, the indexes for
+ * the ascii values 'm' and 'M' have the value '60', the indexes
+ * for the ascii values 'D' and 'd' have a value of '86400', etc.
+ */
+const int duration_multi[] =
+{
+       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+       1, 1, 1, 1, 1, 1, 1, 1, 86400, 1, 1, 1, 3600,
+       1, 1, 1, 1, 60, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+       604800, 1, 31536000, 1, 1, 1, 1, 1, 1, 1, 1,
+       1, 1, 86400, 1, 1, 1, 3600, 1, 1, 1, 1, 60,
+       1, 1, 1, 1, 1, 1, 1, 1, 1, 604800, 1, 31536000,
+       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
+};
+
+#endif
+
index d251891f8a28653c5af5dddf6de4ec77157b762e..108c4aa9f523b15f7706a7964a969ac4f049646f 100644 (file)
@@ -1 +1,44 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.\r *                  E-mail:\r *               <brain@chatspike.net>\r *                <Craig@chatspike.net>\r *\r * Written by Craig Edwards, Craig McLure, and others.\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __CMD_ADMIN_H__\r#define __CMD_ADMIN_H__\r\r#include "users.h"\r#include "channels.h"\r#include "ctables.h"\r\r/** Handle /ADMIN. These command handlers can be reloaded by the core,\r * and handle basic RFC1459 commands. Commands within modules work\r * the same way, however, they can be fully unloaded, where these\r * may not.\r */\rclass cmd_admin : public command_t\r{\r public:\r     /** Constructor for admin.\r      */\r    cmd_admin (InspIRCd* Instance) : command_t(Instance,"ADMIN",0,0) { syntax = "[<servername>]"; }\r        /** Handle command.\r     * @param parameters The parameters to the comamnd\r      * @param pcnt The number of parameters passed to teh command\r   * @param user The user issuing the command\r     * @return A value from CmdResult to indicate command success or failure.\r       */\r    CmdResult Handle(const char** parameters, int pcnt, userrec *user);\r};\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.
+ *                    E-mail:
+ *             <brain@chatspike.net>
+ *             <Craig@chatspike.net>
+ *
+ * Written by Craig Edwards, Craig McLure, and others.
+ * This program is free but copyrighted software; see
+ *         the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __CMD_ADMIN_H__
+#define __CMD_ADMIN_H__
+
+#include "users.h"
+#include "channels.h"
+#include "ctables.h"
+
+/** Handle /ADMIN. These command handlers can be reloaded by the core,
+ * and handle basic RFC1459 commands. Commands within modules work
+ * the same way, however, they can be fully unloaded, where these
+ * may not.
+ */
+class cmd_admin : public command_t
+{
+ public:
+       /** Constructor for admin.
+        */
+       cmd_admin (InspIRCd* Instance) : command_t(Instance,"ADMIN",0,0) { syntax = "[<servername>]"; }
+       /** Handle command.
+        * @param parameters The parameters to the comamnd
+        * @param pcnt The number of parameters passed to teh command
+        * @param user The user issuing the command
+        * @return A value from CmdResult to indicate command success or failure.
+        */
+       CmdResult Handle(const char** parameters, int pcnt, userrec *user);
+};
+
+#endif
index ce6a66abde02b72dcb8b80257492123430446a87..88d111c78c62374099947b4fb5f4e2f2e2b0bcf2 100644 (file)
@@ -1 +1,45 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.\r *                  E-mail:\r *               <brain@chatspike.net>\r *                <Craig@chatspike.net>\r *\r * Written by Craig Edwards, Craig McLure, and others.\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __CMD_AWAY_H__\r#define __CMD_AWAY_H__\r\r// include the common header files\r\r#include "users.h"\r#include "channels.h"\r\r/** Handle /AWAY. These command handlers can be reloaded by the core,\r * and handle basic RFC1459 commands. Commands within modules work\r * the same way, however, they can be fully unloaded, where these\r * may not.\r */\rclass cmd_away : public command_t\r{\r public:\r  /** Constructor for away.\r       */\r    cmd_away (InspIRCd* Instance) : command_t(Instance,"AWAY",0,0) { syntax = "[<message>]"; }\r     /** Handle command.\r     * @param parameters The parameters to the comamnd\r      * @param pcnt The number of parameters passed to teh command\r   * @param user The user issuing the command\r     * @return A value from CmdResult to indicate command success or failure.\r       */\r    CmdResult Handle(const char** parameters, int pcnt, userrec *user);\r};\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.
+ *                    E-mail:
+ *             <brain@chatspike.net>
+ *             <Craig@chatspike.net>
+ *
+ * Written by Craig Edwards, Craig McLure, and others.
+ * This program is free but copyrighted software; see
+ *         the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __CMD_AWAY_H__
+#define __CMD_AWAY_H__
+
+// include the common header files
+
+#include "users.h"
+#include "channels.h"
+
+/** Handle /AWAY. These command handlers can be reloaded by the core,
+ * and handle basic RFC1459 commands. Commands within modules work
+ * the same way, however, they can be fully unloaded, where these
+ * may not.
+ */
+class cmd_away : public command_t
+{
+ public:
+       /** Constructor for away.
+        */
+       cmd_away (InspIRCd* Instance) : command_t(Instance,"AWAY",0,0) { syntax = "[<message>]"; }
+       /** Handle command.
+        * @param parameters The parameters to the comamnd
+        * @param pcnt The number of parameters passed to teh command
+        * @param user The user issuing the command
+        * @return A value from CmdResult to indicate command success or failure.
+        */
+       CmdResult Handle(const char** parameters, int pcnt, userrec *user);
+};
+
+#endif
index abf5b8a548ced5b1a15b3522d4140b2c1d86d221..6c5d66ac83110296403f939c222fba3e9b8bba7f 100644 (file)
@@ -1 +1,44 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.\r *                  E-mail:\r *               <brain@chatspike.net>\r *                <Craig@chatspike.net>\r *\r * Written by Craig Edwards, Craig McLure, and others.\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __CMD_ADMIN_H__\r#define __CMD_ADMIN_H__\r\r#include "users.h"\r#include "channels.h"\r#include "ctables.h"\r\r/** Handle /ADMIN. These command handlers can be reloaded by the core,\r * and handle basic RFC1459 commands. Commands within modules work\r * the same way, however, they can be fully unloaded, where these\r * may not.\r */\rclass cmd_clearcache : public command_t\r{\r public:\r        /** Constructor for clearcache.\r         */\r    cmd_clearcache (InspIRCd* Instance) : command_t(Instance,"CLEARCACHE",'o',0) { }\r       /** Handle command.\r     * @param parameters The parameters to the comamnd\r      * @param pcnt The number of parameters passed to teh command\r   * @param user The user issuing the command\r     * @return A value from CmdResult to indicate command success or failure.\r       */\r    CmdResult Handle(const char** parameters, int pcnt, userrec *user);\r};\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.
+ *                    E-mail:
+ *             <brain@chatspike.net>
+ *             <Craig@chatspike.net>
+ *
+ * Written by Craig Edwards, Craig McLure, and others.
+ * This program is free but copyrighted software; see
+ *         the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __CMD_ADMIN_H__
+#define __CMD_ADMIN_H__
+
+#include "users.h"
+#include "channels.h"
+#include "ctables.h"
+
+/** Handle /ADMIN. These command handlers can be reloaded by the core,
+ * and handle basic RFC1459 commands. Commands within modules work
+ * the same way, however, they can be fully unloaded, where these
+ * may not.
+ */
+class cmd_clearcache : public command_t
+{
+ public:
+       /** Constructor for clearcache.
+        */
+       cmd_clearcache (InspIRCd* Instance) : command_t(Instance,"CLEARCACHE",'o',0) { }
+       /** Handle command.
+        * @param parameters The parameters to the comamnd
+        * @param pcnt The number of parameters passed to teh command
+        * @param user The user issuing the command
+        * @return A value from CmdResult to indicate command success or failure.
+        */
+       CmdResult Handle(const char** parameters, int pcnt, userrec *user);
+};
+
+#endif
index 095a88557fbb496574211833a3666351c840346c..62359dd5d5428b4beca76c3ae22e0b425d474a62 100644 (file)
@@ -1 +1,45 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.\r *                  E-mail:\r *               <brain@chatspike.net>\r *                <Craig@chatspike.net>\r *\r * Written by Craig Edwards, Craig McLure, and others.\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __CMD_COMMANDS_H__\r#define __CMD_COMMANDS_H__\r\r// include the common header files\r\r#include "users.h"\r#include "channels.h"\r\r/** Handle /COMMANDS. These command handlers can be reloaded by the core,\r * and handle basic RFC1459 commands. Commands within modules work\r * the same way, however, they can be fully unloaded, where these\r * may not.\r */\rclass cmd_commands : public command_t\r{\r public:\r  /** Constructor for commands.\r   */\r    cmd_commands (InspIRCd* Instance) : command_t(Instance,"COMMANDS",0,0) { }\r     /** Handle command.\r     * @param parameters The parameters to the comamnd\r      * @param pcnt The number of parameters passed to teh command\r   * @param user The user issuing the command\r     * @return A value from CmdResult to indicate command success or failure.\r       */\r    CmdResult Handle(const char** parameters, int pcnt, userrec *user);\r};\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.
+ *                    E-mail:
+ *             <brain@chatspike.net>
+ *             <Craig@chatspike.net>
+ *
+ * Written by Craig Edwards, Craig McLure, and others.
+ * This program is free but copyrighted software; see
+ *         the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __CMD_COMMANDS_H__
+#define __CMD_COMMANDS_H__
+
+// include the common header files
+
+#include "users.h"
+#include "channels.h"
+
+/** Handle /COMMANDS. These command handlers can be reloaded by the core,
+ * and handle basic RFC1459 commands. Commands within modules work
+ * the same way, however, they can be fully unloaded, where these
+ * may not.
+ */
+class cmd_commands : public command_t
+{
+ public:
+       /** Constructor for commands.
+        */
+       cmd_commands (InspIRCd* Instance) : command_t(Instance,"COMMANDS",0,0) { }
+       /** Handle command.
+        * @param parameters The parameters to the comamnd
+        * @param pcnt The number of parameters passed to teh command
+        * @param user The user issuing the command
+        * @return A value from CmdResult to indicate command success or failure.
+        */
+       CmdResult Handle(const char** parameters, int pcnt, userrec *user);
+};
+
+#endif
index bcb25c15ae667a945823b0b89823b779c5c29d32..01150fc68ce137595ab6f905674c1a50efb081bc 100644 (file)
@@ -1 +1,45 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.\r *                  E-mail:\r *               <brain@chatspike.net>\r *                <Craig@chatspike.net>\r *\r * Written by Craig Edwards, Craig McLure, and others.\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __CMD_CONNECT_H__\r#define __CMD_CONNECT_H__\r\r#include "users.h"\r#include "channels.h"\r#include "ctables.h"\r#include "modules.h"\r\r/** Handle /CONNECT. These command handlers can be reloaded by the core,\r * and handle basic RFC1459 commands. Commands within modules work\r * the same way, however, they can be fully unloaded, where these\r * may not.\r */\rclass cmd_connect : public command_t\r{\r public:\r        /** Constructor for connect.\r    */\r    cmd_connect (InspIRCd* Instance) : command_t(Instance,"CONNECT",'o',1) { syntax = "<servername> [<remote-server>]"; }\r  /** Handle command.\r     * @param parameters The parameters to the comamnd\r      * @param pcnt The number of parameters passed to teh command\r   * @param user The user issuing the command\r     * @return A value from CmdResult to indicate command success or failure.\r       */\r    CmdResult Handle(const char** parameters, int pcnt, userrec *user);\r};\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.
+ *                    E-mail:
+ *             <brain@chatspike.net>
+ *             <Craig@chatspike.net>
+ *
+ * Written by Craig Edwards, Craig McLure, and others.
+ * This program is free but copyrighted software; see
+ *         the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __CMD_CONNECT_H__
+#define __CMD_CONNECT_H__
+
+#include "users.h"
+#include "channels.h"
+#include "ctables.h"
+#include "modules.h"
+
+/** Handle /CONNECT. These command handlers can be reloaded by the core,
+ * and handle basic RFC1459 commands. Commands within modules work
+ * the same way, however, they can be fully unloaded, where these
+ * may not.
+ */
+class cmd_connect : public command_t
+{
+ public:
+       /** Constructor for connect.
+        */
+       cmd_connect (InspIRCd* Instance) : command_t(Instance,"CONNECT",'o',1) { syntax = "<servername> [<remote-server>]"; }
+       /** Handle command.
+        * @param parameters The parameters to the comamnd
+        * @param pcnt The number of parameters passed to teh command
+        * @param user The user issuing the command
+        * @return A value from CmdResult to indicate command success or failure.
+        */
+       CmdResult Handle(const char** parameters, int pcnt, userrec *user);
+};
+
+#endif
index 3d88ec4c1609da8b72f369746dc8f957247a9ce0..e3ee3ab9d1d87f86726509daecdd3f7c0b797056 100644 (file)
@@ -1 +1,45 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.\r *                  E-mail:\r *               <brain@chatspike.net>\r *                <Craig@chatspike.net>\r *\r * Written by Craig Edwards, Craig McLure, and others.\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __CMD_DIE_H__\r#define __CMD_DIE_H__\r\r// include the common header files\r\r#include "users.h"\r#include "channels.h"\r\r/** Handle /DIE. These command handlers can be reloaded by the core,\r * and handle basic RFC1459 commands. Commands within modules work\r * the same way, however, they can be fully unloaded, where these\r * may not.\r */\rclass cmd_die : public command_t\r{\r public:\r      /** Constructor for die.\r        */\r    cmd_die (InspIRCd* Instance) : command_t(Instance,"DIE",'o',1) { syntax = "<password>"; }\r      /** Handle command.\r     * @param parameters The parameters to the comamnd\r      * @param pcnt The number of parameters passed to teh command\r   * @param user The user issuing the command\r     * @return A value from CmdResult to indicate command success or failure.\r       */\r    CmdResult Handle(const char** parameters, int pcnt, userrec *user);\r};\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.
+ *                    E-mail:
+ *             <brain@chatspike.net>
+ *             <Craig@chatspike.net>
+ *
+ * Written by Craig Edwards, Craig McLure, and others.
+ * This program is free but copyrighted software; see
+ *         the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __CMD_DIE_H__
+#define __CMD_DIE_H__
+
+// include the common header files
+
+#include "users.h"
+#include "channels.h"
+
+/** Handle /DIE. These command handlers can be reloaded by the core,
+ * and handle basic RFC1459 commands. Commands within modules work
+ * the same way, however, they can be fully unloaded, where these
+ * may not.
+ */
+class cmd_die : public command_t
+{
+ public:
+       /** Constructor for die.
+        */
+       cmd_die (InspIRCd* Instance) : command_t(Instance,"DIE",'o',1) { syntax = "<password>"; }
+       /** Handle command.
+        * @param parameters The parameters to the comamnd
+        * @param pcnt The number of parameters passed to teh command
+        * @param user The user issuing the command
+        * @return A value from CmdResult to indicate command success or failure.
+        */
+       CmdResult Handle(const char** parameters, int pcnt, userrec *user);
+};
+
+#endif
index 23fae3f03ed5afc397ef18c2b690be02358ff07d..594af96973a6420e36824848e68a209ad4116c03 100644 (file)
@@ -1 +1,45 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.\r *                  E-mail:\r *               <brain@chatspike.net>\r *                <Craig@chatspike.net>\r *\r * Written by Craig Edwards, Craig McLure, and others.\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __CMD_ELINE_H__\r#define __CMD_ELINE_H__\r\r// include the common header files\r\r#include "users.h"\r#include "channels.h"\r\r/** Handle /ELINE. These command handlers can be reloaded by the core,\r * and handle basic RFC1459 commands. Commands within modules work\r * the same way, however, they can be fully unloaded, where these\r * may not.\r */\rclass cmd_eline : public command_t\r{\r public:\r      /** Constructor for eline.\r      */\r    cmd_eline (InspIRCd* Instance) : command_t(Instance,"ELINE",'o',1) { syntax = "<ident@host> [<duration> :<reason>]"; }\r /** Handle command.\r     * @param parameters The parameters to the comamnd\r      * @param pcnt The number of parameters passed to teh command\r   * @param user The user issuing the command\r     * @return A value from CmdResult to indicate command success or failure.\r       */\r    CmdResult Handle(const char** parameters, int pcnt, userrec *user);\r};\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.
+ *                    E-mail:
+ *             <brain@chatspike.net>
+ *             <Craig@chatspike.net>
+ *
+ * Written by Craig Edwards, Craig McLure, and others.
+ * This program is free but copyrighted software; see
+ *         the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __CMD_ELINE_H__
+#define __CMD_ELINE_H__
+
+// include the common header files
+
+#include "users.h"
+#include "channels.h"
+
+/** Handle /ELINE. These command handlers can be reloaded by the core,
+ * and handle basic RFC1459 commands. Commands within modules work
+ * the same way, however, they can be fully unloaded, where these
+ * may not.
+ */
+class cmd_eline : public command_t
+{
+ public:
+       /** Constructor for eline.
+        */
+       cmd_eline (InspIRCd* Instance) : command_t(Instance,"ELINE",'o',1) { syntax = "<ident@host> [<duration> :<reason>]"; }
+       /** Handle command.
+        * @param parameters The parameters to the comamnd
+        * @param pcnt The number of parameters passed to teh command
+        * @param user The user issuing the command
+        * @return A value from CmdResult to indicate command success or failure.
+        */
+       CmdResult Handle(const char** parameters, int pcnt, userrec *user);
+};
+
+#endif
index f8a82dfa8a8edc4e5457bb54e81df1869f8cfe83..5fc8eccee33f4de8de174fff465910a8b60c5374 100644 (file)
@@ -1 +1,45 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.\r *                  E-mail:\r *               <brain@chatspike.net>\r *                <Craig@chatspike.net>\r *\r * Written by Craig Edwards, Craig McLure, and others.\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __CMD_GLINE_H__\r#define __CMD_GLINE_H__\r\r// include the common header file\r\r#include "users.h"\r#include "channels.h"\r\r/** Handle /GLINE. These command handlers can be reloaded by the core,\r * and handle basic RFC1459 commands. Commands within modules work\r * the same way, however, they can be fully unloaded, where these\r * may not.\r */\rclass cmd_gline : public command_t\r{\r public:\r       /** Constructor for gline.\r      */\r    cmd_gline (InspIRCd* Instance) : command_t(Instance,"GLINE",'o',1) { syntax = "<ident@host> [<duration> :<reason>]"; }\r /** Handle command.\r     * @param parameters The parameters to the comamnd\r      * @param pcnt The number of parameters passed to teh command\r   * @param user The user issuing the command\r     * @return A value from CmdResult to indicate command success or failure.\r       */\r    CmdResult Handle(const char** parameters, int pcnt, userrec *user);\r};\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.
+ *                    E-mail:
+ *             <brain@chatspike.net>
+ *             <Craig@chatspike.net>
+ *
+ * Written by Craig Edwards, Craig McLure, and others.
+ * This program is free but copyrighted software; see
+ *         the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __CMD_GLINE_H__
+#define __CMD_GLINE_H__
+
+// include the common header file
+
+#include "users.h"
+#include "channels.h"
+
+/** Handle /GLINE. These command handlers can be reloaded by the core,
+ * and handle basic RFC1459 commands. Commands within modules work
+ * the same way, however, they can be fully unloaded, where these
+ * may not.
+ */
+class cmd_gline : public command_t
+{
+ public:
+       /** Constructor for gline.
+        */
+       cmd_gline (InspIRCd* Instance) : command_t(Instance,"GLINE",'o',1) { syntax = "<ident@host> [<duration> :<reason>]"; }
+       /** Handle command.
+        * @param parameters The parameters to the comamnd
+        * @param pcnt The number of parameters passed to teh command
+        * @param user The user issuing the command
+        * @return A value from CmdResult to indicate command success or failure.
+        */
+       CmdResult Handle(const char** parameters, int pcnt, userrec *user);
+};
+
+#endif
index 00bb6d2f2406b576cfa59b77da6b09c51063d609..330c8bcf1cf4e5a5d099d05ed9861ae4243131aa 100644 (file)
@@ -1 +1,45 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.\r *                  E-mail:\r *               <brain@chatspike.net>\r *                <Craig@chatspike.net>\r *\r * Written by Craig Edwards, Craig McLure, and others.\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __CMD_INFO_H__\r#define __CMD_INFO_H__\r\r// include the common header files\r\r#include "users.h"\r#include "channels.h"\r\r/** Handle /INFO. These command handlers can be reloaded by the core,\r * and handle basic RFC1459 commands. Commands within modules work\r * the same way, however, they can be fully unloaded, where these\r * may not.\r */\rclass cmd_info : public command_t\r{\r public:\r  /** Constructor for info.\r       */\r    cmd_info (InspIRCd* Instance) : command_t(Instance,"INFO",0,0) { syntax = "[<servermask>]"; }\r  /** Handle command.\r     * @param parameters The parameters to the comamnd\r      * @param pcnt The number of parameters passed to teh command\r   * @param user The user issuing the command\r     * @return A value from CmdResult to indicate command success or failure.\r       */\r    CmdResult Handle(const char** parameters, int pcnt, userrec *user);\r};\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.
+ *                    E-mail:
+ *             <brain@chatspike.net>
+ *             <Craig@chatspike.net>
+ *
+ * Written by Craig Edwards, Craig McLure, and others.
+ * This program is free but copyrighted software; see
+ *         the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __CMD_INFO_H__
+#define __CMD_INFO_H__
+
+// include the common header files
+
+#include "users.h"
+#include "channels.h"
+
+/** Handle /INFO. These command handlers can be reloaded by the core,
+ * and handle basic RFC1459 commands. Commands within modules work
+ * the same way, however, they can be fully unloaded, where these
+ * may not.
+ */
+class cmd_info : public command_t
+{
+ public:
+       /** Constructor for info.
+        */
+       cmd_info (InspIRCd* Instance) : command_t(Instance,"INFO",0,0) { syntax = "[<servermask>]"; }
+       /** Handle command.
+        * @param parameters The parameters to the comamnd
+        * @param pcnt The number of parameters passed to teh command
+        * @param user The user issuing the command
+        * @return A value from CmdResult to indicate command success or failure.
+        */
+       CmdResult Handle(const char** parameters, int pcnt, userrec *user);
+};
+
+#endif
index db506fee9019e79d6b6ba0a7808ae1f0cf3b7afb..13bd1f35b02b3c2431750d7853d325b7ea4d4cd3 100644 (file)
@@ -1 +1,45 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.\r *                  E-mail:\r *               <brain@chatspike.net>\r *                <Craig@chatspike.net>\r *\r * Written by Craig Edwards, Craig McLure, and others.\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __CMD_INVITE_H__\r#define __CMD_INVITE_H__\r\r// include the common header files\r\r#include "users.h"\r#include "channels.h"\r\r/** Handle /INVITE. These command handlers can be reloaded by the core,\r * and handle basic RFC1459 commands. Commands within modules work\r * the same way, however, they can be fully unloaded, where these\r * may not.\r */\rclass cmd_invite : public command_t\r{\r public:\r  /** Constructor for invite.\r     */\r    cmd_invite (InspIRCd* Instance) : command_t(Instance,"INVITE",0,0) { syntax = "[<nick> <channel>]"; }\r  /** Handle command.\r     * @param parameters The parameters to the comamnd\r      * @param pcnt The number of parameters passed to teh command\r   * @param user The user issuing the command\r     * @return A value from CmdResult to indicate command success or failure.\r       */\r    CmdResult Handle(const char** parameters, int pcnt, userrec *user);\r};\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.
+ *                    E-mail:
+ *             <brain@chatspike.net>
+ *             <Craig@chatspike.net>
+ *
+ * Written by Craig Edwards, Craig McLure, and others.
+ * This program is free but copyrighted software; see
+ *         the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __CMD_INVITE_H__
+#define __CMD_INVITE_H__
+
+// include the common header files
+
+#include "users.h"
+#include "channels.h"
+
+/** Handle /INVITE. These command handlers can be reloaded by the core,
+ * and handle basic RFC1459 commands. Commands within modules work
+ * the same way, however, they can be fully unloaded, where these
+ * may not.
+ */
+class cmd_invite : public command_t
+{
+ public:
+       /** Constructor for invite.
+        */
+       cmd_invite (InspIRCd* Instance) : command_t(Instance,"INVITE",0,0) { syntax = "[<nick> <channel>]"; }
+       /** Handle command.
+        * @param parameters The parameters to the comamnd
+        * @param pcnt The number of parameters passed to teh command
+        * @param user The user issuing the command
+        * @return A value from CmdResult to indicate command success or failure.
+        */
+       CmdResult Handle(const char** parameters, int pcnt, userrec *user);
+};
+
+#endif
index 143a3efd702e8657133217856ad7d3fb346611dd..d0be58c2360826dabf465c31b4d360d939ec037a 100644 (file)
@@ -1 +1,45 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.\r *                  E-mail:\r *               <brain@chatspike.net>\r *                <Craig@chatspike.net>\r *\r * Written by Craig Edwards, Craig McLure, and others.\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __CMD_ISON_H__\r#define __CMD_ISON_H__\r\r// include the common header files\r\r#include "users.h"\r#include "channels.h"\r\r/** Handle /ISON. These command handlers can be reloaded by the core,\r * and handle basic RFC1459 commands. Commands within modules work\r * the same way, however, they can be fully unloaded, where these\r * may not.\r */\rclass cmd_ison : public command_t\r{\r public:\r  /** Constructor for ison.\r       */\r    cmd_ison (InspIRCd* Instance) : command_t(Instance,"ISON",0,0) { syntax = "<nick> {nick}"; }\r   /** Handle command.\r     * @param parameters The parameters to the comamnd\r      * @param pcnt The number of parameters passed to teh command\r   * @param user The user issuing the command\r     * @return A value from CmdResult to indicate command success or failure.\r       */\r    CmdResult Handle(const char** parameters, int pcnt, userrec *user);\r};\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.
+ *                    E-mail:
+ *             <brain@chatspike.net>
+ *             <Craig@chatspike.net>
+ *
+ * Written by Craig Edwards, Craig McLure, and others.
+ * This program is free but copyrighted software; see
+ *         the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __CMD_ISON_H__
+#define __CMD_ISON_H__
+
+// include the common header files
+
+#include "users.h"
+#include "channels.h"
+
+/** Handle /ISON. These command handlers can be reloaded by the core,
+ * and handle basic RFC1459 commands. Commands within modules work
+ * the same way, however, they can be fully unloaded, where these
+ * may not.
+ */
+class cmd_ison : public command_t
+{
+ public:
+       /** Constructor for ison.
+        */
+       cmd_ison (InspIRCd* Instance) : command_t(Instance,"ISON",0,0) { syntax = "<nick> {nick}"; }
+       /** Handle command.
+        * @param parameters The parameters to the comamnd
+        * @param pcnt The number of parameters passed to teh command
+        * @param user The user issuing the command
+        * @return A value from CmdResult to indicate command success or failure.
+        */
+       CmdResult Handle(const char** parameters, int pcnt, userrec *user);
+};
+
+#endif
index 65abdff59255d2f0b84e2d20753bd775bb910e43..6e343bb72de2a3c8a0dfb65415a92cf4bcfe4277 100644 (file)
@@ -1 +1,45 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.\r *                  E-mail:\r *               <brain@chatspike.net>\r *                <Craig@chatspike.net>\r *\r * Written by Craig Edwards, Craig McLure, and others.\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __CMD_JOIN_H__\r#define __CMD_JOIN_H__\r\r// include the common header files\r\r#include "users.h"\r#include "channels.h"\r\r/** Handle /JOIN. These command handlers can be reloaded by the core,\r * and handle basic RFC1459 commands. Commands within modules work\r * the same way, however, they can be fully unloaded, where these\r * may not.\r */\rclass cmd_join : public command_t\r{\r public:\r  /** Constructor for join.\r       */\r    cmd_join (InspIRCd* Instance) : command_t(Instance,"JOIN",0,1) { syntax = "<channel>{,<channel>} {<key>{,<key>}}"; }\r   /** Handle command.\r     * @param parameters The parameters to the comamnd\r      * @param pcnt The number of parameters passed to teh command\r   * @param user The user issuing the command\r     * @return A value from CmdResult to indicate command success or failure.\r       */\r    CmdResult Handle(const char** parameters, int pcnt, userrec *user);\r};\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.
+ *                    E-mail:
+ *             <brain@chatspike.net>
+ *             <Craig@chatspike.net>
+ *
+ * Written by Craig Edwards, Craig McLure, and others.
+ * This program is free but copyrighted software; see
+ *         the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __CMD_JOIN_H__
+#define __CMD_JOIN_H__
+
+// include the common header files
+
+#include "users.h"
+#include "channels.h"
+
+/** Handle /JOIN. These command handlers can be reloaded by the core,
+ * and handle basic RFC1459 commands. Commands within modules work
+ * the same way, however, they can be fully unloaded, where these
+ * may not.
+ */
+class cmd_join : public command_t
+{
+ public:
+       /** Constructor for join.
+        */
+       cmd_join (InspIRCd* Instance) : command_t(Instance,"JOIN",0,1) { syntax = "<channel>{,<channel>} {<key>{,<key>}}"; }
+       /** Handle command.
+        * @param parameters The parameters to the comamnd
+        * @param pcnt The number of parameters passed to teh command
+        * @param user The user issuing the command
+        * @return A value from CmdResult to indicate command success or failure.
+        */
+       CmdResult Handle(const char** parameters, int pcnt, userrec *user);
+};
+
+#endif
index c8832f042cbf95ba937a0f52a37ddb7e54ad1e0f..6a44d0c12441bdd1480507a7f20d2e2c3d230333 100644 (file)
@@ -1 +1,45 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.\r *                  E-mail:\r *               <brain@chatspike.net>\r *                <Craig@chatspike.net>\r *\r * Written by Craig Edwards, Craig McLure, and others.\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __CMD_KICK_H__\r#define __CMD_KICK_H__\r\r// include the common header files\r\r#include "users.h"\r#include "channels.h"\r\r/** Handle /KICK. These command handlers can be reloaded by the core,\r * and handle basic RFC1459 commands. Commands within modules work\r * the same way, however, they can be fully unloaded, where these\r * may not.\r */\rclass cmd_kick : public command_t\r{\r public:\r  /** Constructor for kick.\r       */\r    cmd_kick (InspIRCd* Instance) : command_t(Instance,"KICK",0,2) { syntax = "<channel> <nick>{,<nick>} [<reason>]"; }\r    /** Handle command.\r     * @param parameters The parameters to the comamnd\r      * @param pcnt The number of parameters passed to teh command\r   * @param user The user issuing the command\r     * @return A value from CmdResult to indicate command success or failure.\r       */\r    CmdResult Handle(const char** parameters, int pcnt, userrec *user);\r};\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.
+ *                    E-mail:
+ *             <brain@chatspike.net>
+ *             <Craig@chatspike.net>
+ *
+ * Written by Craig Edwards, Craig McLure, and others.
+ * This program is free but copyrighted software; see
+ *         the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __CMD_KICK_H__
+#define __CMD_KICK_H__
+
+// include the common header files
+
+#include "users.h"
+#include "channels.h"
+
+/** Handle /KICK. These command handlers can be reloaded by the core,
+ * and handle basic RFC1459 commands. Commands within modules work
+ * the same way, however, they can be fully unloaded, where these
+ * may not.
+ */
+class cmd_kick : public command_t
+{
+ public:
+       /** Constructor for kick.
+        */
+       cmd_kick (InspIRCd* Instance) : command_t(Instance,"KICK",0,2) { syntax = "<channel> <nick>{,<nick>} [<reason>]"; }
+       /** Handle command.
+        * @param parameters The parameters to the comamnd
+        * @param pcnt The number of parameters passed to teh command
+        * @param user The user issuing the command
+        * @return A value from CmdResult to indicate command success or failure.
+        */
+       CmdResult Handle(const char** parameters, int pcnt, userrec *user);
+};
+
+#endif
index 456744c26f1f2a1dff2aaa5622f42d8ca1d7b20d..8489599b61f2f9b473bb3d0ddaae0a246cd9d2bf 100644 (file)
@@ -1 +1,45 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.\r *                  E-mail:\r *               <brain@chatspike.net>\r *                <Craig@chatspike.net>\r *\r * Written by Craig Edwards, Craig McLure, and others.\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __CMD_KILL_H__\r#define __CMD_KILL_H__\r\r// include the common header files\r\r#include "users.h"\r#include "channels.h"\r\r/** Handle /KILL. These command handlers can be reloaded by the core,\r * and handle basic RFC1459 commands. Commands within modules work\r * the same way, however, they can be fully unloaded, where these\r * may not.\r */\rclass cmd_kill : public command_t\r{\r public:\r  /** Constructor for kill.\r       */\r    cmd_kill (InspIRCd* Instance) : command_t(Instance,"KILL",'o',2) { syntax = "<nickname> <reason>"; }\r   /** Handle command.\r     * @param parameters The parameters to the comamnd\r      * @param pcnt The number of parameters passed to teh command\r   * @param user The user issuing the command\r     * @return A value from CmdResult to indicate command success or failure.\r       */\r    CmdResult Handle(const char** parameters, int pcnt, userrec *user);\r};\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.
+ *                    E-mail:
+ *             <brain@chatspike.net>
+ *             <Craig@chatspike.net>
+ *
+ * Written by Craig Edwards, Craig McLure, and others.
+ * This program is free but copyrighted software; see
+ *         the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __CMD_KILL_H__
+#define __CMD_KILL_H__
+
+// include the common header files
+
+#include "users.h"
+#include "channels.h"
+
+/** Handle /KILL. These command handlers can be reloaded by the core,
+ * and handle basic RFC1459 commands. Commands within modules work
+ * the same way, however, they can be fully unloaded, where these
+ * may not.
+ */
+class cmd_kill : public command_t
+{
+ public:
+       /** Constructor for kill.
+        */
+       cmd_kill (InspIRCd* Instance) : command_t(Instance,"KILL",'o',2) { syntax = "<nickname> <reason>"; }
+       /** Handle command.
+        * @param parameters The parameters to the comamnd
+        * @param pcnt The number of parameters passed to teh command
+        * @param user The user issuing the command
+        * @return A value from CmdResult to indicate command success or failure.
+        */
+       CmdResult Handle(const char** parameters, int pcnt, userrec *user);
+};
+
+#endif
index 22d04b558bf8e445141fb9da1f13586dc67e146b..053b7634dd451ceff84cecc7052f49eb9fa80e44 100644 (file)
@@ -1 +1,45 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.\r *                  E-mail:\r *               <brain@chatspike.net>\r *                <Craig@chatspike.net>\r *\r * Written by Craig Edwards, Craig McLure, and others.\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __CMD_KLINE_H__\r#define __CMD_KLINE_H__\r\r// include the common header files\r\r#include "users.h"\r#include "channels.h"\r\r/** Handle /KLINE. These command handlers can be reloaded by the core,\r * and handle basic RFC1459 commands. Commands within modules work\r * the same way, however, they can be fully unloaded, where these\r * may not.\r */\rclass cmd_kline : public command_t\r{\r public:\r      /** Constructor for kline.\r      */\r    cmd_kline (InspIRCd* Instance) : command_t(Instance,"KLINE",'o',1) { syntax = "<ident@host> [<duration> :<reason>]"; }\r /** Handle command.\r     * @param parameters The parameters to the comamnd\r      * @param pcnt The number of parameters passed to teh command\r   * @param user The user issuing the command\r     * @return A value from CmdResult to indicate command success or failure.\r       */\r    CmdResult Handle(const char** parameters, int pcnt, userrec *user);\r};\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.
+ *                    E-mail:
+ *             <brain@chatspike.net>
+ *             <Craig@chatspike.net>
+ *
+ * Written by Craig Edwards, Craig McLure, and others.
+ * This program is free but copyrighted software; see
+ *         the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __CMD_KLINE_H__
+#define __CMD_KLINE_H__
+
+// include the common header files
+
+#include "users.h"
+#include "channels.h"
+
+/** Handle /KLINE. These command handlers can be reloaded by the core,
+ * and handle basic RFC1459 commands. Commands within modules work
+ * the same way, however, they can be fully unloaded, where these
+ * may not.
+ */
+class cmd_kline : public command_t
+{
+ public:
+       /** Constructor for kline.
+        */
+       cmd_kline (InspIRCd* Instance) : command_t(Instance,"KLINE",'o',1) { syntax = "<ident@host> [<duration> :<reason>]"; }
+       /** Handle command.
+        * @param parameters The parameters to the comamnd
+        * @param pcnt The number of parameters passed to teh command
+        * @param user The user issuing the command
+        * @return A value from CmdResult to indicate command success or failure.
+        */
+       CmdResult Handle(const char** parameters, int pcnt, userrec *user);
+};
+
+#endif
index c0748ec7bf3cd0f5299abb6f7d91b584723df06b..7d0eee9e5864cd3d8b1808ebc6e4d833626a6b0f 100644 (file)
@@ -1 +1,45 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.\r *                  E-mail:\r *               <brain@chatspike.net>\r *                <Craig@chatspike.net>\r *\r * Written by Craig Edwards, Craig McLure, and others.\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __CMD_LINKS_H__\r#define __CMD_LINKS_H__\r\r// include the common header files\r\r#include "users.h"\r#include "channels.h"\r\r/** Handle /LINKS. These command handlers can be reloaded by the core,\r * and handle basic RFC1459 commands. Commands within modules work\r * the same way, however, they can be fully unloaded, where these\r * may not.\r */\rclass cmd_links : public command_t\r{\r public:\r      /** Constructor for links.\r      */\r    cmd_links (InspIRCd* Instance) : command_t(Instance,"LINKS",0,0) { }\r   /** Handle command.\r     * @param parameters The parameters to the comamnd\r      * @param pcnt The number of parameters passed to teh command\r   * @param user The user issuing the command\r     * @return A value from CmdResult to indicate command success or failure.\r       */\r    CmdResult Handle(const char** parameters, int pcnt, userrec *user);\r};\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.
+ *                    E-mail:
+ *             <brain@chatspike.net>
+ *             <Craig@chatspike.net>
+ *
+ * Written by Craig Edwards, Craig McLure, and others.
+ * This program is free but copyrighted software; see
+ *         the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __CMD_LINKS_H__
+#define __CMD_LINKS_H__
+
+// include the common header files
+
+#include "users.h"
+#include "channels.h"
+
+/** Handle /LINKS. These command handlers can be reloaded by the core,
+ * and handle basic RFC1459 commands. Commands within modules work
+ * the same way, however, they can be fully unloaded, where these
+ * may not.
+ */
+class cmd_links : public command_t
+{
+ public:
+       /** Constructor for links.
+        */
+       cmd_links (InspIRCd* Instance) : command_t(Instance,"LINKS",0,0) { }
+       /** Handle command.
+        * @param parameters The parameters to the comamnd
+        * @param pcnt The number of parameters passed to teh command
+        * @param user The user issuing the command
+        * @return A value from CmdResult to indicate command success or failure.
+        */
+       CmdResult Handle(const char** parameters, int pcnt, userrec *user);
+};
+
+#endif
index 01b330bd17e956cd9d6977ca9632bdbbc6d84c66..5c956863d1a89475e7dc4dfb677b1ca7a7871340 100644 (file)
@@ -1 +1,45 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.\r *                  E-mail:\r *               <brain@chatspike.net>\r *                <Craig@chatspike.net>\r *\r * Written by Craig Edwards, Craig McLure, and others.\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __CMD_LIST_H__\r#define __CMD_LIST_H__\r\r// include the common header files\r\r#include "users.h"\r#include "channels.h"\r\r/** Handle /LIST. These command handlers can be reloaded by the core,\r * and handle basic RFC1459 commands. Commands within modules work\r * the same way, however, they can be fully unloaded, where these\r * may not.\r */\rclass cmd_list : public command_t\r{\r public:\r  /** Constructor for list.\r       */\r    cmd_list (InspIRCd* Instance) : command_t(Instance,"LIST",0,0) { }\r     /** Handle command.\r     * @param parameters The parameters to the comamnd\r      * @param pcnt The number of parameters passed to teh command\r   * @param user The user issuing the command\r     * @return A value from CmdResult to indicate command success or failure.\r       */\r    CmdResult Handle(const char** parameters, int pcnt, userrec *user);\r};\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.
+ *                    E-mail:
+ *             <brain@chatspike.net>
+ *             <Craig@chatspike.net>
+ *
+ * Written by Craig Edwards, Craig McLure, and others.
+ * This program is free but copyrighted software; see
+ *         the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __CMD_LIST_H__
+#define __CMD_LIST_H__
+
+// include the common header files
+
+#include "users.h"
+#include "channels.h"
+
+/** Handle /LIST. These command handlers can be reloaded by the core,
+ * and handle basic RFC1459 commands. Commands within modules work
+ * the same way, however, they can be fully unloaded, where these
+ * may not.
+ */
+class cmd_list : public command_t
+{
+ public:
+       /** Constructor for list.
+        */
+       cmd_list (InspIRCd* Instance) : command_t(Instance,"LIST",0,0) { }
+       /** Handle command.
+        * @param parameters The parameters to the comamnd
+        * @param pcnt The number of parameters passed to teh command
+        * @param user The user issuing the command
+        * @return A value from CmdResult to indicate command success or failure.
+        */
+       CmdResult Handle(const char** parameters, int pcnt, userrec *user);
+};
+
+#endif
index e35fc50672a44b0d626f443b8bb749867be8cc09..40ca03e81f1bf702aac7f4b46b1a88e57f4d4092 100644 (file)
@@ -1 +1,45 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.\r *                  E-mail:\r *               <brain@chatspike.net>\r *                <Craig@chatspike.net>\r *\r * Written by Craig Edwards, Craig McLure, and others.\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __CMD_LOADMODULE_H__\r#define __CMD_LOADMODULE_H__\r\r// include the common header files\r\r#include "users.h"\r#include "channels.h"\r\r/** Handle /LOADMODULE. These command handlers can be reloaded by the core,\r * and handle basic RFC1459 commands. Commands within modules work\r * the same way, however, they can be fully unloaded, where these\r * may not.\r */\rclass cmd_loadmodule : public command_t\r{\r public:\r  /** Constructor for loadmodule.\r         */\r    cmd_loadmodule (InspIRCd* Instance) : command_t(Instance,"LOADMODULE",'o',1) { syntax = "<modulename>"; }\r      /** Handle command.\r     * @param parameters The parameters to the comamnd\r      * @param pcnt The number of parameters passed to teh command\r   * @param user The user issuing the command\r     * @return A value from CmdResult to indicate command success or failure.\r       */\r    CmdResult Handle(const char** parameters, int pcnt, userrec *user);\r};\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.
+ *                    E-mail:
+ *             <brain@chatspike.net>
+ *             <Craig@chatspike.net>
+ *
+ * Written by Craig Edwards, Craig McLure, and others.
+ * This program is free but copyrighted software; see
+ *         the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __CMD_LOADMODULE_H__
+#define __CMD_LOADMODULE_H__
+
+// include the common header files
+
+#include "users.h"
+#include "channels.h"
+
+/** Handle /LOADMODULE. These command handlers can be reloaded by the core,
+ * and handle basic RFC1459 commands. Commands within modules work
+ * the same way, however, they can be fully unloaded, where these
+ * may not.
+ */
+class cmd_loadmodule : public command_t
+{
+ public:
+       /** Constructor for loadmodule.
+        */
+       cmd_loadmodule (InspIRCd* Instance) : command_t(Instance,"LOADMODULE",'o',1) { syntax = "<modulename>"; }
+       /** Handle command.
+        * @param parameters The parameters to the comamnd
+        * @param pcnt The number of parameters passed to teh command
+        * @param user The user issuing the command
+        * @return A value from CmdResult to indicate command success or failure.
+        */
+       CmdResult Handle(const char** parameters, int pcnt, userrec *user);
+};
+
+#endif
index 3621fcb118a37fde07391a9eff3e364ece59b38e..8f9226b4eb3b95d5c60d4b48ff72bb2fa93f91e9 100644 (file)
@@ -1 +1,45 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.\r *                  E-mail:\r *               <brain@chatspike.net>\r *                <Craig@chatspike.net>\r *\r * Written by Craig Edwards, Craig McLure, and others.\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __CMD_LUSERS_H__\r#define __CMD_LUSERS_H__\r\r// include the common header files\r\r#include "users.h"\r#include "channels.h"\r\r/** Handle /LUSERS. These command handlers can be reloaded by the core,\r * and handle basic RFC1459 commands. Commands within modules work\r * the same way, however, they can be fully unloaded, where these\r * may not.\r */\rclass cmd_lusers : public command_t\r{\r public:\r  /** Constructor for lusers.\r     */\r    cmd_lusers (InspIRCd* Instance) : command_t(Instance,"LUSERS",0,0) { }\r /** Handle command.\r     * @param parameters The parameters to the comamnd\r      * @param pcnt The number of parameters passed to teh command\r   * @param user The user issuing the command\r     * @return A value from CmdResult to indicate command success or failure.\r       */\r    CmdResult Handle(const char** parameters, int pcnt, userrec *user);\r};\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.
+ *                    E-mail:
+ *             <brain@chatspike.net>
+ *             <Craig@chatspike.net>
+ *
+ * Written by Craig Edwards, Craig McLure, and others.
+ * This program is free but copyrighted software; see
+ *         the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __CMD_LUSERS_H__
+#define __CMD_LUSERS_H__
+
+// include the common header files
+
+#include "users.h"
+#include "channels.h"
+
+/** Handle /LUSERS. These command handlers can be reloaded by the core,
+ * and handle basic RFC1459 commands. Commands within modules work
+ * the same way, however, they can be fully unloaded, where these
+ * may not.
+ */
+class cmd_lusers : public command_t
+{
+ public:
+       /** Constructor for lusers.
+        */
+       cmd_lusers (InspIRCd* Instance) : command_t(Instance,"LUSERS",0,0) { }
+       /** Handle command.
+        * @param parameters The parameters to the comamnd
+        * @param pcnt The number of parameters passed to teh command
+        * @param user The user issuing the command
+        * @return A value from CmdResult to indicate command success or failure.
+        */
+       CmdResult Handle(const char** parameters, int pcnt, userrec *user);
+};
+
+#endif
index e67e09b53167b797dc571534fd9de14b697893e9..f1b586c9f3054f95155dc5785171df092c74d758 100644 (file)
@@ -1 +1,45 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.\r *                  E-mail:\r *               <brain@chatspike.net>\r *                <Craig@chatspike.net>\r *\r * Written by Craig Edwards, Craig McLure, and others.\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __CMD_MAP_H__\r#define __CMD_MAP_H__\r\r// include the common header files\r\r#include "users.h"\r#include "channels.h"\r\r/** Handle /MAP. These command handlers can be reloaded by the core,\r * and handle basic RFC1459 commands. Commands within modules work\r * the same way, however, they can be fully unloaded, where these\r * may not.\r */\rclass cmd_map : public command_t\r{\r public:\r      /** Constructor for map.\r        */\r    cmd_map (InspIRCd* Instance) : command_t(Instance,"MAP",0,0) { }\r       /** Handle command.\r     * @param parameters The parameters to the comamnd\r      * @param pcnt The number of parameters passed to teh command\r   * @param user The user issuing the command\r     * @return A value from CmdResult to indicate command success or failure.\r       */\r    CmdResult Handle(const char** parameters, int pcnt, userrec *user);\r};\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.
+ *                    E-mail:
+ *             <brain@chatspike.net>
+ *             <Craig@chatspike.net>
+ *
+ * Written by Craig Edwards, Craig McLure, and others.
+ * This program is free but copyrighted software; see
+ *         the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __CMD_MAP_H__
+#define __CMD_MAP_H__
+
+// include the common header files
+
+#include "users.h"
+#include "channels.h"
+
+/** Handle /MAP. These command handlers can be reloaded by the core,
+ * and handle basic RFC1459 commands. Commands within modules work
+ * the same way, however, they can be fully unloaded, where these
+ * may not.
+ */
+class cmd_map : public command_t
+{
+ public:
+       /** Constructor for map.
+        */
+       cmd_map (InspIRCd* Instance) : command_t(Instance,"MAP",0,0) { }
+       /** Handle command.
+        * @param parameters The parameters to the comamnd
+        * @param pcnt The number of parameters passed to teh command
+        * @param user The user issuing the command
+        * @return A value from CmdResult to indicate command success or failure.
+        */
+       CmdResult Handle(const char** parameters, int pcnt, userrec *user);
+};
+
+#endif
index a75bd86352ba4ddca3c7ec3734c28260a3df1071..36e76bf66b8d5e5a940b6c574f99a9dccba41552 100644 (file)
@@ -1 +1,44 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.\r *                  E-mail:\r *               <brain@chatspike.net>\r *                <Craig@chatspike.net>\r *\r * Written by Craig Edwards, Craig McLure, and others.\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __CMD_ADMIN_H__\r#define __CMD_ADMIN_H__\r\r#include "users.h"\r#include "channels.h"\r#include "ctables.h"\r\r/** Handle /MODE. These command handlers can be reloaded by the core,\r * and handle basic RFC1459 commands. Commands within modules work\r * the same way, however, they can be fully unloaded, where these\r * may not.\r */\rclass cmd_mode : public command_t\r{\r public:\r       /** Constructor for mode.\r       */\r    cmd_mode (InspIRCd* Instance) : command_t(Instance,"MODE",0,1) { syntax = "<target> <modes> {<mode-parameters>}"; }\r    /** Handle command.\r     * @param parameters The parameters to the comamnd\r      * @param pcnt The number of parameters passed to teh command\r   * @param user The user issuing the command\r     * @return A value from CmdResult to indicate command success or failure.\r       */\r    CmdResult Handle(const char** parameters, int pcnt, userrec *user);\r};\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.
+ *                    E-mail:
+ *             <brain@chatspike.net>
+ *             <Craig@chatspike.net>
+ *
+ * Written by Craig Edwards, Craig McLure, and others.
+ * This program is free but copyrighted software; see
+ *         the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __CMD_ADMIN_H__
+#define __CMD_ADMIN_H__
+
+#include "users.h"
+#include "channels.h"
+#include "ctables.h"
+
+/** Handle /MODE. These command handlers can be reloaded by the core,
+ * and handle basic RFC1459 commands. Commands within modules work
+ * the same way, however, they can be fully unloaded, where these
+ * may not.
+ */
+class cmd_mode : public command_t
+{
+ public:
+       /** Constructor for mode.
+        */
+       cmd_mode (InspIRCd* Instance) : command_t(Instance,"MODE",0,1) { syntax = "<target> <modes> {<mode-parameters>}"; }
+       /** Handle command.
+        * @param parameters The parameters to the comamnd
+        * @param pcnt The number of parameters passed to teh command
+        * @param user The user issuing the command
+        * @return A value from CmdResult to indicate command success or failure.
+        */
+       CmdResult Handle(const char** parameters, int pcnt, userrec *user);
+};
+
+#endif
index 02ada014a5ca1a584e831d0db78381a82adf2b9b..372a87c058a552e7a879f3b32841eb8b8722fd9f 100644 (file)
@@ -1 +1,45 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.\r *                  E-mail:\r *               <brain@chatspike.net>\r *                <Craig@chatspike.net>\r *\r * Written by Craig Edwards, Craig McLure, and others.\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __CMD_MODULES_H__\r#define __CMD_MODULES_H__\r\r// include the common header files\r\r#include "users.h"\r#include "channels.h"\r\r/** Handle /MODULES. These command handlers can be reloaded by the core,\r * and handle basic RFC1459 commands. Commands within modules work\r * the same way, however, they can be fully unloaded, where these\r * may not.\r */\rclass cmd_modules : public command_t\r{\r public:\r      /** Constructor for modules.\r    */\r    cmd_modules (InspIRCd* Instance) : command_t(Instance,"MODULES",0,0) { syntax = "[debug]"; }\r   /** Handle command.\r     * @param parameters The parameters to the comamnd\r      * @param pcnt The number of parameters passed to teh command\r   * @param user The user issuing the command\r     * @return A value from CmdResult to indicate command success or failure.\r       */\r    CmdResult Handle(const char** parameters, int pcnt, userrec *user);\r};\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.
+ *                    E-mail:
+ *             <brain@chatspike.net>
+ *             <Craig@chatspike.net>
+ *
+ * Written by Craig Edwards, Craig McLure, and others.
+ * This program is free but copyrighted software; see
+ *         the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __CMD_MODULES_H__
+#define __CMD_MODULES_H__
+
+// include the common header files
+
+#include "users.h"
+#include "channels.h"
+
+/** Handle /MODULES. These command handlers can be reloaded by the core,
+ * and handle basic RFC1459 commands. Commands within modules work
+ * the same way, however, they can be fully unloaded, where these
+ * may not.
+ */
+class cmd_modules : public command_t
+{
+ public:
+       /** Constructor for modules.
+        */
+       cmd_modules (InspIRCd* Instance) : command_t(Instance,"MODULES",0,0) { syntax = "[debug]"; }
+       /** Handle command.
+        * @param parameters The parameters to the comamnd
+        * @param pcnt The number of parameters passed to teh command
+        * @param user The user issuing the command
+        * @return A value from CmdResult to indicate command success or failure.
+        */
+       CmdResult Handle(const char** parameters, int pcnt, userrec *user);
+};
+
+#endif
index 47c1ca9879c9d0f27de5c2967c1f741af33e8b6c..75162274a15e876f5deea09408bce5c1133afdbb 100644 (file)
@@ -1 +1,48 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.\r *                  E-mail:\r *               <brain@chatspike.net>\r *                <Craig@chatspike.net>\r *\r * Written by Craig Edwards, Craig McLure, and others.\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __CMD_MOTD_H__\r#define __CMD_MOTD_H__\r\r// include the common header files\r\r#include <string>\r#include <vector>\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r\r/** Handle /MOTD. These command handlers can be reloaded by the core,\r * and handle basic RFC1459 commands. Commands within modules work\r * the same way, however, they can be fully unloaded, where these\r * may not.\r */\rclass cmd_motd : public command_t\r{\r public:\r        /** Constructor for motd.\r       */\r    cmd_motd (InspIRCd* Instance) : command_t(Instance,"MOTD",0,0) { syntax = "[<servername>]"; }\r  /** Handle command.\r     * @param parameters The parameters to the comamnd\r      * @param pcnt The number of parameters passed to teh command\r   * @param user The user issuing the command\r     * @return A value from CmdResult to indicate command success or failure.\r       */\r    CmdResult Handle(const char** parameters, int pcnt, userrec *user);\r};\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.
+ *                    E-mail:
+ *             <brain@chatspike.net>
+ *             <Craig@chatspike.net>
+ *
+ * Written by Craig Edwards, Craig McLure, and others.
+ * This program is free but copyrighted software; see
+ *         the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __CMD_MOTD_H__
+#define __CMD_MOTD_H__
+
+// include the common header files
+
+#include <string>
+#include <vector>
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+
+/** Handle /MOTD. These command handlers can be reloaded by the core,
+ * and handle basic RFC1459 commands. Commands within modules work
+ * the same way, however, they can be fully unloaded, where these
+ * may not.
+ */
+class cmd_motd : public command_t
+{
+ public:
+       /** Constructor for motd.
+        */
+       cmd_motd (InspIRCd* Instance) : command_t(Instance,"MOTD",0,0) { syntax = "[<servername>]"; }
+       /** Handle command.
+        * @param parameters The parameters to the comamnd
+        * @param pcnt The number of parameters passed to teh command
+        * @param user The user issuing the command
+        * @return A value from CmdResult to indicate command success or failure.
+        */
+       CmdResult Handle(const char** parameters, int pcnt, userrec *user);
+};
+
+#endif
index b1e78df3f7107f34e50bcdd966cec720afeba934..135e7946b056959585b24733d911fbf6352dd4e7 100644 (file)
@@ -1 +1,45 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.\r *                  E-mail:\r *               <brain@chatspike.net>\r *                <Craig@chatspike.net>\r *\r * Written by Craig Edwards, Craig McLure, and others.\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __CMD_NAMES_H__\r#define __CMD_NAMES_H__\r\r// include the common header files\r\r#include "users.h"\r#include "channels.h"\r\r/** Handle /NAMES. These command handlers can be reloaded by the core,\r * and handle basic RFC1459 commands. Commands within modules work\r * the same way, however, they can be fully unloaded, where these\r * may not.\r */\rclass cmd_names : public command_t\r{\r public:\r      /** Constructor for names.\r      */\r    cmd_names (InspIRCd* Instance) : command_t(Instance,"NAMES",0,0) { syntax = "{<channel>{,<channel>}}"; }\r       /** Handle command.\r     * @param parameters The parameters to the comamnd\r      * @param pcnt The number of parameters passed to teh command\r   * @param user The user issuing the command\r     * @return A value from CmdResult to indicate command success or failure.\r       */\r    CmdResult Handle(const char** parameters, int pcnt, userrec *user);\r};\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.
+ *                    E-mail:
+ *             <brain@chatspike.net>
+ *             <Craig@chatspike.net>
+ *
+ * Written by Craig Edwards, Craig McLure, and others.
+ * This program is free but copyrighted software; see
+ *         the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __CMD_NAMES_H__
+#define __CMD_NAMES_H__
+
+// include the common header files
+
+#include "users.h"
+#include "channels.h"
+
+/** Handle /NAMES. These command handlers can be reloaded by the core,
+ * and handle basic RFC1459 commands. Commands within modules work
+ * the same way, however, they can be fully unloaded, where these
+ * may not.
+ */
+class cmd_names : public command_t
+{
+ public:
+       /** Constructor for names.
+        */
+       cmd_names (InspIRCd* Instance) : command_t(Instance,"NAMES",0,0) { syntax = "{<channel>{,<channel>}}"; }
+       /** Handle command.
+        * @param parameters The parameters to the comamnd
+        * @param pcnt The number of parameters passed to teh command
+        * @param user The user issuing the command
+        * @return A value from CmdResult to indicate command success or failure.
+        */
+       CmdResult Handle(const char** parameters, int pcnt, userrec *user);
+};
+
+#endif
index b1485a27bd87529b6426e8f9a1f7c76ec97ea200..69df1514e6465d368a9b2234ad835d28dbc74ad4 100644 (file)
@@ -1 +1,45 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.\r *                  E-mail:\r *               <brain@chatspike.net>\r *                <Craig@chatspike.net>\r *\r * Written by Craig Edwards, Craig McLure, and others.\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __CMD_NICK_H__\r#define __CMD_NICK_H__\r\r// include the common header files\r\r#include "users.h"\r#include "channels.h"\r\r/** Handle /NICK. These command handlers can be reloaded by the core,\r * and handle basic RFC1459 commands. Commands within modules work\r * the same way, however, they can be fully unloaded, where these\r * may not.\r */\rclass cmd_nick : public command_t\r{\r public:\r  /** Constructor for nick.\r       */\r    cmd_nick (InspIRCd* Instance) : command_t(Instance,"NICK",0,1,true) { syntax = "<newnick>"; }\r  /** Handle command.\r     * @param parameters The parameters to the comamnd\r      * @param pcnt The number of parameters passed to teh command\r   * @param user The user issuing the command\r     * @return A value from CmdResult to indicate command success or failure.\r       */\r    CmdResult Handle(const char** parameters, int pcnt, userrec *user);\r};\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.
+ *                    E-mail:
+ *             <brain@chatspike.net>
+ *             <Craig@chatspike.net>
+ *
+ * Written by Craig Edwards, Craig McLure, and others.
+ * This program is free but copyrighted software; see
+ *         the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __CMD_NICK_H__
+#define __CMD_NICK_H__
+
+// include the common header files
+
+#include "users.h"
+#include "channels.h"
+
+/** Handle /NICK. These command handlers can be reloaded by the core,
+ * and handle basic RFC1459 commands. Commands within modules work
+ * the same way, however, they can be fully unloaded, where these
+ * may not.
+ */
+class cmd_nick : public command_t
+{
+ public:
+       /** Constructor for nick.
+        */
+       cmd_nick (InspIRCd* Instance) : command_t(Instance,"NICK",0,1,true) { syntax = "<newnick>"; }
+       /** Handle command.
+        * @param parameters The parameters to the comamnd
+        * @param pcnt The number of parameters passed to teh command
+        * @param user The user issuing the command
+        * @return A value from CmdResult to indicate command success or failure.
+        */
+       CmdResult Handle(const char** parameters, int pcnt, userrec *user);
+};
+
+#endif
index 402f4b3b117d60d0464402b56fc62086e1d187b4..ec4372066127bcac05ea49092f79590b2bb0adf7 100644 (file)
@@ -1 +1,45 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.\r *                  E-mail:\r *               <brain@chatspike.net>\r *                <Craig@chatspike.net>\r *\r * Written by Craig Edwards, Craig McLure, and others.\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __CMD_NOTICE_H__\r#define __CMD_NOTICE_H__\r\r// include the common header files\r\r#include "users.h"\r#include "channels.h"\r\r/** Handle /NOTICE. These command handlers can be reloaded by the core,\r * and handle basic RFC1459 commands. Commands within modules work\r * the same way, however, they can be fully unloaded, where these\r * may not.\r */\rclass cmd_notice : public command_t\r{\r public:\r  /** Constructor for notice.\r     */\r    cmd_notice (InspIRCd* Instance) : command_t(Instance,"NOTICE",0,2) { syntax = "<target>{,<target>} <message>"; }\r       /** Handle command.\r     * @param parameters The parameters to the comamnd\r      * @param pcnt The number of parameters passed to teh command\r   * @param user The user issuing the command\r     * @return A value from CmdResult to indicate command success or failure.\r       */\r    CmdResult Handle(const char** parameters, int pcnt, userrec *user);\r};\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.
+ *                    E-mail:
+ *             <brain@chatspike.net>
+ *             <Craig@chatspike.net>
+ *
+ * Written by Craig Edwards, Craig McLure, and others.
+ * This program is free but copyrighted software; see
+ *         the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __CMD_NOTICE_H__
+#define __CMD_NOTICE_H__
+
+// include the common header files
+
+#include "users.h"
+#include "channels.h"
+
+/** Handle /NOTICE. These command handlers can be reloaded by the core,
+ * and handle basic RFC1459 commands. Commands within modules work
+ * the same way, however, they can be fully unloaded, where these
+ * may not.
+ */
+class cmd_notice : public command_t
+{
+ public:
+       /** Constructor for notice.
+        */
+       cmd_notice (InspIRCd* Instance) : command_t(Instance,"NOTICE",0,2) { syntax = "<target>{,<target>} <message>"; }
+       /** Handle command.
+        * @param parameters The parameters to the comamnd
+        * @param pcnt The number of parameters passed to teh command
+        * @param user The user issuing the command
+        * @return A value from CmdResult to indicate command success or failure.
+        */
+       CmdResult Handle(const char** parameters, int pcnt, userrec *user);
+};
+
+#endif
index 0bfda174e33587fb88edda6ef0dd01df225a8698..77c4b01255174b05941a89bd6f0f8d73506fafd1 100644 (file)
@@ -1 +1,47 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.\r *                  E-mail:\r *               <brain@chatspike.net>\r *                <Craig@chatspike.net>\r *\r * Written by Craig Edwards, Craig McLure, and others.\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __CMD_OPER_H__\r#define __CMD_OPER_H__\r\r// include the common header files\r\r#include "users.h"\r#include "channels.h"\r\rbool OneOfMatches(const char* host, const char* ip, const char* hostlist);\r\r/** Handle /OPER. These command handlers can be reloaded by the core,\r * and handle basic RFC1459 commands. Commands within modules work\r * the same way, however, they can be fully unloaded, where these\r * may not.\r */\rclass cmd_oper : public command_t\r{\r public:\r      /** Constructor for oper.\r       */\r    cmd_oper (InspIRCd* Instance) : command_t(Instance,"OPER",0,2) { syntax = "<username> <password>"; }\r   /** Handle command.\r     * @param parameters The parameters to the comamnd\r      * @param pcnt The number of parameters passed to teh command\r   * @param user The user issuing the command\r     * @return A value from CmdResult to indicate command success or failure.\r       */\r    CmdResult Handle(const char** parameters, int pcnt, userrec *user);\r};\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.
+ *                    E-mail:
+ *             <brain@chatspike.net>
+ *             <Craig@chatspike.net>
+ *
+ * Written by Craig Edwards, Craig McLure, and others.
+ * This program is free but copyrighted software; see
+ *         the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __CMD_OPER_H__
+#define __CMD_OPER_H__
+
+// include the common header files
+
+#include "users.h"
+#include "channels.h"
+
+bool OneOfMatches(const char* host, const char* ip, const char* hostlist);
+
+/** Handle /OPER. These command handlers can be reloaded by the core,
+ * and handle basic RFC1459 commands. Commands within modules work
+ * the same way, however, they can be fully unloaded, where these
+ * may not.
+ */
+class cmd_oper : public command_t
+{
+ public:
+       /** Constructor for oper.
+        */
+       cmd_oper (InspIRCd* Instance) : command_t(Instance,"OPER",0,2) { syntax = "<username> <password>"; }
+       /** Handle command.
+        * @param parameters The parameters to the comamnd
+        * @param pcnt The number of parameters passed to teh command
+        * @param user The user issuing the command
+        * @return A value from CmdResult to indicate command success or failure.
+        */
+       CmdResult Handle(const char** parameters, int pcnt, userrec *user);
+};
+
+#endif
index e4ce48e0883d670a7465abc6ff4e655b25b44cee..5f5781874d9caa4bf0cbf51e4b4f6aca60ef82b2 100644 (file)
@@ -1 +1,45 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.\r *                  E-mail:\r *               <brain@chatspike.net>\r *                <Craig@chatspike.net>\r *\r * Written by Craig Edwards, Craig McLure, and others.\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __CMD_PART_H__\r#define __CMD_PART_H__\r\r// include the common header files\r\r#include "users.h"\r#include "channels.h"\r\r/** Handle /PART. These command handlers can be reloaded by the core,\r * and handle basic RFC1459 commands. Commands within modules work\r * the same way, however, they can be fully unloaded, where these\r * may not.\r */\rclass cmd_part : public command_t\r{\r public:\r  /** Constructor for part.\r       */\r    cmd_part (InspIRCd* Instance) : command_t(Instance,"PART",0,1) { syntax = "<channel>{,<channel>} [<reason>]"; }\r        /** Handle command.\r     * @param parameters The parameters to the comamnd\r      * @param pcnt The number of parameters passed to teh command\r   * @param user The user issuing the command\r     * @return A value from CmdResult to indicate command success or failure.\r       */\r    CmdResult Handle(const char** parameters, int pcnt, userrec *user);\r};\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.
+ *                    E-mail:
+ *             <brain@chatspike.net>
+ *             <Craig@chatspike.net>
+ *
+ * Written by Craig Edwards, Craig McLure, and others.
+ * This program is free but copyrighted software; see
+ *         the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __CMD_PART_H__
+#define __CMD_PART_H__
+
+// include the common header files
+
+#include "users.h"
+#include "channels.h"
+
+/** Handle /PART. These command handlers can be reloaded by the core,
+ * and handle basic RFC1459 commands. Commands within modules work
+ * the same way, however, they can be fully unloaded, where these
+ * may not.
+ */
+class cmd_part : public command_t
+{
+ public:
+       /** Constructor for part.
+        */
+       cmd_part (InspIRCd* Instance) : command_t(Instance,"PART",0,1) { syntax = "<channel>{,<channel>} [<reason>]"; }
+       /** Handle command.
+        * @param parameters The parameters to the comamnd
+        * @param pcnt The number of parameters passed to teh command
+        * @param user The user issuing the command
+        * @return A value from CmdResult to indicate command success or failure.
+        */
+       CmdResult Handle(const char** parameters, int pcnt, userrec *user);
+};
+
+#endif
index d3d2cb76bb945672522b09c1cb2645608b3894f0..53addf80fdfa1ae4dcd29facef41169878d45253 100644 (file)
@@ -1 +1,48 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.\r *                  E-mail:\r *               <brain@chatspike.net>\r *                <Craig@chatspike.net>\r *\r * Written by Craig Edwards, Craig McLure, and others.\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __CMD_PASS_H__\r#define __CMD_PASS_H__\r\r// include the common header files\r\r#include <string>\r#include <vector>\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r\r/** Handle /PASS. These command handlers can be reloaded by the core,\r * and handle basic RFC1459 commands. Commands within modules work\r * the same way, however, they can be fully unloaded, where these\r * may not.\r */\rclass cmd_pass : public command_t\r{\r public:\r        /** Constructor for pass.\r       */\r    cmd_pass (InspIRCd* Instance) : command_t(Instance,"PASS",0,1,true) { syntax = "<password>"; }\r /** Handle command.\r     * @param parameters The parameters to the comamnd\r      * @param pcnt The number of parameters passed to teh command\r   * @param user The user issuing the command\r     * @return A value from CmdResult to indicate command success or failure.\r       */\r    CmdResult Handle(const char** parameters, int pcnt, userrec *user);\r};\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.
+ *                    E-mail:
+ *             <brain@chatspike.net>
+ *             <Craig@chatspike.net>
+ *
+ * Written by Craig Edwards, Craig McLure, and others.
+ * This program is free but copyrighted software; see
+ *         the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __CMD_PASS_H__
+#define __CMD_PASS_H__
+
+// include the common header files
+
+#include <string>
+#include <vector>
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+
+/** Handle /PASS. These command handlers can be reloaded by the core,
+ * and handle basic RFC1459 commands. Commands within modules work
+ * the same way, however, they can be fully unloaded, where these
+ * may not.
+ */
+class cmd_pass : public command_t
+{
+ public:
+       /** Constructor for pass.
+        */
+       cmd_pass (InspIRCd* Instance) : command_t(Instance,"PASS",0,1,true) { syntax = "<password>"; }
+       /** Handle command.
+        * @param parameters The parameters to the comamnd
+        * @param pcnt The number of parameters passed to teh command
+        * @param user The user issuing the command
+        * @return A value from CmdResult to indicate command success or failure.
+        */
+       CmdResult Handle(const char** parameters, int pcnt, userrec *user);
+};
+
+#endif
index 1e04eb18ecb3f3944940330df20eacad8ac9fd47..c5350eba5bf96fa3339663f2bb034f2f29c16fa8 100644 (file)
@@ -1 +1,45 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.\r *                  E-mail:\r *               <brain@chatspike.net>\r *                <Craig@chatspike.net>\r *\r * Written by Craig Edwards, Craig McLure, and others.\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __CMD_PING_H__\r#define __CMD_PING_H__\r\r// include the common header files\r\r#include "users.h"\r#include "channels.h"\r\r/** Handle /PING. These command handlers can be reloaded by the core,\r * and handle basic RFC1459 commands. Commands within modules work\r * the same way, however, they can be fully unloaded, where these\r * may not.\r */\rclass cmd_ping : public command_t\r{\r public:\r  /** Constructor for ping.\r       */\r    cmd_ping (InspIRCd* Instance) : command_t(Instance,"PING",0,1) { syntax = "<servername> [:<servername>]"; }\r    /** Handle command.\r     * @param parameters The parameters to the comamnd\r      * @param pcnt The number of parameters passed to teh command\r   * @param user The user issuing the command\r     * @return A value from CmdResult to indicate command success or failure.\r       */\r    CmdResult Handle(const char** parameters, int pcnt, userrec *user);\r};\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.
+ *                    E-mail:
+ *             <brain@chatspike.net>
+ *             <Craig@chatspike.net>
+ *
+ * Written by Craig Edwards, Craig McLure, and others.
+ * This program is free but copyrighted software; see
+ *         the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __CMD_PING_H__
+#define __CMD_PING_H__
+
+// include the common header files
+
+#include "users.h"
+#include "channels.h"
+
+/** Handle /PING. These command handlers can be reloaded by the core,
+ * and handle basic RFC1459 commands. Commands within modules work
+ * the same way, however, they can be fully unloaded, where these
+ * may not.
+ */
+class cmd_ping : public command_t
+{
+ public:
+       /** Constructor for ping.
+        */
+       cmd_ping (InspIRCd* Instance) : command_t(Instance,"PING",0,1) { syntax = "<servername> [:<servername>]"; }
+       /** Handle command.
+        * @param parameters The parameters to the comamnd
+        * @param pcnt The number of parameters passed to teh command
+        * @param user The user issuing the command
+        * @return A value from CmdResult to indicate command success or failure.
+        */
+       CmdResult Handle(const char** parameters, int pcnt, userrec *user);
+};
+
+#endif
index 73784b34030177cd5cbb3bafde25f4ef5b6999ef..724ed0dfc435b0f8111ade7f991dcfbb29170cb0 100644 (file)
@@ -1 +1,46 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.\r *                  E-mail:\r *               <brain@chatspike.net>\r *                <Craig@chatspike.net>\r *\r * Written by Craig Edwards, Craig McLure, and others.\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __CMD_PONG_H__\r#define __CMD_PONG_H__\r\r// include the common header files\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r\r/** Handle /PONG. These command handlers can be reloaded by the core,\r * and handle basic RFC1459 commands. Commands within modules work\r * the same way, however, they can be fully unloaded, where these\r * may not.\r */\rclass cmd_pong : public command_t\r{\r public:\r    /** Constructor for pong.\r       */\r    cmd_pong (InspIRCd* Instance) : command_t(Instance,"PONG",0,1) { syntax = "<ping-text>"; }\r     /** Handle command.\r     * @param parameters The parameters to the comamnd\r      * @param pcnt The number of parameters passed to teh command\r   * @param user The user issuing the command\r     * @return A value from CmdResult to indicate command success or failure.\r       */\r    CmdResult Handle(const char** parameters, int pcnt, userrec *user);\r};\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.
+ *                    E-mail:
+ *             <brain@chatspike.net>
+ *             <Craig@chatspike.net>
+ *
+ * Written by Craig Edwards, Craig McLure, and others.
+ * This program is free but copyrighted software; see
+ *         the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __CMD_PONG_H__
+#define __CMD_PONG_H__
+
+// include the common header files
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+
+/** Handle /PONG. These command handlers can be reloaded by the core,
+ * and handle basic RFC1459 commands. Commands within modules work
+ * the same way, however, they can be fully unloaded, where these
+ * may not.
+ */
+class cmd_pong : public command_t
+{
+ public:
+       /** Constructor for pong.
+        */
+       cmd_pong (InspIRCd* Instance) : command_t(Instance,"PONG",0,1) { syntax = "<ping-text>"; }
+       /** Handle command.
+        * @param parameters The parameters to the comamnd
+        * @param pcnt The number of parameters passed to teh command
+        * @param user The user issuing the command
+        * @return A value from CmdResult to indicate command success or failure.
+        */
+       CmdResult Handle(const char** parameters, int pcnt, userrec *user);
+};
+
+#endif
index 0b43d803c30e2e2ab2262356ee4ce93f51150a9c..17b7b0445b18b3fb1970b8bec58b124990641759 100644 (file)
@@ -1 +1,45 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.\r *                  E-mail:\r *               <brain@chatspike.net>\r *                <Craig@chatspike.net>\r *\r * Written by Craig Edwards, Craig McLure, and others.\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __CMD_PRIVMSG_H__\r#define __CMD_PRIVMSG_H__\r\r// include the common header files\r\r#include "users.h"\r#include "channels.h"\r\r/** Handle /PRIVMSG. These command handlers can be reloaded by the core,\r * and handle basic RFC1459 commands. Commands within modules work\r * the same way, however, they can be fully unloaded, where these\r * may not.\r */\rclass cmd_privmsg : public command_t\r{\r public:\r      /** Constructor for privmsg.\r    */\r    cmd_privmsg (InspIRCd* Instance) : command_t(Instance,"PRIVMSG",0,2) { syntax = "<target>{,<target>} <message>"; }\r     /** Handle command.\r     * @param parameters The parameters to the comamnd\r      * @param pcnt The number of parameters passed to teh command\r   * @param user The user issuing the command\r     * @return A value from CmdResult to indicate command success or failure.\r       */\r    CmdResult Handle(const char** parameters, int pcnt, userrec *user);\r};\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.
+ *                    E-mail:
+ *             <brain@chatspike.net>
+ *             <Craig@chatspike.net>
+ *
+ * Written by Craig Edwards, Craig McLure, and others.
+ * This program is free but copyrighted software; see
+ *         the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __CMD_PRIVMSG_H__
+#define __CMD_PRIVMSG_H__
+
+// include the common header files
+
+#include "users.h"
+#include "channels.h"
+
+/** Handle /PRIVMSG. These command handlers can be reloaded by the core,
+ * and handle basic RFC1459 commands. Commands within modules work
+ * the same way, however, they can be fully unloaded, where these
+ * may not.
+ */
+class cmd_privmsg : public command_t
+{
+ public:
+       /** Constructor for privmsg.
+        */
+       cmd_privmsg (InspIRCd* Instance) : command_t(Instance,"PRIVMSG",0,2) { syntax = "<target>{,<target>} <message>"; }
+       /** Handle command.
+        * @param parameters The parameters to the comamnd
+        * @param pcnt The number of parameters passed to teh command
+        * @param user The user issuing the command
+        * @return A value from CmdResult to indicate command success or failure.
+        */
+       CmdResult Handle(const char** parameters, int pcnt, userrec *user);
+};
+
+#endif
index 1aca556a88c107077d75c02518f3db21e1078ae6..5d69f9a9a0638133c17729e56b13c57489b58cf7 100644 (file)
@@ -1 +1,45 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.\r *                  E-mail:\r *               <brain@chatspike.net>\r *                <Craig@chatspike.net>\r *\r * Written by Craig Edwards, Craig McLure, and others.\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __CMD_QLINE_H__\r#define __CMD_QLINE_H__\r\r// include the common header files\r\r#include "users.h"\r#include "channels.h"\r\r/** Handle /QLINE. These command handlers can be reloaded by the core,\r * and handle basic RFC1459 commands. Commands within modules work\r * the same way, however, they can be fully unloaded, where these\r * may not.\r */\rclass cmd_qline : public command_t\r{\r public:\r      /** Constructor for qline.\r      */\r    cmd_qline (InspIRCd* Instance) : command_t(Instance,"QLINE",'o',1) { syntax = "<nick> [<duration> :<reason>]"; }\r       /** Handle command.\r     * @param parameters The parameters to the comamnd\r      * @param pcnt The number of parameters passed to teh command\r   * @param user The user issuing the command\r     * @return A value from CmdResult to indicate command success or failure.\r       */\r    CmdResult Handle(const char** parameters, int pcnt, userrec *user);\r};\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.
+ *                    E-mail:
+ *             <brain@chatspike.net>
+ *             <Craig@chatspike.net>
+ *
+ * Written by Craig Edwards, Craig McLure, and others.
+ * This program is free but copyrighted software; see
+ *         the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __CMD_QLINE_H__
+#define __CMD_QLINE_H__
+
+// include the common header files
+
+#include "users.h"
+#include "channels.h"
+
+/** Handle /QLINE. These command handlers can be reloaded by the core,
+ * and handle basic RFC1459 commands. Commands within modules work
+ * the same way, however, they can be fully unloaded, where these
+ * may not.
+ */
+class cmd_qline : public command_t
+{
+ public:
+       /** Constructor for qline.
+        */
+       cmd_qline (InspIRCd* Instance) : command_t(Instance,"QLINE",'o',1) { syntax = "<nick> [<duration> :<reason>]"; }
+       /** Handle command.
+        * @param parameters The parameters to the comamnd
+        * @param pcnt The number of parameters passed to teh command
+        * @param user The user issuing the command
+        * @return A value from CmdResult to indicate command success or failure.
+        */
+       CmdResult Handle(const char** parameters, int pcnt, userrec *user);
+};
+
+#endif
index 2d3287d13850340bc16126826d7a319052aed9a9..9c80130a2c00d933ebe54ce906ade021af0edd8f 100644 (file)
@@ -1 +1,45 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.\r *                  E-mail:\r *               <brain@chatspike.net>\r *                <Craig@chatspike.net>\r *\r * Written by Craig Edwards, Craig McLure, and others.\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __CMD_QUIT_H__\r#define __CMD_QUIT_H__\r\r// include the common header files\r\r#include "users.h"\r#include "channels.h"\r\r/** Handle /QUIT. These command handlers can be reloaded by the core,\r * and handle basic RFC1459 commands. Commands within modules work\r * the same way, however, they can be fully unloaded, where these\r * may not.\r */\rclass cmd_quit : public command_t\r{\r public:\r  /** Constructor for quit.\r       */\r    cmd_quit (InspIRCd* Instance) : command_t(Instance,"QUIT",0,0,true) { syntax = "[<message>]"; }\r        /** Handle command.\r     * @param parameters The parameters to the comamnd\r      * @param pcnt The number of parameters passed to teh command\r   * @param user The user issuing the command\r     * @return A value from CmdResult to indicate command success or failure.\r       */\r    CmdResult Handle(const char** parameters, int pcnt, userrec *user);\r};\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.
+ *                    E-mail:
+ *             <brain@chatspike.net>
+ *             <Craig@chatspike.net>
+ *
+ * Written by Craig Edwards, Craig McLure, and others.
+ * This program is free but copyrighted software; see
+ *         the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __CMD_QUIT_H__
+#define __CMD_QUIT_H__
+
+// include the common header files
+
+#include "users.h"
+#include "channels.h"
+
+/** Handle /QUIT. These command handlers can be reloaded by the core,
+ * and handle basic RFC1459 commands. Commands within modules work
+ * the same way, however, they can be fully unloaded, where these
+ * may not.
+ */
+class cmd_quit : public command_t
+{
+ public:
+       /** Constructor for quit.
+        */
+       cmd_quit (InspIRCd* Instance) : command_t(Instance,"QUIT",0,0,true) { syntax = "[<message>]"; }
+       /** Handle command.
+        * @param parameters The parameters to the comamnd
+        * @param pcnt The number of parameters passed to teh command
+        * @param user The user issuing the command
+        * @return A value from CmdResult to indicate command success or failure.
+        */
+       CmdResult Handle(const char** parameters, int pcnt, userrec *user);
+};
+
+#endif
index de8d9b6c665063dfecd8addd2d7729ee81942251..f33ac141dc5cd1c51c991633789ec211b4c596c9 100644 (file)
@@ -1 +1,45 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.\r *                  E-mail:\r *               <brain@chatspike.net>\r *                <Craig@chatspike.net>\r *\r * Written by Craig Edwards, Craig McLure, and others.\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __CMD_REHASH_H__\r#define __CMD_REHASH_H__\r\r// include the common header files\r\r#include "users.h"\r#include "channels.h"\r\r/** Handle /REHASH. These command handlers can be reloaded by the core,\r * and handle basic RFC1459 commands. Commands within modules work\r * the same way, however, they can be fully unloaded, where these\r * may not.\r */\rclass cmd_rehash : public command_t\r{\r public:\r  /** Constructor for rehash.\r     */\r    cmd_rehash (InspIRCd* Instance) : command_t(Instance,"REHASH",'o',0) { syntax = "[<servermask>]"; }\r    /** Handle command.\r     * @param parameters The parameters to the comamnd\r      * @param pcnt The number of parameters passed to teh command\r   * @param user The user issuing the command\r     * @return A value from CmdResult to indicate command success or failure.\r       */\r    CmdResult Handle(const char** parameters, int pcnt, userrec *user);\r};\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.
+ *                    E-mail:
+ *             <brain@chatspike.net>
+ *             <Craig@chatspike.net>
+ *
+ * Written by Craig Edwards, Craig McLure, and others.
+ * This program is free but copyrighted software; see
+ *         the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __CMD_REHASH_H__
+#define __CMD_REHASH_H__
+
+// include the common header files
+
+#include "users.h"
+#include "channels.h"
+
+/** Handle /REHASH. These command handlers can be reloaded by the core,
+ * and handle basic RFC1459 commands. Commands within modules work
+ * the same way, however, they can be fully unloaded, where these
+ * may not.
+ */
+class cmd_rehash : public command_t
+{
+ public:
+       /** Constructor for rehash.
+        */
+       cmd_rehash (InspIRCd* Instance) : command_t(Instance,"REHASH",'o',0) { syntax = "[<servermask>]"; }
+       /** Handle command.
+        * @param parameters The parameters to the comamnd
+        * @param pcnt The number of parameters passed to teh command
+        * @param user The user issuing the command
+        * @return A value from CmdResult to indicate command success or failure.
+        */
+       CmdResult Handle(const char** parameters, int pcnt, userrec *user);
+};
+
+#endif
index 115ad5b19c217d7e2ab2c3ca6e7f5112fc704e3f..76bc656f8df2c2166c8043b8b28d12651cfa1081 100644 (file)
@@ -1 +1,45 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.\r *                  E-mail:\r *               <brain@chatspike.net>\r *                <Craig@chatspike.net>\r *\r * Written by Craig Edwards, Craig McLure, and others.\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __CMD_RELOADMODULE_H__\r#define __CMD_RELOADMODULE_H__\r\r// include the common header files\r\r#include "users.h"\r#include "channels.h"\r\r/** Handle /RELOADMODULE. These command handlers can be reloaded by the core,\r * and handle basic RFC1459 commands. Commands within modules work\r * the same way, however, they can be fully unloaded, where these\r * may not.\r */\rclass cmd_reloadmodule : public command_t\r{\r public:\r  /** Constructor for reloadmodule.\r       */\r    cmd_reloadmodule (InspIRCd* Instance) : command_t(Instance,"RELOADMODULE",'o',1) { syntax = "<modulename>"; }\r  /** Handle command.\r     * @param parameters The parameters to the comamnd\r      * @param pcnt The number of parameters passed to teh command\r   * @param user The user issuing the command\r     * @return A value from CmdResult to indicate command success or failure.\r       */\r    CmdResult Handle(const char** parameters, int pcnt, userrec *user);\r};\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.
+ *                    E-mail:
+ *             <brain@chatspike.net>
+ *             <Craig@chatspike.net>
+ *
+ * Written by Craig Edwards, Craig McLure, and others.
+ * This program is free but copyrighted software; see
+ *         the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __CMD_RELOADMODULE_H__
+#define __CMD_RELOADMODULE_H__
+
+// include the common header files
+
+#include "users.h"
+#include "channels.h"
+
+/** Handle /RELOADMODULE. These command handlers can be reloaded by the core,
+ * and handle basic RFC1459 commands. Commands within modules work
+ * the same way, however, they can be fully unloaded, where these
+ * may not.
+ */
+class cmd_reloadmodule : public command_t
+{
+ public:
+       /** Constructor for reloadmodule.
+        */
+       cmd_reloadmodule (InspIRCd* Instance) : command_t(Instance,"RELOADMODULE",'o',1) { syntax = "<modulename>"; }
+       /** Handle command.
+        * @param parameters The parameters to the comamnd
+        * @param pcnt The number of parameters passed to teh command
+        * @param user The user issuing the command
+        * @return A value from CmdResult to indicate command success or failure.
+        */
+       CmdResult Handle(const char** parameters, int pcnt, userrec *user);
+};
+
+#endif
index c227304aa3e93a16c7b6e032442ed2be83bffdff..89a217a955c1648c9a0db5ec4f537bd48069101f 100644 (file)
@@ -1 +1,48 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.\r *                  E-mail:\r *               <brain@chatspike.net>\r *                <Craig@chatspike.net>\r *\r * Written by Craig Edwards, Craig McLure, and others.\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __CMD_RESTART_H__\r#define __CMD_RESTART_H__\r\r// include the common header files\r\r#include <string>\r#include <deque>\r#include <vector>\r#include "users.h"\r#include "channels.h"\r\r/** Handle /RESTART. These command handlers can be reloaded by the core,\r * and handle basic RFC1459 commands. Commands within modules work\r * the same way, however, they can be fully unloaded, where these\r * may not.\r */\rclass cmd_restart : public command_t\r{\r public:\r /** Constructor for restart.\r    */\r    cmd_restart (InspIRCd* Instance) : command_t(Instance,"RESTART",'o',1) { syntax = "<password>"; }\r      /** Handle command.\r     * @param parameters The parameters to the comamnd\r      * @param pcnt The number of parameters passed to teh command\r   * @param user The user issuing the command\r     * @return A value from CmdResult to indicate command success or failure.\r       */\r    CmdResult Handle(const char** parameters, int pcnt, userrec *user);\r};\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.
+ *                    E-mail:
+ *             <brain@chatspike.net>
+ *             <Craig@chatspike.net>
+ *
+ * Written by Craig Edwards, Craig McLure, and others.
+ * This program is free but copyrighted software; see
+ *         the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __CMD_RESTART_H__
+#define __CMD_RESTART_H__
+
+// include the common header files
+
+#include <string>
+#include <deque>
+#include <vector>
+#include "users.h"
+#include "channels.h"
+
+/** Handle /RESTART. These command handlers can be reloaded by the core,
+ * and handle basic RFC1459 commands. Commands within modules work
+ * the same way, however, they can be fully unloaded, where these
+ * may not.
+ */
+class cmd_restart : public command_t
+{
+ public:
+       /** Constructor for restart.
+        */
+       cmd_restart (InspIRCd* Instance) : command_t(Instance,"RESTART",'o',1) { syntax = "<password>"; }
+       /** Handle command.
+        * @param parameters The parameters to the comamnd
+        * @param pcnt The number of parameters passed to teh command
+        * @param user The user issuing the command
+        * @return A value from CmdResult to indicate command success or failure.
+        */
+       CmdResult Handle(const char** parameters, int pcnt, userrec *user);
+};
+
+#endif
index 2ade369cafcf819b53926b97ee3ddc074ea2ef31..ffa7ea8bda32d09f529be3eca6aeb62d6169f0e5 100644 (file)
@@ -1 +1,48 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.\r *                  E-mail:\r *               <brain@chatspike.net>\r *                <Craig@chatspike.net>\r *\r * Written by Craig Edwards, Craig McLure, and others.\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __CMD_RULES_H__\r#define __CMD_RULES_H__\r\r// include the common header files\r\r#include <string>\r#include <vector>\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r\r/** Handle /RULES. These command handlers can be reloaded by the core,\r * and handle basic RFC1459 commands. Commands within modules work\r * the same way, however, they can be fully unloaded, where these\r * may not.\r */\rclass cmd_rules : public command_t\r{\r public:\r    /** Constructor for rules.\r      */\r    cmd_rules (InspIRCd* Instance) : command_t(Instance,"RULES",0,0) { syntax = "[<servername>]"; }\r        /** Handle command.\r     * @param parameters The parameters to the comamnd\r      * @param pcnt The number of parameters passed to teh command\r   * @param user The user issuing the command\r     * @return A value from CmdResult to indicate command success or failure.\r       */\r    CmdResult Handle(const char** parameters, int pcnt, userrec *user);\r};\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.
+ *                    E-mail:
+ *             <brain@chatspike.net>
+ *             <Craig@chatspike.net>
+ *
+ * Written by Craig Edwards, Craig McLure, and others.
+ * This program is free but copyrighted software; see
+ *         the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __CMD_RULES_H__
+#define __CMD_RULES_H__
+
+// include the common header files
+
+#include <string>
+#include <vector>
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+
+/** Handle /RULES. These command handlers can be reloaded by the core,
+ * and handle basic RFC1459 commands. Commands within modules work
+ * the same way, however, they can be fully unloaded, where these
+ * may not.
+ */
+class cmd_rules : public command_t
+{
+ public:
+       /** Constructor for rules.
+        */
+       cmd_rules (InspIRCd* Instance) : command_t(Instance,"RULES",0,0) { syntax = "[<servername>]"; }
+       /** Handle command.
+        * @param parameters The parameters to the comamnd
+        * @param pcnt The number of parameters passed to teh command
+        * @param user The user issuing the command
+        * @return A value from CmdResult to indicate command success or failure.
+        */
+       CmdResult Handle(const char** parameters, int pcnt, userrec *user);
+};
+
+#endif
index 92867ba6cc2a3606dcf77a38d914a080c7336651..3c88c0ac69eb4e9813d6cde564d347a1c4fbc4dc 100644 (file)
@@ -1 +1,45 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.\r *                  E-mail:\r *               <brain@chatspike.net>\r *                <Craig@chatspike.net>\r *\r * Written by Craig Edwards, Craig McLure, and others.\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __CMD_SERVER_H__\r#define __CMD_SERVER_H__\r\r// include the common header files\r\r#include "users.h"\r#include "channels.h"\r\r/** Handle /SERVER. These command handlers can be reloaded by the core,\r * and handle basic RFC1459 commands. Commands within modules work\r * the same way, however, they can be fully unloaded, where these\r * may not.\r */\rclass cmd_server : public command_t\r{\r public:\r  /** Constructor for server.\r     */\r    cmd_server (InspIRCd* Instance) : command_t(Instance,"SERVER",0,0) { }\r /** Handle command.\r     * @param parameters The parameters to the comamnd\r      * @param pcnt The number of parameters passed to teh command\r   * @param user The user issuing the command\r     * @return A value from CmdResult to indicate command success or failure.\r       */\r    CmdResult Handle(const char** parameters, int pcnt, userrec *user);\r};\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.
+ *                    E-mail:
+ *             <brain@chatspike.net>
+ *             <Craig@chatspike.net>
+ *
+ * Written by Craig Edwards, Craig McLure, and others.
+ * This program is free but copyrighted software; see
+ *         the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __CMD_SERVER_H__
+#define __CMD_SERVER_H__
+
+// include the common header files
+
+#include "users.h"
+#include "channels.h"
+
+/** Handle /SERVER. These command handlers can be reloaded by the core,
+ * and handle basic RFC1459 commands. Commands within modules work
+ * the same way, however, they can be fully unloaded, where these
+ * may not.
+ */
+class cmd_server : public command_t
+{
+ public:
+       /** Constructor for server.
+        */
+       cmd_server (InspIRCd* Instance) : command_t(Instance,"SERVER",0,0) { }
+       /** Handle command.
+        * @param parameters The parameters to the comamnd
+        * @param pcnt The number of parameters passed to teh command
+        * @param user The user issuing the command
+        * @return A value from CmdResult to indicate command success or failure.
+        */
+       CmdResult Handle(const char** parameters, int pcnt, userrec *user);
+};
+
+#endif
index e5e20bbcafda806ad37b3c89cca7da8bb56f2432..43cb115f72ec3815164345c8809b30f219b5f789 100644 (file)
@@ -1 +1,48 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.\r *                  E-mail:\r *               <brain@chatspike.net>\r *                <Craig@chatspike.net>\r *\r * Written by Craig Edwards, Craig McLure, and others.\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __CMD_SQUIT_H__\r#define __CMD_SQUIT_H__\r\r// include the common header files\r\r#include <string>\r#include <vector>\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r\r/** Handle /SQUIT. These command handlers can be reloaded by the core,\r * and handle basic RFC1459 commands. Commands within modules work\r * the same way, however, they can be fully unloaded, where these\r * may not.\r */\rclass cmd_squit : public command_t\r{\r public:\r    /** Constructor for squit.\r      */\r    cmd_squit (InspIRCd* Instance) : command_t(Instance,"SQUIT",'o',1) { syntax = "<servername> [<reason>]"; }\r     /** Handle command.\r     * @param parameters The parameters to the comamnd\r      * @param pcnt The number of parameters passed to teh command\r   * @param user The user issuing the command\r     * @return A value from CmdResult to indicate command success or failure.\r       */\r    CmdResult Handle(const char** parameters, int pcnt, userrec *user);\r};\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.
+ *                    E-mail:
+ *             <brain@chatspike.net>
+ *             <Craig@chatspike.net>
+ *
+ * Written by Craig Edwards, Craig McLure, and others.
+ * This program is free but copyrighted software; see
+ *         the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __CMD_SQUIT_H__
+#define __CMD_SQUIT_H__
+
+// include the common header files
+
+#include <string>
+#include <vector>
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+
+/** Handle /SQUIT. These command handlers can be reloaded by the core,
+ * and handle basic RFC1459 commands. Commands within modules work
+ * the same way, however, they can be fully unloaded, where these
+ * may not.
+ */
+class cmd_squit : public command_t
+{
+ public:
+       /** Constructor for squit.
+        */
+       cmd_squit (InspIRCd* Instance) : command_t(Instance,"SQUIT",'o',1) { syntax = "<servername> [<reason>]"; }
+       /** Handle command.
+        * @param parameters The parameters to the comamnd
+        * @param pcnt The number of parameters passed to teh command
+        * @param user The user issuing the command
+        * @return A value from CmdResult to indicate command success or failure.
+        */
+       CmdResult Handle(const char** parameters, int pcnt, userrec *user);
+};
+
+#endif
index e2aabef2f91705a5f7e597987e5a20047b1e8f68..b4c0c3784759ba9c5a38e104be2ff88099afdfa2 100644 (file)
@@ -1 +1,48 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.\r *                  E-mail:\r *               <brain@chatspike.net>\r *                <Craig@chatspike.net>\r *\r * Written by Craig Edwards, Craig McLure, and others.\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __CMD_STATS_H__\r#define __CMD_STATS_H__\r\r// include the common header files\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r\rDllExport void DoStats(InspIRCd* Instance, char statschar, userrec* user, string_list &results);\r\r/** Handle /STATS. These command handlers can be reloaded by the core,\r * and handle basic RFC1459 commands. Commands within modules work\r * the same way, however, they can be fully unloaded, where these\r * may not.\r */\rclass cmd_stats : public command_t\r{\r public:\r      /** Constructor for stats.\r      */\r    cmd_stats (InspIRCd* Instance) : command_t(Instance,"STATS",0,1) { syntax = "<stats-symbol> [<servername>]"; }\r /** Handle command.\r     * @param parameters The parameters to the comamnd\r      * @param pcnt The number of parameters passed to teh command\r   * @param user The user issuing the command\r     * @return A value from CmdResult to indicate command success or failure.\r       */\r    CmdResult Handle(const char** parameters, int pcnt, userrec *user);\r};\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.
+ *                    E-mail:
+ *             <brain@chatspike.net>
+ *             <Craig@chatspike.net>
+ *
+ * Written by Craig Edwards, Craig McLure, and others.
+ * This program is free but copyrighted software; see
+ *         the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __CMD_STATS_H__
+#define __CMD_STATS_H__
+
+// include the common header files
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+
+DllExport void DoStats(InspIRCd* Instance, char statschar, userrec* user, string_list &results);
+
+/** Handle /STATS. These command handlers can be reloaded by the core,
+ * and handle basic RFC1459 commands. Commands within modules work
+ * the same way, however, they can be fully unloaded, where these
+ * may not.
+ */
+class cmd_stats : public command_t
+{
+ public:
+       /** Constructor for stats.
+        */
+       cmd_stats (InspIRCd* Instance) : command_t(Instance,"STATS",0,1) { syntax = "<stats-symbol> [<servername>]"; }
+       /** Handle command.
+        * @param parameters The parameters to the comamnd
+        * @param pcnt The number of parameters passed to teh command
+        * @param user The user issuing the command
+        * @return A value from CmdResult to indicate command success or failure.
+        */
+       CmdResult Handle(const char** parameters, int pcnt, userrec *user);
+};
+
+#endif
index 18e0871ab41004f4493b4a79e79ba300dafa6531..717863f357175252c1a105652cebd06199898bad 100644 (file)
@@ -1 +1,48 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.\r *                  E-mail:\r *               <brain@chatspike.net>\r *                <Craig@chatspike.net>\r *\r * Written by Craig Edwards, Craig McLure, and others.\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __CMD_SUMMON_H__\r#define __CMD_SUMMON_H__\r\r// include the common header files\r\r#include <string>\r#include <vector>\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r\r/** Handle /SUMMON stub. These command handlers can be reloaded by the core,\r * and handle basic RFC1459 commands. Commands within modules work\r * the same way, however, they can be fully unloaded, where these\r * may not.\r */\rclass cmd_summon : public command_t\r{\r public:\r   /** Constructor for summon.\r     */\r    cmd_summon (InspIRCd* Instance) : command_t(Instance,"SUMMON",0,0) { }\r /** Handle command.\r     * @param parameters The parameters to the comamnd\r      * @param pcnt The number of parameters passed to teh command\r   * @param user The user issuing the command\r     * @return A value from CmdResult to indicate command success or failure.\r       */\r    CmdResult Handle(const char** parameters, int pcnt, userrec *user);\r};\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.
+ *                    E-mail:
+ *             <brain@chatspike.net>
+ *             <Craig@chatspike.net>
+ *
+ * Written by Craig Edwards, Craig McLure, and others.
+ * This program is free but copyrighted software; see
+ *         the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __CMD_SUMMON_H__
+#define __CMD_SUMMON_H__
+
+// include the common header files
+
+#include <string>
+#include <vector>
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+
+/** Handle /SUMMON stub. These command handlers can be reloaded by the core,
+ * and handle basic RFC1459 commands. Commands within modules work
+ * the same way, however, they can be fully unloaded, where these
+ * may not.
+ */
+class cmd_summon : public command_t
+{
+ public:
+       /** Constructor for summon.
+        */
+       cmd_summon (InspIRCd* Instance) : command_t(Instance,"SUMMON",0,0) { }
+       /** Handle command.
+        * @param parameters The parameters to the comamnd
+        * @param pcnt The number of parameters passed to teh command
+        * @param user The user issuing the command
+        * @return A value from CmdResult to indicate command success or failure.
+        */
+       CmdResult Handle(const char** parameters, int pcnt, userrec *user);
+};
+
+#endif
index 395281a50f9f48a0039754228c419b5e5c6c0157..0a2dc2f950dad34403202b37f43279bc2b177ac2 100644 (file)
@@ -1 +1,45 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.\r *                  E-mail:\r *               <brain@chatspike.net>\r *                <Craig@chatspike.net>\r *\r * Written by Craig Edwards, Craig McLure, and others.\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __CMD_TIME_H__\r#define __CMD_TIME_H__\r\r// include the common header files\r\r#include "users.h"\r#include "channels.h"\r\r/** Handle /TIME. These command handlers can be reloaded by the core,\r * and handle basic RFC1459 commands. Commands within modules work\r * the same way, however, they can be fully unloaded, where these\r * may not.\r */\rclass cmd_time : public command_t\r{\r public:\r  /** Constructor for time.\r       */\r    cmd_time (InspIRCd* Instance) : command_t(Instance,"TIME",0,0) { syntax = "[<servername>]"; }\r  /** Handle command.\r     * @param parameters The parameters to the comamnd\r      * @param pcnt The number of parameters passed to teh command\r   * @param user The user issuing the command\r     * @return A value from CmdResult to indicate command success or failure.\r       */\r    CmdResult Handle(const char** parameters, int pcnt, userrec *user);\r};\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.
+ *                    E-mail:
+ *             <brain@chatspike.net>
+ *             <Craig@chatspike.net>
+ *
+ * Written by Craig Edwards, Craig McLure, and others.
+ * This program is free but copyrighted software; see
+ *         the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __CMD_TIME_H__
+#define __CMD_TIME_H__
+
+// include the common header files
+
+#include "users.h"
+#include "channels.h"
+
+/** Handle /TIME. These command handlers can be reloaded by the core,
+ * and handle basic RFC1459 commands. Commands within modules work
+ * the same way, however, they can be fully unloaded, where these
+ * may not.
+ */
+class cmd_time : public command_t
+{
+ public:
+       /** Constructor for time.
+        */
+       cmd_time (InspIRCd* Instance) : command_t(Instance,"TIME",0,0) { syntax = "[<servername>]"; }
+       /** Handle command.
+        * @param parameters The parameters to the comamnd
+        * @param pcnt The number of parameters passed to teh command
+        * @param user The user issuing the command
+        * @return A value from CmdResult to indicate command success or failure.
+        */
+       CmdResult Handle(const char** parameters, int pcnt, userrec *user);
+};
+
+#endif
index 05ecd75993225ec85aed76624aa4f398569faff8..c3ac113efbc5c36aec76b0f765ec1d37d55fcb29 100644 (file)
@@ -1 +1,45 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.\r *                  E-mail:\r *               <brain@chatspike.net>\r *                <Craig@chatspike.net>\r *\r * Written by Craig Edwards, Craig McLure, and others.\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __CMD_TOPIC_H__\r#define __CMD_TOPIC_H__\r\r// include the common header files\r\r#include "users.h"\r#include "channels.h"\r\r/** Handle /TOPIC. These command handlers can be reloaded by the core,\r * and handle basic RFC1459 commands. Commands within modules work\r * the same way, however, they can be fully unloaded, where these\r * may not.\r */\rclass cmd_topic : public command_t\r{\r public:\r      /** Constructor for topic.\r      */\r    cmd_topic (InspIRCd* Instance) : command_t(Instance,"TOPIC",0,1) { syntax = "<channel> [<topic>]"; }\r   /** Handle command.\r     * @param parameters The parameters to the comamnd\r      * @param pcnt The number of parameters passed to teh command\r   * @param user The user issuing the command\r     * @return A value from CmdResult to indicate command success or failure.\r       */\r    CmdResult Handle(const char** parameters, int pcnt, userrec *user);\r};\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.
+ *                    E-mail:
+ *             <brain@chatspike.net>
+ *             <Craig@chatspike.net>
+ *
+ * Written by Craig Edwards, Craig McLure, and others.
+ * This program is free but copyrighted software; see
+ *         the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __CMD_TOPIC_H__
+#define __CMD_TOPIC_H__
+
+// include the common header files
+
+#include "users.h"
+#include "channels.h"
+
+/** Handle /TOPIC. These command handlers can be reloaded by the core,
+ * and handle basic RFC1459 commands. Commands within modules work
+ * the same way, however, they can be fully unloaded, where these
+ * may not.
+ */
+class cmd_topic : public command_t
+{
+ public:
+       /** Constructor for topic.
+        */
+       cmd_topic (InspIRCd* Instance) : command_t(Instance,"TOPIC",0,1) { syntax = "<channel> [<topic>]"; }
+       /** Handle command.
+        * @param parameters The parameters to the comamnd
+        * @param pcnt The number of parameters passed to teh command
+        * @param user The user issuing the command
+        * @return A value from CmdResult to indicate command success or failure.
+        */
+       CmdResult Handle(const char** parameters, int pcnt, userrec *user);
+};
+
+#endif
index f9f8f2bb8042b7713a2f84496e2325d9a78a89d2..2c681363df017ae7dfc66c7be6d37a098fc7e290 100644 (file)
@@ -1 +1,45 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.\r *                  E-mail:\r *               <brain@chatspike.net>\r *                <Craig@chatspike.net>\r *\r * Written by Craig Edwards, Craig McLure, and others.\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __CMD_TRACE_H__\r#define __CMD_TRACE_H__\r\r// include the common header files\r\r#include "users.h"\r#include "channels.h"\r\r/** Handle /TRACE. These command handlers can be reloaded by the core,\r * and handle basic RFC1459 commands. Commands within modules work\r * the same way, however, they can be fully unloaded, where these\r * may not.\r */\rclass cmd_trace : public command_t\r{\r public:\r      /** Constructor for trace.\r      */\r    cmd_trace (InspIRCd* Instance) : command_t(Instance,"TRACE",'o',0) { syntax = "[<object>]"; }\r  /** Handle command.\r     * @param parameters The parameters to the comamnd\r      * @param pcnt The number of parameters passed to teh command\r   * @param user The user issuing the command\r     * @return A value from CmdResult to indicate command success or failure.\r       */\r    CmdResult Handle(const char** parameters, int pcnt, userrec *user);\r};\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.
+ *                    E-mail:
+ *             <brain@chatspike.net>
+ *             <Craig@chatspike.net>
+ *
+ * Written by Craig Edwards, Craig McLure, and others.
+ * This program is free but copyrighted software; see
+ *         the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __CMD_TRACE_H__
+#define __CMD_TRACE_H__
+
+// include the common header files
+
+#include "users.h"
+#include "channels.h"
+
+/** Handle /TRACE. These command handlers can be reloaded by the core,
+ * and handle basic RFC1459 commands. Commands within modules work
+ * the same way, however, they can be fully unloaded, where these
+ * may not.
+ */
+class cmd_trace : public command_t
+{
+ public:
+       /** Constructor for trace.
+        */
+       cmd_trace (InspIRCd* Instance) : command_t(Instance,"TRACE",'o',0) { syntax = "[<object>]"; }
+       /** Handle command.
+        * @param parameters The parameters to the comamnd
+        * @param pcnt The number of parameters passed to teh command
+        * @param user The user issuing the command
+        * @return A value from CmdResult to indicate command success or failure.
+        */
+       CmdResult Handle(const char** parameters, int pcnt, userrec *user);
+};
+
+#endif
index b8e87e7137bc7a88549d93a1384fe5634e73622f..2f435576f55fd728c2d4ab91274988582d584b1b 100644 (file)
@@ -1 +1,45 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.\r *                  E-mail:\r *               <brain@chatspike.net>\r *                <Craig@chatspike.net>\r *\r * Written by Craig Edwards, Craig McLure, and others.\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __CMD_UNLOADMODULE_H__\r#define __CMD_UNLOADMODULE_H__\r\r// include the common header files\r\r#include "users.h"\r#include "channels.h"\r\r/** Handle /UNLOADMODULE. These command handlers can be reloaded by the core,\r * and handle basic RFC1459 commands. Commands within modules work\r * the same way, however, they can be fully unloaded, where these\r * may not.\r */\rclass cmd_unloadmodule : public command_t\r{\r public:\r  /** Constructor for unloadmodule.\r       */\r    cmd_unloadmodule (InspIRCd* Instance) : command_t(Instance,"UNLOADMODULE",'o',1) { syntax = "<modulename>"; }\r  /** Handle command.\r     * @param parameters The parameters to the comamnd\r      * @param pcnt The number of parameters passed to teh command\r   * @param user The user issuing the command\r     * @return A value from CmdResult to indicate command success or failure.\r       */\r    CmdResult Handle(const char** parameters, int pcnt, userrec *user);\r};\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.
+ *                    E-mail:
+ *             <brain@chatspike.net>
+ *             <Craig@chatspike.net>
+ *
+ * Written by Craig Edwards, Craig McLure, and others.
+ * This program is free but copyrighted software; see
+ *         the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __CMD_UNLOADMODULE_H__
+#define __CMD_UNLOADMODULE_H__
+
+// include the common header files
+
+#include "users.h"
+#include "channels.h"
+
+/** Handle /UNLOADMODULE. These command handlers can be reloaded by the core,
+ * and handle basic RFC1459 commands. Commands within modules work
+ * the same way, however, they can be fully unloaded, where these
+ * may not.
+ */
+class cmd_unloadmodule : public command_t
+{
+ public:
+       /** Constructor for unloadmodule.
+        */
+       cmd_unloadmodule (InspIRCd* Instance) : command_t(Instance,"UNLOADMODULE",'o',1) { syntax = "<modulename>"; }
+       /** Handle command.
+        * @param parameters The parameters to the comamnd
+        * @param pcnt The number of parameters passed to teh command
+        * @param user The user issuing the command
+        * @return A value from CmdResult to indicate command success or failure.
+        */
+       CmdResult Handle(const char** parameters, int pcnt, userrec *user);
+};
+
+#endif
index d31484f060ef545d7b1035a42963a311b6c9d1d3..eb835e2903a0b61b0b74cd38d3e3b5b8b8fa6f97 100644 (file)
@@ -1 +1,45 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.\r *                  E-mail:\r *               <brain@chatspike.net>\r *                <Craig@chatspike.net>\r *\r * Written by Craig Edwards, Craig McLure, and others.\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __CMD_USER_H__\r#define __CMD_USER_H__\r\r// include the common header files\r\r#include "users.h"\r#include "channels.h"\r\r/** Handle /USER. These command handlers can be reloaded by the core,\r * and handle basic RFC1459 commands. Commands within modules work\r * the same way, however, they can be fully unloaded, where these\r * may not.\r */\rclass cmd_user : public command_t\r{\r public:\r  /** Constructor for user.\r       */\r    cmd_user (InspIRCd* Instance) : command_t(Instance,"USER",0,4,true) { syntax = "<username> <localhost> <remotehost> <GECOS>"; }\r        /** Handle command.\r     * @param parameters The parameters to the comamnd\r      * @param pcnt The number of parameters passed to teh command\r   * @param user The user issuing the command\r     * @return A value from CmdResult to indicate command success or failure.\r       */\r    CmdResult Handle(const char** parameters, int pcnt, userrec *user);\r};\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.
+ *                    E-mail:
+ *             <brain@chatspike.net>
+ *             <Craig@chatspike.net>
+ *
+ * Written by Craig Edwards, Craig McLure, and others.
+ * This program is free but copyrighted software; see
+ *         the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __CMD_USER_H__
+#define __CMD_USER_H__
+
+// include the common header files
+
+#include "users.h"
+#include "channels.h"
+
+/** Handle /USER. These command handlers can be reloaded by the core,
+ * and handle basic RFC1459 commands. Commands within modules work
+ * the same way, however, they can be fully unloaded, where these
+ * may not.
+ */
+class cmd_user : public command_t
+{
+ public:
+       /** Constructor for user.
+        */
+       cmd_user (InspIRCd* Instance) : command_t(Instance,"USER",0,4,true) { syntax = "<username> <localhost> <remotehost> <GECOS>"; }
+       /** Handle command.
+        * @param parameters The parameters to the comamnd
+        * @param pcnt The number of parameters passed to teh command
+        * @param user The user issuing the command
+        * @return A value from CmdResult to indicate command success or failure.
+        */
+       CmdResult Handle(const char** parameters, int pcnt, userrec *user);
+};
+
+#endif
index 3740257452aacdcf97c74c0d57ffc117cb959b8b..0a72bcda220fb211d369d89312616257799829b0 100644 (file)
@@ -1 +1,45 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.\r *                  E-mail:\r *               <brain@chatspike.net>\r *                <Craig@chatspike.net>\r *\r * Written by Craig Edwards, Craig McLure, and others.\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __CMD_USERHOST_H__\r#define __CMD_USERHOST_H__\r\r// include the common header files\r\r#include "users.h"\r#include "channels.h"\r\r/** Handle /USERHOST. These command handlers can be reloaded by the core,\r * and handle basic RFC1459 commands. Commands within modules work\r * the same way, however, they can be fully unloaded, where these\r * may not.\r */\rclass cmd_userhost : public command_t\r{\r public:\r  /** Constructor for userhost.\r   */\r    cmd_userhost (InspIRCd* Instance) : command_t(Instance,"USERHOST",0,1) { syntax = "<nick>{,<nick>}"; }\r /** Handle command.\r     * @param parameters The parameters to the comamnd\r      * @param pcnt The number of parameters passed to teh command\r   * @param user The user issuing the command\r     * @return A value from CmdResult to indicate command success or failure.\r       */\r    CmdResult Handle(const char** parameters, int pcnt, userrec *user);\r};\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.
+ *                    E-mail:
+ *             <brain@chatspike.net>
+ *             <Craig@chatspike.net>
+ *
+ * Written by Craig Edwards, Craig McLure, and others.
+ * This program is free but copyrighted software; see
+ *         the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __CMD_USERHOST_H__
+#define __CMD_USERHOST_H__
+
+// include the common header files
+
+#include "users.h"
+#include "channels.h"
+
+/** Handle /USERHOST. These command handlers can be reloaded by the core,
+ * and handle basic RFC1459 commands. Commands within modules work
+ * the same way, however, they can be fully unloaded, where these
+ * may not.
+ */
+class cmd_userhost : public command_t
+{
+ public:
+       /** Constructor for userhost.
+        */
+       cmd_userhost (InspIRCd* Instance) : command_t(Instance,"USERHOST",0,1) { syntax = "<nick>{,<nick>}"; }
+       /** Handle command.
+        * @param parameters The parameters to the comamnd
+        * @param pcnt The number of parameters passed to teh command
+        * @param user The user issuing the command
+        * @return A value from CmdResult to indicate command success or failure.
+        */
+       CmdResult Handle(const char** parameters, int pcnt, userrec *user);
+};
+
+#endif
index 9374c1de21e78bc009b3f163a3003a4c1443a277..60341871dec309458569bbb9bf33f5ce951191ef 100644 (file)
@@ -1 +1,48 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.\r *                  E-mail:\r *               <brain@chatspike.net>\r *                <Craig@chatspike.net>\r *\r * Written by Craig Edwards, Craig McLure, and others.\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __CMD_USERS_H__\r#define __CMD_USERS_H__\r\r// include the common header files\r// \r#include <string>\r#include <vector>\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r\r/** Handle /USERS stub. These command handlers can be reloaded by the core,\r * and handle basic RFC1459 commands. Commands within modules work\r * the same way, however, they can be fully unloaded, where these\r * may not.\r */\rclass cmd_users : public command_t\r{\r public:\r    /** Constructor for users.\r      */\r    cmd_users (InspIRCd* Instance) : command_t(Instance,"USERS",0,0) { }\r   /** Handle command.\r     * @param parameters The parameters to the comamnd\r      * @param pcnt The number of parameters passed to teh command\r   * @param user The user issuing the command\r     * @return A value from CmdResult to indicate command success or failure.\r       */\r    CmdResult Handle(const char** parameters, int pcnt, userrec *user);\r};\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.
+ *                    E-mail:
+ *             <brain@chatspike.net>
+ *             <Craig@chatspike.net>
+ *
+ * Written by Craig Edwards, Craig McLure, and others.
+ * This program is free but copyrighted software; see
+ *         the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __CMD_USERS_H__
+#define __CMD_USERS_H__
+
+// include the common header files
+// 
+#include <string>
+#include <vector>
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+
+/** Handle /USERS stub. These command handlers can be reloaded by the core,
+ * and handle basic RFC1459 commands. Commands within modules work
+ * the same way, however, they can be fully unloaded, where these
+ * may not.
+ */
+class cmd_users : public command_t
+{
+ public:
+       /** Constructor for users.
+        */
+       cmd_users (InspIRCd* Instance) : command_t(Instance,"USERS",0,0) { }
+       /** Handle command.
+        * @param parameters The parameters to the comamnd
+        * @param pcnt The number of parameters passed to teh command
+        * @param user The user issuing the command
+        * @return A value from CmdResult to indicate command success or failure.
+        */
+       CmdResult Handle(const char** parameters, int pcnt, userrec *user);
+};
+
+#endif
index 9ded1641a85d1b6b74c58480f9d65282b0df49be..824a9ef7e363af8d8abc645f2f323cd6877eb31a 100644 (file)
@@ -1 +1,45 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.\r *                  E-mail:\r *               <brain@chatspike.net>\r *                <Craig@chatspike.net>\r *\r * Written by Craig Edwards, Craig McLure, and others.\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __CMD_VERSION_H__\r#define __CMD_VERSION_H__\r\r// include the common header files\r\r#include "users.h"\r#include "channels.h"\r\r/** Handle /VERSION. These command handlers can be reloaded by the core,\r * and handle basic RFC1459 commands. Commands within modules work\r * the same way, however, they can be fully unloaded, where these\r * may not.\r */\rclass cmd_version : public command_t\r{\r public:\r      /** Constructor for version.\r    */\r    cmd_version (InspIRCd* Instance) : command_t(Instance,"VERSION",0,0) { syntax = "[<servername>]"; }\r    /** Handle command.\r     * @param parameters The parameters to the comamnd\r      * @param pcnt The number of parameters passed to teh command\r   * @param user The user issuing the command\r     * @return A value from CmdResult to indicate command success or failure.\r       */\r    CmdResult Handle(const char** parameters, int pcnt, userrec *user);\r};\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.
+ *                    E-mail:
+ *             <brain@chatspike.net>
+ *             <Craig@chatspike.net>
+ *
+ * Written by Craig Edwards, Craig McLure, and others.
+ * This program is free but copyrighted software; see
+ *         the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __CMD_VERSION_H__
+#define __CMD_VERSION_H__
+
+// include the common header files
+
+#include "users.h"
+#include "channels.h"
+
+/** Handle /VERSION. These command handlers can be reloaded by the core,
+ * and handle basic RFC1459 commands. Commands within modules work
+ * the same way, however, they can be fully unloaded, where these
+ * may not.
+ */
+class cmd_version : public command_t
+{
+ public:
+       /** Constructor for version.
+        */
+       cmd_version (InspIRCd* Instance) : command_t(Instance,"VERSION",0,0) { syntax = "[<servername>]"; }
+       /** Handle command.
+        * @param parameters The parameters to the comamnd
+        * @param pcnt The number of parameters passed to teh command
+        * @param user The user issuing the command
+        * @return A value from CmdResult to indicate command success or failure.
+        */
+       CmdResult Handle(const char** parameters, int pcnt, userrec *user);
+};
+
+#endif
index 514f6a5de167563dcdba571c6b345f377ccf30a7..548ba53ded31398b51cb2a2edc90a46aa59dd200 100644 (file)
@@ -1 +1,45 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.\r *                  E-mail:\r *               <brain@chatspike.net>\r *                <Craig@chatspike.net>\r *\r * Written by Craig Edwards, Craig McLure, and others.\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __CMD_WALLOPS_H__\r#define __CMD_WALLOPS_H__\r\r// include the common header files\r\r#include "users.h"\r#include "channels.h"\r\r/** Handle /WALLOPS. These command handlers can be reloaded by the core,\r * and handle basic RFC1459 commands. Commands within modules work\r * the same way, however, they can be fully unloaded, where these\r * may not.\r */\rclass cmd_wallops : public command_t\r{\r public:\r      /** Constructor for wallops.\r    */\r    cmd_wallops (InspIRCd* Instance) : command_t(Instance,"WALLOPS",'o',1) { syntax = "<any-text>"; }\r      /** Handle command.\r     * @param parameters The parameters to the comamnd\r      * @param pcnt The number of parameters passed to teh command\r   * @param user The user issuing the command\r     * @return A value from CmdResult to indicate command success or failure.\r       */\r    CmdResult Handle(const char** parameters, int pcnt, userrec *user);\r};\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.
+ *                    E-mail:
+ *             <brain@chatspike.net>
+ *             <Craig@chatspike.net>
+ *
+ * Written by Craig Edwards, Craig McLure, and others.
+ * This program is free but copyrighted software; see
+ *         the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __CMD_WALLOPS_H__
+#define __CMD_WALLOPS_H__
+
+// include the common header files
+
+#include "users.h"
+#include "channels.h"
+
+/** Handle /WALLOPS. These command handlers can be reloaded by the core,
+ * and handle basic RFC1459 commands. Commands within modules work
+ * the same way, however, they can be fully unloaded, where these
+ * may not.
+ */
+class cmd_wallops : public command_t
+{
+ public:
+       /** Constructor for wallops.
+        */
+       cmd_wallops (InspIRCd* Instance) : command_t(Instance,"WALLOPS",'o',1) { syntax = "<any-text>"; }
+       /** Handle command.
+        * @param parameters The parameters to the comamnd
+        * @param pcnt The number of parameters passed to teh command
+        * @param user The user issuing the command
+        * @return A value from CmdResult to indicate command success or failure.
+        */
+       CmdResult Handle(const char** parameters, int pcnt, userrec *user);
+};
+
+#endif
index e84de3d35f948632ba1293f15e713535086f9c47..6ccfa3b5d9f03cd66083eb3ad5ccb963511f2938 100644 (file)
@@ -1 +1,59 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.\r *                  E-mail:\r *               <brain@chatspike.net>\r *                <Craig@chatspike.net>\r *\r * Written by Craig Edwards, Craig McLure, and others.\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __CMD_WHO_H__\r#define __CMD_WHO_H__\r\r// include the common header files\r\r#include "users.h"\r#include "channels.h"\r\r/** Handle /WHO. These command handlers can be reloaded by the core,\r * and handle basic RFC1459 commands. Commands within modules work\r * the same way, however, they can be fully unloaded, where these\r * may not.\r */\rclass cmd_who : public command_t\r{\r       bool CanView(chanrec* chan, userrec* user);\r    bool opt_viewopersonly;\r        bool opt_showrealhost;\r bool opt_unlimit;\r      bool opt_realname;\r     bool opt_mode;\r bool opt_ident;\r        bool opt_metadata;\r     bool opt_port;\r bool opt_away;\r bool opt_local;\r        bool opt_far;\r public:\r /** Constructor for who.\r        */\r    cmd_who (InspIRCd* Instance) : command_t(Instance,"WHO",0,1) { syntax = "<server>|<nickname>|<channel>|<realname>|<host>|0 [ohurmMiaplf]"; }\r   void SendWhoLine(userrec* user, const std::string &initial, chanrec* ch, userrec* u, std::vector<std::string> &whoresults);\r    /** Handle command.\r     * @param parameters The parameters to the comamnd\r      * @param pcnt The number of parameters passed to teh command\r   * @param user The user issuing the command\r     * @return A value from CmdResult to indicate command success or failure.\r       */\r    CmdResult Handle(const char** parameters, int pcnt, userrec *user);\r    bool whomatch(userrec* user, const char* matchtext);\r};\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.
+ *                    E-mail:
+ *             <brain@chatspike.net>
+ *             <Craig@chatspike.net>
+ *
+ * Written by Craig Edwards, Craig McLure, and others.
+ * This program is free but copyrighted software; see
+ *         the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __CMD_WHO_H__
+#define __CMD_WHO_H__
+
+// include the common header files
+
+#include "users.h"
+#include "channels.h"
+
+/** Handle /WHO. These command handlers can be reloaded by the core,
+ * and handle basic RFC1459 commands. Commands within modules work
+ * the same way, however, they can be fully unloaded, where these
+ * may not.
+ */
+class cmd_who : public command_t
+{
+       bool CanView(chanrec* chan, userrec* user);
+       bool opt_viewopersonly;
+       bool opt_showrealhost;
+       bool opt_unlimit;
+       bool opt_realname;
+       bool opt_mode;
+       bool opt_ident;
+       bool opt_metadata;
+       bool opt_port;
+       bool opt_away;
+       bool opt_local;
+       bool opt_far;
+ public:
+       /** Constructor for who.
+        */
+       cmd_who (InspIRCd* Instance) : command_t(Instance,"WHO",0,1) { syntax = "<server>|<nickname>|<channel>|<realname>|<host>|0 [ohurmMiaplf]"; }
+       void SendWhoLine(userrec* user, const std::string &initial, chanrec* ch, userrec* u, std::vector<std::string> &whoresults);
+       /** Handle command.
+        * @param parameters The parameters to the comamnd
+        * @param pcnt The number of parameters passed to teh command
+        * @param user The user issuing the command
+        * @return A value from CmdResult to indicate command success or failure.
+        */
+       CmdResult Handle(const char** parameters, int pcnt, userrec *user);
+       bool whomatch(userrec* user, const char* matchtext);
+};
+
+#endif
index 5e0c0d4d3d9a5dd21f584aaac2d29237fc3c16e8..d3086788a47fcc99c5a9d251e0848d58699d4d85 100644 (file)
@@ -1 +1,48 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.\r *                  E-mail:\r *               <brain@chatspike.net>\r *                <Craig@chatspike.net>\r *\r * Written by Craig Edwards, Craig McLure, and others.\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __CMD_WHOIS_H__\r#define __CMD_WHOIS_H__\r\r// include the common header files\r\r#include "users.h"\r#include "channels.h"\r\rconst char* Spacify(char* n);\rDllExport void do_whois(InspIRCd* Instance, userrec* user, userrec* dest,unsigned long signon, unsigned long idle, const char* nick);\r\r/** Handle /WHOIS. These command handlers can be reloaded by the core,\r * and handle basic RFC1459 commands. Commands within modules work\r * the same way, however, they can be fully unloaded, where these\r * may not.\r */\rclass cmd_whois : public command_t\r{\r public:\r /** Constructor for whois.\r      */\r    cmd_whois (InspIRCd* Instance) : command_t(Instance,"WHOIS",0,1) { syntax = "<nick>{,<nick>}"; }\r       /** Handle command.\r     * @param parameters The parameters to the comamnd\r      * @param pcnt The number of parameters passed to teh command\r   * @param user The user issuing the command\r     * @return A value from CmdResult to indicate command success or failure.\r       */\r    CmdResult Handle(const char** parameters, int pcnt, userrec *user);\r};\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.
+ *                    E-mail:
+ *             <brain@chatspike.net>
+ *             <Craig@chatspike.net>
+ *
+ * Written by Craig Edwards, Craig McLure, and others.
+ * This program is free but copyrighted software; see
+ *         the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __CMD_WHOIS_H__
+#define __CMD_WHOIS_H__
+
+// include the common header files
+
+#include "users.h"
+#include "channels.h"
+
+const char* Spacify(char* n);
+DllExport void do_whois(InspIRCd* Instance, userrec* user, userrec* dest,unsigned long signon, unsigned long idle, const char* nick);
+
+/** Handle /WHOIS. These command handlers can be reloaded by the core,
+ * and handle basic RFC1459 commands. Commands within modules work
+ * the same way, however, they can be fully unloaded, where these
+ * may not.
+ */
+class cmd_whois : public command_t
+{
+ public:
+       /** Constructor for whois.
+        */
+       cmd_whois (InspIRCd* Instance) : command_t(Instance,"WHOIS",0,1) { syntax = "<nick>{,<nick>}"; }
+       /** Handle command.
+        * @param parameters The parameters to the comamnd
+        * @param pcnt The number of parameters passed to teh command
+        * @param user The user issuing the command
+        * @return A value from CmdResult to indicate command success or failure.
+        */
+       CmdResult Handle(const char** parameters, int pcnt, userrec *user);
+};
+
+#endif
index bf020143cddc2782340150b6c317a30618db3fb2..58aa14bfd9c95a789235076cc9d521b4dee2d8b3 100644 (file)
@@ -1 +1,144 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.\r *                  E-mail:\r *               <brain@chatspike.net>\r *                <Craig@chatspike.net>\r *\r * Written by Craig Edwards, Craig McLure, and others.\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __CMD_WHOWAS_H__\r#define __CMD_WHOWAS_H__\r\r\r// include the common header files\r\r#include "users.h"\r#include "channels.h"\r\r/* list of available internal commands */\renum Internals\r{\r  WHOWAS_ADD = 1,\r        WHOWAS_STATS = 2,\r      WHOWAS_PRUNE = 3,\r      WHOWAS_MAINTAIN = 4\r};\r\r/* Forward ref for timer */\rclass WhoWasMaintainTimer;\r\r/* Forward ref for typedefs */\rclass WhoWasGroup;\r\r/** InspTimer that is used to maintain the whowas list, called once an hour\r */\rextern WhoWasMaintainTimer* timer;\r\r/** A group of users related by nickname\r */\rtypedef std::deque<WhoWasGroup*> whowas_set;\r\r/** Sets of users in the whowas system\r */\rtypedef std::map<irc::string,whowas_set*> whowas_users;\r\r/** Sets of time and users in whowas list\r */\rtypedef std::deque<std::pair<time_t,irc::string> > whowas_users_fifo;\r\r/** Handle /WHOWAS. These command handlers can be reloaded by the core,\r * and handle basic RFC1459 commands. Commands within modules work\r * the same way, however, they can be fully unloaded, where these\r * may not.\r */\rclass cmd_whowas : public command_t\r{\r  private:\r       /** Whowas container, contains a map of vectors of users tracked by WHOWAS\r      */\r    whowas_users whowas;\r   \r       /** Whowas container, contains a map of time_t to users tracked by WHOWAS\r       */\r    whowas_users_fifo whowas_fifo;\r\r        /* String holding stats so it can be collected\r  */\r    std::string stats;\r\r  public:\r  cmd_whowas(InspIRCd* Instance);\r        /** Handle command.\r     * @param parameters The parameters to the comamnd\r      * @param pcnt The number of parameters passed to teh command\r   * @param user The user issuing the command\r     * @return A value from CmdResult to indicate command success or failure.\r       */\r    CmdResult Handle(const char** parameters, int pcnt, userrec *user);\r    /** Handle command.\r     * @param parameters The parameters to the comamnd\r      * @param pcnt The number of parameters passed to teh command\r   * @param user The user issuing the command\r     * @return A value from CmdResult to indicate command success or failure.\r       */\r    CmdResult HandleInternal(const unsigned int id, const std::deque<classbase*> &parameters);\r     void AddToWhoWas(userrec* user);\r       void GetStats(Extensible* ext);\r        void PruneWhoWas(time_t t);\r    void MaintainWhoWas(time_t t);\r virtual ~cmd_whowas();\r};\r\r/** Used to hold WHOWAS information\r */\rclass WhoWasGroup : public classbase\r{\r public:\r     /** Real host\r   */\r    char* host;\r    /** Displayed host\r      */\r    char* dhost;\r   /** Ident\r       */\r    char* ident;\r   /** Server name\r         */\r    const char* server;\r    /** Fullname (GECOS)\r    */\r    char* gecos;\r   /** Signon time\r         */\r    time_t signon;\r\r        /** Initialize this WhoQasFroup with a user\r     */\r    WhoWasGroup(userrec* user);\r    /** Destructor\r  */\r    ~WhoWasGroup();\r};\r\rclass WhoWasMaintainTimer : public InspTimer\r{\r  private:\r  InspIRCd* ServerInstance;\r  public:\r    WhoWasMaintainTimer(InspIRCd* Instance, long interval)\r : InspTimer(interval, Instance->Time(), true), ServerInstance(Instance)\r        {\r      }\r      virtual void Tick(time_t TIME);\r};\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.
+ *                    E-mail:
+ *             <brain@chatspike.net>
+ *             <Craig@chatspike.net>
+ *
+ * Written by Craig Edwards, Craig McLure, and others.
+ * This program is free but copyrighted software; see
+ *         the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __CMD_WHOWAS_H__
+#define __CMD_WHOWAS_H__
+
+
+// include the common header files
+
+#include "users.h"
+#include "channels.h"
+
+/* list of available internal commands */
+enum Internals
+{
+       WHOWAS_ADD = 1,
+       WHOWAS_STATS = 2,
+       WHOWAS_PRUNE = 3,
+       WHOWAS_MAINTAIN = 4
+};
+
+/* Forward ref for timer */
+class WhoWasMaintainTimer;
+
+/* Forward ref for typedefs */
+class WhoWasGroup;
+
+/** InspTimer that is used to maintain the whowas list, called once an hour
+ */
+extern WhoWasMaintainTimer* timer;
+
+/** A group of users related by nickname
+ */
+typedef std::deque<WhoWasGroup*> whowas_set;
+
+/** Sets of users in the whowas system
+ */
+typedef std::map<irc::string,whowas_set*> whowas_users;
+
+/** Sets of time and users in whowas list
+ */
+typedef std::deque<std::pair<time_t,irc::string> > whowas_users_fifo;
+
+/** Handle /WHOWAS. These command handlers can be reloaded by the core,
+ * and handle basic RFC1459 commands. Commands within modules work
+ * the same way, however, they can be fully unloaded, where these
+ * may not.
+ */
+class cmd_whowas : public command_t
+{
+  private:
+       /** Whowas container, contains a map of vectors of users tracked by WHOWAS
+        */
+       whowas_users whowas;
+       
+       /** Whowas container, contains a map of time_t to users tracked by WHOWAS
+        */
+       whowas_users_fifo whowas_fifo;
+
+       /* String holding stats so it can be collected
+        */
+       std::string stats;
+
+  public:
+       cmd_whowas(InspIRCd* Instance);
+       /** Handle command.
+        * @param parameters The parameters to the comamnd
+        * @param pcnt The number of parameters passed to teh command
+        * @param user The user issuing the command
+        * @return A value from CmdResult to indicate command success or failure.
+        */
+       CmdResult Handle(const char** parameters, int pcnt, userrec *user);
+       /** Handle command.
+        * @param parameters The parameters to the comamnd
+        * @param pcnt The number of parameters passed to teh command
+        * @param user The user issuing the command
+        * @return A value from CmdResult to indicate command success or failure.
+        */
+       CmdResult HandleInternal(const unsigned int id, const std::deque<classbase*> &parameters);
+       void AddToWhoWas(userrec* user);
+       void GetStats(Extensible* ext);
+       void PruneWhoWas(time_t t);
+       void MaintainWhoWas(time_t t);
+       virtual ~cmd_whowas();
+};
+
+/** Used to hold WHOWAS information
+ */
+class WhoWasGroup : public classbase
+{
+ public:
+       /** Real host
+        */
+       char* host;
+       /** Displayed host
+        */
+       char* dhost;
+       /** Ident
+        */
+       char* ident;
+       /** Server name
+        */
+       const char* server;
+       /** Fullname (GECOS)
+        */
+       char* gecos;
+       /** Signon time
+        */
+       time_t signon;
+
+       /** Initialize this WhoQasFroup with a user
+        */
+       WhoWasGroup(userrec* user);
+       /** Destructor
+        */
+       ~WhoWasGroup();
+};
+
+class WhoWasMaintainTimer : public InspTimer
+{
+  private:
+       InspIRCd* ServerInstance;
+  public:
+       WhoWasMaintainTimer(InspIRCd* Instance, long interval)
+       : InspTimer(interval, Instance->Time(), true), ServerInstance(Instance)
+       {
+       }
+       virtual void Tick(time_t TIME);
+};
+
+#endif
index acd7f2ffd36ae3bcb69f88ee905d4c7431e911ba..cf9edbfc635a3e0c1e0dfa70f37bce610782e6e8 100644 (file)
@@ -1 +1,45 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.\r *                  E-mail:\r *               <brain@chatspike.net>\r *                <Craig@chatspike.net>\r *\r * Written by Craig Edwards, Craig McLure, and others.\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __CMD_ZLINE_H__\r#define __CMD_ZLINE_H__\r\r// include the common header files\r\r#include "users.h"\r#include "channels.h"\r\r/** Handle /ZLINE. These command handlers can be reloaded by the core,\r * and handle basic RFC1459 commands. Commands within modules work\r * the same way, however, they can be fully unloaded, where these\r * may not.\r */\rclass cmd_zline : public command_t\r{\r public:\r      /** Constructor for zline.\r      */\r    cmd_zline (InspIRCd* Instance) : command_t(Instance,"ZLINE",'o',1) { syntax = "<ipmask> [<duration> :<reason>]"; }\r     /** Handle command.\r     * @param parameters The parameters to the comamnd\r      * @param pcnt The number of parameters passed to teh command\r   * @param user The user issuing the command\r     * @return A value from CmdResult to indicate command success or failure.\r       */\r    CmdResult Handle(const char** parameters, int pcnt, userrec *user);\r};\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd is copyright (C) 2002-2007 ChatSpike-Dev.
+ *                    E-mail:
+ *             <brain@chatspike.net>
+ *             <Craig@chatspike.net>
+ *
+ * Written by Craig Edwards, Craig McLure, and others.
+ * This program is free but copyrighted software; see
+ *         the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __CMD_ZLINE_H__
+#define __CMD_ZLINE_H__
+
+// include the common header files
+
+#include "users.h"
+#include "channels.h"
+
+/** Handle /ZLINE. These command handlers can be reloaded by the core,
+ * and handle basic RFC1459 commands. Commands within modules work
+ * the same way, however, they can be fully unloaded, where these
+ * may not.
+ */
+class cmd_zline : public command_t
+{
+ public:
+       /** Constructor for zline.
+        */
+       cmd_zline (InspIRCd* Instance) : command_t(Instance,"ZLINE",'o',1) { syntax = "<ipmask> [<duration> :<reason>]"; }
+       /** Handle command.
+        * @param parameters The parameters to the comamnd
+        * @param pcnt The number of parameters passed to teh command
+        * @param user The user issuing the command
+        * @return A value from CmdResult to indicate command success or failure.
+        */
+       CmdResult Handle(const char** parameters, int pcnt, userrec *user);
+};
+
+#endif
index 687ca4d8d6f683dbd5632bcc1c7f7905e94aff40..8a719f77e98344fd451fbe55506abb0d1ab3b8d1 100644 (file)
@@ -1 +1,790 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef INSPIRCD_CONFIGREADER\r#define INSPIRCD_CONFIGREADER\r\r/* handy defines */\r\r/** Determines if a channel op is exempt from given mode m,\r * in config of server instance s. \r */\r#define CHANOPS_EXEMPT(s, m) (s->Config->ExemptChanOps[(unsigned char)m])\r\r#include <sstream>\r#include <string>\r#include <vector>\r#include <map>\r#include "inspircd.h"\r#include "globals.h"\r#include "modules.h"\r#include "socketengine.h"\r#include "socket.h"\r\r/* Required forward definitions */\rclass ServerConfig;\rclass InspIRCd;\rclass InspSocket;\r\r/** Types of data in the core config\r */\renum ConfigDataType\r{\r    DT_NOTHING       = 0,           /* No data */\r  DT_INTEGER       = 1,           /* Integer */\r  DT_CHARPTR       = 2,           /* Char pointer */\r     DT_BOOLEAN       = 3,           /* Boolean */\r  DT_ALLOW_NEWLINE = 128          /* New line characters allowed */\r};\r\r/** Holds a config value, either string, integer or boolean.\r * Callback functions receive one or more of these, either on\r * their own as a reference, or in a reference to a deque of them.\r * The callback function can then alter the values of the ValueItem\r * classes to validate the settings.\r */\rclass ValueItem\r{\r     /** Actual data */\r     std::string v;\r public:\r        /** Initialize with an int */\r  ValueItem(int value);\r  /** Initialize with a bool */\r  ValueItem(bool value);\r /** Initialize with a char pointer */\r  ValueItem(char* value);\r        /** Change value to a char pointer */\r  void Set(char* value);\r /** Change value to a const char pointer */\r    void Set(const char* val);\r     /** Change value to an int */\r  void Set(int value);\r   /** Get value as an int */\r     int GetInteger();\r      /** Get value as a string */\r   char* GetString();\r     /** Get value as a bool */\r     bool GetBool();\r};\r\r/** The base class of the container 'ValueContainer'\r * used internally by the core to hold core values.\r */\rclass ValueContainerBase\r{\r public:\r   /** Constructor */\r     ValueContainerBase() { }\r       /** Destructor */\r      virtual ~ValueContainerBase() { }\r};\r\r/** ValueContainer is used to contain pointers to different\r * core values such as the server name, maximum number of\r * clients etc.\r * It is specialized to hold a data type, then pointed at\r * a value in the ServerConfig class. When the value has been\r * read and validated, the Set method is called to write the\r * value safely in a type-safe manner.\r */\rtemplate<typename T> class ValueContainer : public ValueContainerBase\r{\r    /** Contained item */\r  T val;\r public:\r\r       /** Initialize with nothing */\r ValueContainer()\r       {\r              val = NULL;\r    }\r\r     /** Initialize with a value of type T */\r       ValueContainer(T Val)\r  {\r              val = Val;\r     }\r\r     /** Change value to type T of size s */\r        void Set(T newval, size_t s)\r   {\r              memcpy(val, newval, s);\r        }\r};\r\r/** A specialization of ValueContainer to hold a pointer to a bool\r */\rtypedef ValueContainer<bool*> ValueContainerBool;\r\r/** A specialization of ValueContainer to hold a pointer to\r * an unsigned int\r */\rtypedef ValueContainer<unsigned int*> ValueContainerUInt;\r\r/** A specialization of ValueContainer to hold a pointer to\r * a char array.\r */\rtypedef ValueContainer<char*> ValueContainerChar;\r\r/** A specialization of ValueContainer to hold a pointer to\r * an int\r */\rtypedef ValueContainer<int*> ValueContainerInt;\r\r/** A set of ValueItems used by multi-value validator functions\r */\rtypedef std::deque<ValueItem> ValueList;\r\r/** A callback for validating a single value\r */\rtypedef bool (*Validator)(ServerConfig* conf, const char*, const char*, ValueItem&);\r/** A callback for validating multiple value entries\r */\rtypedef bool (*MultiValidator)(ServerConfig* conf, const char*, char**, ValueList&, int*);\r/** A callback indicating the end of a group of entries\r */\rtypedef bool (*MultiNotify)(ServerConfig* conf, const char*);\r\r/** Holds a core configuration item and its callbacks\r */\rstruct InitialConfig\r{\r       /** Tag name */\r        char* tag;\r     /** Value name */\r      char* value;\r   /** Default, if not defined */\r char* default_value;\r   /** Value containers */\r        ValueContainerBase* val;\r       /** Data types */\r      ConfigDataType datatype;\r       /** Validation function */\r     Validator validation_function;\r};\r\r/** Holds a core configuration item and its callbacks\r * where there may be more than one item\r */\rstruct MultiConfig\r{\r     /** Tag name */\r        const char*     tag;\r   /** One or more items within tag */\r    char*           items[13];\r     /** One or more defaults for items within tags */\r      char*           items_default[13];\r     /** One or more data types */\r  int             datatype[13];\r  /** Initialization function */\r MultiNotify     init_function;\r /** Validation function */\r     MultiValidator  validation_function;\r   /** Completion function */\r     MultiNotify     finish_function;\r};\r\r/** A set of oper types\r */\rtypedef std::map<irc::string,char*> opertype_t;\r\r/** A Set of oper classes\r */\rtypedef std::map<irc::string,char*> operclass_t;\r\r\r/** This class holds the bulk of the runtime configuration for the ircd.\r * It allows for reading new config values, accessing configuration files,\r * and storage of the configuration data needed to run the ircd, such as\r * the servername, connect classes, /ADMIN data, MOTDs and filenames etc.\r */\rclass CoreExport ServerConfig : public Extensible\r{\r  private:\r   /** Creator/owner pointer\r       */\r    InspIRCd* ServerInstance;\r\r     /** This variable holds the names of all\r        * files included from the main one. This\r       * is used to make sure that no files are\r       * recursively included.\r        */\r    std::vector<std::string> include_stack;\r\r       /** This private method processes one line of\r   * configutation, appending errors to errorstream\r       * and setting error if an error has occured.\r   */\r    bool ParseLine(ConfigDataHash &target, std::string &line, long linenumber, std::ostringstream &errorstream);\r  \r        /** Process an include directive\r        */\r    bool DoInclude(ConfigDataHash &target, const std::string &file, std::ostringstream &errorstream);\r\r     /** Check that there is only one of each configuration item\r     */\r    bool CheckOnce(char* tag, bool bail, userrec* user);\r  \r  public:\r\r     InspIRCd* GetInstance();\r         \r     /** This holds all the information in the config file,\r  * it's indexed by tag name to a vector of key/values.\r  */\r    ConfigDataHash config_data;\r\r   /** Max number of WhoWas entries per user.\r      */\r    int WhoWasGroupSize;\r\r  /** Max number of cumulative user-entries in WhoWas.\r    *  When max reached and added to, push out oldest entry FIFO style.\r    */\r    int WhoWasMaxGroups;\r\r  /** Max seconds a user is kept in WhoWas before being pruned.\r   */\r    int WhoWasMaxKeep;\r\r    /** Holds the server name of the local server\r   * as defined by the administrator.\r     */\r    char ServerName[MAXBUF];\r\r      /** Notice to give to users when they are Xlined\r        */\r    char MoronBanner[MAXBUF];\r      \r       /* Holds the network name the local server\r      * belongs to. This is an arbitary field defined\r        * by the administrator.\r        */\r    char Network[MAXBUF];\r\r /** Holds the description of the local server\r   * as defined by the administrator.\r     */\r    char ServerDesc[MAXBUF];\r\r      /** Holds the admin's name, for output in\r       * the /ADMIN command.\r  */\r    char AdminName[MAXBUF];\r\r       /** Holds the email address of the admin,\r       * for output in the /ADMIN command.\r    */\r    char AdminEmail[MAXBUF];\r\r      /** Holds the admin's nickname, for output\r      * in the /ADMIN command\r        */\r    char AdminNick[MAXBUF];\r\r       /** The admin-configured /DIE password\r  */\r    char diepass[MAXBUF];\r\r /** The admin-configured /RESTART password\r      */\r    char restartpass[MAXBUF];\r\r     /** The pathname and filename of the message of the\r     * day file, as defined by the administrator.\r   */\r    char motd[MAXBUF];\r\r    /** The pathname and filename of the rules file,\r        * as defined by the administrator.\r     */\r    char rules[MAXBUF];\r\r   /** The quit prefix in use, or an empty string\r  */\r    char PrefixQuit[MAXBUF];\r\r      /** The quit suffix in use, or an empty string\r  */\r    char SuffixQuit[MAXBUF];\r\r      /** The fixed quit message in use, or an empty string\r   */\r    char FixedQuit[MAXBUF];\r\r       /** The last string found within a <die> tag, or\r        * an empty string.\r     */\r    char DieValue[MAXBUF];\r\r        /** The DNS server to use for DNS queries\r       */\r    char DNSServer[MAXBUF];\r\r       /** This variable contains a space-seperated list\r       * of commands which are disabled by the\r        * administrator of the server for non-opers.\r   */\r    char DisabledCommands[MAXBUF];\r\r        /** The full path to the modules directory.\r     * This is either set at compile time, or\r       * overridden in the configuration file via\r     * the <options> tag.\r   */\r    char ModPath[1024];\r\r   /** The full pathname to the executable, as\r     * given in argv[0] when the program starts.\r    */\r    char MyExecutable[1024];\r\r      /** The file handle of the logfile. If this\r     * value is NULL, the log file is not open,\r     * probably due to a permissions error on\r       * startup (this should not happen in normal\r    * operation!).\r         */\r    FILE *log_file;\r\r       /** If this value is true, the owner of the\r     * server specified -nofork on the command\r      * line, causing the daemon to stay in the\r      * foreground.\r  */\r    bool nofork;\r   \r       /** If this value if true then all log\r  * messages will be output, regardless of\r       * the level given in the config file.\r  * This is set with the -debug commandline\r      * option.\r      */\r    bool forcedebug;\r       \r       /** If this is true then log output will be\r     * written to the logfile. This is the default.\r         * If you put -nolog on the commandline then\r    * the logfile will not be written.\r     * This is meant to be used in conjunction with\r         * -debug for debugging without filling up the\r  * hard disk.\r   */\r    bool writelog;\r\r        /** If this value is true, halfops have been\r    * enabled in the configuration file.\r   */\r    bool AllowHalfop;\r\r     /** If this is set to true, then mode lists (e.g\r        * MODE #chan b) are hidden from unprivileged\r   * users.\r       */\r    bool HideModeLists[256];\r\r      /** If this is set to true, then channel operators\r      * are exempt from this channel mode. Used for +Sc etc.\r         */\r    bool ExemptChanOps[256];\r\r      /** The number of seconds the DNS subsystem\r     * will wait before timing out any request.\r     */\r    int dns_timeout;\r\r      /** The size of the read() buffer in the user\r   * handling code, used to read data into a user's\r       * recvQ.\r       */\r    int NetBufferSize;\r\r    /** The value to be used for listen() backlogs\r  * as default.\r  */\r    int MaxConn;\r\r  /** The soft limit value assigned to the irc server.\r    * The IRC server will not allow more than this\r         * number of local users.\r       */\r    unsigned int SoftLimit;\r\r       /** Maximum number of targets for a multi target command\r        * such as PRIVMSG or KICK\r      */\r    unsigned int MaxTargets;\r\r      /** The maximum number of /WHO results allowed\r  * in any single /WHO command.\r  */\r    int MaxWhoResults;\r\r    /** True if the DEBUG loglevel is selected.\r     */\r    int debugging;\r\r        /** The loglevel in use by the IRC server\r       */\r    int LogLevel;\r\r /** How many seconds to wait before exiting\r     * the program when /DIE is correctly issued.\r   */\r    int DieDelay;\r\r /** True if we're going to hide netsplits as *.net *.split for non-opers\r        */\r    bool HideSplits;\r\r      /** True if we're going to hide ban reasons for non-opers (e.g. G-Lines,\r        * K-Lines, Z-Lines)\r    */\r    bool HideBans;\r\r        /** Announce invites to the channel with a server notice\r        */\r    bool AnnounceInvites;\r\r /** If this is enabled then operators will\r      * see invisible (+i) channels in /whois.\r       */\r    bool OperSpyWhois;\r\r    /** Set to a non-empty string to obfuscate the server name of users in WHOIS\r    */\r    char HideWhoisServer[MAXBUF];\r\r /** Set to a non empty string to obfuscate nicknames prepended to a KILL.\r       */\r    char HideKillsServer[MAXBUF];\r\r /** The MOTD file, cached in a file_cache type.\r         */\r    file_cache MOTD;\r\r      /** The RULES file, cached in a file_cache type.\r        */\r    file_cache RULES;\r\r     /** The full pathname and filename of the PID\r   * file as defined in the configuration.\r        */\r    char PID[1024];\r\r       /** The connect classes in use by the IRC server.\r       */\r    ClassVector Classes;\r\r  /** A list of module names (names only, no paths)\r       * which are currently loaded by the server.\r    */\r    std::vector<std::string> module_names;\r\r        /** A list of the classes for listening client ports\r    */\r    std::vector<ListenSocket*> ports;\r\r     /** Boolean sets of which modules implement which functions\r     */\r    char implement_lists[255][255];\r\r       /** Global implementation list\r  */\r    char global_implementation[255];\r\r      /** A list of ports claimed by IO Modules\r       */\r    std::map<int,Module*> IOHookModule;\r\r   std::map<InspSocket*, Module*> SocketIOHookModule;\r\r    /** The 005 tokens of this server (ISUPPORT)\r    * populated/repopulated upon loading or unloading\r      * modules.\r     */\r    std::string data005;\r\r  /** isupport strings\r    */\r    std::vector<std::string> isupport;\r\r    /** STATS characters in this list are available\r         * only to operators.\r   */\r    char UserStats[MAXBUF];\r        \r       /** The path and filename of the ircd.log file\r  */\r    std::string logpath;\r\r  /** Default channel modes\r       */\r    char DefaultModes[MAXBUF];\r\r    /** Custom version string, which if defined can replace the system info in VERSION.\r     */\r    char CustomVersion[MAXBUF];\r\r   /** List of u-lined servers\r     */\r    std::map<irc::string, bool> ulines;\r\r   /** Max banlist sizes for channels (the std::string is a glob)\r  */\r    std::map<std::string, int> maxbans;\r\r   /** Directory where the inspircd binary resides\r         */\r    std::string MyDir;\r\r    /** If set to true, no user DNS lookups are to be performed\r     */\r    bool NoUserDns;\r\r       /** If set to true, provide syntax hints for unknown commands\r   */\r    bool SyntaxHints;\r\r     /** If set to true, users appear to quit then rejoin when their hosts change.\r   * This keeps clients synchronized properly.\r    */\r    bool CycleHosts;\r\r      /** If set to true, prefixed channel NOTICEs and PRIVMSGs will have the prefix\r  *  added to the outgoing text for undernet style msg prefixing.\r        */\r    bool UndernetMsgPrefix;\r\r       /** If set to true, the full nick!user@host will be shown in the TOPIC command\r  * for who set the topic last. If false, only the nick is shown.\r        */\r    bool FullHostInTopic;\r\r /** All oper type definitions from the config file\r      */\r    opertype_t opertypes;\r\r /** All oper class definitions from the config file\r     */\r    operclass_t operclass;\r\r        /** Saved argv from startup\r     */\r    char** argv;\r\r  /** Saved argc from startup\r     */\r    int argc;\r\r     /** Max channels per user\r       */\r    unsigned int MaxChans;\r\r        /** Oper max channels per user\r  */\r    unsigned int OperMaxChans;\r\r    /** Construct a new ServerConfig\r        */\r    ServerConfig(InspIRCd* Instance);\r\r     /** Clears the include stack in preperation for a Read() call.\r  */\r    void ClearStack();\r\r    /** Update the 005 vector\r       */\r    void Update005();\r\r     /** Send the 005 numerics (ISUPPORT) to a user\r  */\r    void Send005(userrec* user);\r\r  /** Read the entire configuration into memory\r   * and initialize this class. All other methods\r         * should be used only by the core.\r     */\r    void Read(bool bail, userrec* user);\r\r  /** Read a file into a file_cache object\r        */\r    bool ReadFile(file_cache &F, const char* fname);\r\r      /** Report a configuration error given in errormessage.\r         * @param bail If this is set to true, the error is sent to the console, and the program exits\r  * @param user If this is set to a non-null value, and bail is false, the errors are spooled to\r         * this user as SNOTICEs.\r       * If the parameter is NULL, the messages are spooled to all users via WriteOpers as SNOTICEs.\r  */\r    void ReportConfigError(const std::string &errormessage, bool bail, userrec* user);\r\r    /** Load 'filename' into 'target', with the new config parser everything is parsed into\r         * tag/key/value at load-time rather than at read-value time.\r   */\r    bool LoadConf(ConfigDataHash &target, const char* filename, std::ostringstream &errorstream);\r\r /** Load 'filename' into 'target', with the new config parser everything is parsed into\r         * tag/key/value at load-time rather than at read-value time.\r   */\r    bool LoadConf(ConfigDataHash &target, const std::string &filename, std::ostringstream &errorstream);\r   \r       /* Both these return true if the value existed or false otherwise */\r   \r       /** Writes 'length' chars into 'result' as a string\r     */\r    bool ConfValue(ConfigDataHash &target, const char* tag, const char* var, int index, char* result, int length, bool allow_linefeeds = false);\r   /** Writes 'length' chars into 'result' as a string\r     */\r    bool ConfValue(ConfigDataHash &target, const char* tag, const char* var, const char* default_value, int index, char* result, int length, bool allow_linefeeds = false);\r\r       /** Writes 'length' chars into 'result' as a string\r     */\r    bool ConfValue(ConfigDataHash &target, const std::string &tag, const std::string &var, int index, std::string &result, bool allow_linefeeds = false);\r  /** Writes 'length' chars into 'result' as a string\r     */\r    bool ConfValue(ConfigDataHash &target, const std::string &tag, const std::string &var, const std::string &default_value, int index, std::string &result, bool allow_linefeeds = false);\r        \r       /** Tries to convert the value to an integer and write it to 'result'\r   */\r    bool ConfValueInteger(ConfigDataHash &target, const char* tag, const char* var, int index, int &result);\r       /** Tries to convert the value to an integer and write it to 'result'\r   */\r    bool ConfValueInteger(ConfigDataHash &target, const char* tag, const char* var, const char* default_value, int index, int &result);\r    /** Tries to convert the value to an integer and write it to 'result'\r   */\r    bool ConfValueInteger(ConfigDataHash &target, const std::string &tag, const std::string &var, int index, int &result);\r /** Tries to convert the value to an integer and write it to 'result'\r   */\r    bool ConfValueInteger(ConfigDataHash &target, const std::string &tag, const std::string &var, const std::string &default_value, int index, int &result);\r       \r       /** Returns true if the value exists and has a true value, false otherwise\r      */\r    bool ConfValueBool(ConfigDataHash &target, const char* tag, const char* var, int index);\r       /** Returns true if the value exists and has a true value, false otherwise\r      */\r    bool ConfValueBool(ConfigDataHash &target, const char* tag, const char* var, const char* default_value, int index);\r    /** Returns true if the value exists and has a true value, false otherwise\r      */\r    bool ConfValueBool(ConfigDataHash &target, const std::string &tag, const std::string &var, int index);\r /** Returns true if the value exists and has a true value, false otherwise\r      */\r    bool ConfValueBool(ConfigDataHash &target, const std::string &tag, const std::string &var, const std::string &default_value, int index);\r       \r       /** Returns the number of occurences of tag in the config file\r  */\r    int ConfValueEnum(ConfigDataHash &target, const char* tag);\r    /** Returns the number of occurences of tag in the config file\r  */\r    int ConfValueEnum(ConfigDataHash &target, const std::string &tag);\r     \r       /** Returns the numbers of vars inside the index'th 'tag in the config file\r     */\r    int ConfVarEnum(ConfigDataHash &target, const char* tag, int index);\r   /** Returns the numbers of vars inside the index'th 'tag in the config file\r     */\r    int ConfVarEnum(ConfigDataHash &target, const std::string &tag, int index);\r    \r       /** Get a pointer to the module which has hooked the given port.\r        * @parameter port Port number\r  * @return Returns a pointer to the hooking module, or NULL\r     */\r    Module* GetIOHook(int port);\r\r  /** Hook a module to a client port, so that it can receive notifications\r        * of low-level port activity.\r  * @param port The port number\r  * @param Module the module to hook to the port\r         * @return True if the hook was successful.\r     */\r    bool AddIOHook(int port, Module* iomod);\r\r      /** Delete a module hook from a client port.\r    * @param port The port to detatch from\r         * @return True if successful\r   */\r    bool DelIOHook(int port);\r      \r       /** Get a pointer to the module which has hooked the given InspSocket class.\r    * @parameter port Port number\r  * @return Returns a pointer to the hooking module, or NULL\r     */\r    Module* GetIOHook(InspSocket* is);\r\r    /** Hook a module to an InspSocket class, so that it can receive notifications\r  * of low-level socket activity.\r        * @param iomod The module to hook to the socket\r        * @param is The InspSocket to attach to\r        * @return True if the hook was successful.\r     */\r    bool AddIOHook(Module* iomod, InspSocket* is);\r\r        /** Delete a module hook from an InspSocket.\r    * @param is The InspSocket to detatch from.\r    * @return True if the unhook was successful\r    */\r    bool DelIOHook(InspSocket* is);\r\r       /** Returns the fully qualified path to the inspircd directory\r  * @return The full program directory\r   */\r    std::string GetFullProgDir();\r\r /** Returns true if a directory is valid (within the modules directory).\r        * @param dirandfile The directory and filename to check\r        * @return True if the directory is valid\r       */\r    static bool DirValid(const char* dirandfile);\r\r /** Clean a filename, stripping the directories (and drives) from string.\r       * @param name Directory to tidy\r        * @return The cleaned filename\r         */\r    static char* CleanFilename(char* name);\r\r       /** Check if a file exists.\r     * @param file The full path to a file\r  * @return True if the file exists and is readable.\r     */\r    static bool FileExists(const char* file);\r      \r};\r\r/** Initialize the disabled commands list\r */\rCoreExport bool InitializeDisabledCommands(const char* data, InspIRCd* ServerInstance);\r\r/** Initialize the oper types\r */\rbool InitTypes(ServerConfig* conf, const char* tag);\r\r/** Initialize the oper classes\r */\rbool InitClasses(ServerConfig* conf, const char* tag);\r\r/** Initialize an oper type \r */\rbool DoType(ServerConfig* conf, const char* tag, char** entries, ValueList &values, int* types);\r\r/** Initialize an oper class\r */\rbool DoClass(ServerConfig* conf, const char* tag, char** entries, ValueList &values, int* types);\r\r/** Finish initializing the oper types and classes\r */\rbool DoneClassesAndTypes(ServerConfig* conf, const char* tag);\r\r#endif\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef INSPIRCD_CONFIGREADER
+#define INSPIRCD_CONFIGREADER
+
+/* handy defines */
+
+/** Determines if a channel op is exempt from given mode m,
+ * in config of server instance s. 
+ */
+#define CHANOPS_EXEMPT(s, m) (s->Config->ExemptChanOps[(unsigned char)m])
+
+#include <sstream>
+#include <string>
+#include <vector>
+#include <map>
+#include "inspircd.h"
+#include "globals.h"
+#include "modules.h"
+#include "socketengine.h"
+#include "socket.h"
+
+/* Required forward definitions */
+class ServerConfig;
+class InspIRCd;
+class InspSocket;
+
+/** Types of data in the core config
+ */
+enum ConfigDataType
+{
+       DT_NOTHING       = 0,           /* No data */
+       DT_INTEGER       = 1,           /* Integer */
+       DT_CHARPTR       = 2,           /* Char pointer */
+       DT_BOOLEAN       = 3,           /* Boolean */
+       DT_ALLOW_NEWLINE = 128          /* New line characters allowed */
+};
+
+/** Holds a config value, either string, integer or boolean.
+ * Callback functions receive one or more of these, either on
+ * their own as a reference, or in a reference to a deque of them.
+ * The callback function can then alter the values of the ValueItem
+ * classes to validate the settings.
+ */
+class ValueItem
+{
+       /** Actual data */
+       std::string v;
+ public:
+       /** Initialize with an int */
+       ValueItem(int value);
+       /** Initialize with a bool */
+       ValueItem(bool value);
+       /** Initialize with a char pointer */
+       ValueItem(char* value);
+       /** Change value to a char pointer */
+       void Set(char* value);
+       /** Change value to a const char pointer */
+       void Set(const char* val);
+       /** Change value to an int */
+       void Set(int value);
+       /** Get value as an int */
+       int GetInteger();
+       /** Get value as a string */
+       char* GetString();
+       /** Get value as a bool */
+       bool GetBool();
+};
+
+/** The base class of the container 'ValueContainer'
+ * used internally by the core to hold core values.
+ */
+class ValueContainerBase
+{
+ public:
+       /** Constructor */
+       ValueContainerBase() { }
+       /** Destructor */
+       virtual ~ValueContainerBase() { }
+};
+
+/** ValueContainer is used to contain pointers to different
+ * core values such as the server name, maximum number of
+ * clients etc.
+ * It is specialized to hold a data type, then pointed at
+ * a value in the ServerConfig class. When the value has been
+ * read and validated, the Set method is called to write the
+ * value safely in a type-safe manner.
+ */
+template<typename T> class ValueContainer : public ValueContainerBase
+{
+       /** Contained item */
+       T val;
+ public:
+
+       /** Initialize with nothing */
+       ValueContainer()
+       {
+               val = NULL;
+       }
+
+       /** Initialize with a value of type T */
+       ValueContainer(T Val)
+       {
+               val = Val;
+       }
+
+       /** Change value to type T of size s */
+       void Set(T newval, size_t s)
+       {
+               memcpy(val, newval, s);
+       }
+};
+
+/** A specialization of ValueContainer to hold a pointer to a bool
+ */
+typedef ValueContainer<bool*> ValueContainerBool;
+
+/** A specialization of ValueContainer to hold a pointer to
+ * an unsigned int
+ */
+typedef ValueContainer<unsigned int*> ValueContainerUInt;
+
+/** A specialization of ValueContainer to hold a pointer to
+ * a char array.
+ */
+typedef ValueContainer<char*> ValueContainerChar;
+
+/** A specialization of ValueContainer to hold a pointer to
+ * an int
+ */
+typedef ValueContainer<int*> ValueContainerInt;
+
+/** A set of ValueItems used by multi-value validator functions
+ */
+typedef std::deque<ValueItem> ValueList;
+
+/** A callback for validating a single value
+ */
+typedef bool (*Validator)(ServerConfig* conf, const char*, const char*, ValueItem&);
+/** A callback for validating multiple value entries
+ */
+typedef bool (*MultiValidator)(ServerConfig* conf, const char*, char**, ValueList&, int*);
+/** A callback indicating the end of a group of entries
+ */
+typedef bool (*MultiNotify)(ServerConfig* conf, const char*);
+
+/** Holds a core configuration item and its callbacks
+ */
+struct InitialConfig
+{
+       /** Tag name */
+       char* tag;
+       /** Value name */
+       char* value;
+       /** Default, if not defined */
+       char* default_value;
+       /** Value containers */
+       ValueContainerBase* val;
+       /** Data types */
+       ConfigDataType datatype;
+       /** Validation function */
+       Validator validation_function;
+};
+
+/** Holds a core configuration item and its callbacks
+ * where there may be more than one item
+ */
+struct MultiConfig
+{
+       /** Tag name */
+       const char*     tag;
+       /** One or more items within tag */
+       char*           items[13];
+       /** One or more defaults for items within tags */
+       char*           items_default[13];
+       /** One or more data types */
+       int             datatype[13];
+       /** Initialization function */
+       MultiNotify     init_function;
+       /** Validation function */
+       MultiValidator  validation_function;
+       /** Completion function */
+       MultiNotify     finish_function;
+};
+
+/** A set of oper types
+ */
+typedef std::map<irc::string,char*> opertype_t;
+
+/** A Set of oper classes
+ */
+typedef std::map<irc::string,char*> operclass_t;
+
+
+/** This class holds the bulk of the runtime configuration for the ircd.
+ * It allows for reading new config values, accessing configuration files,
+ * and storage of the configuration data needed to run the ircd, such as
+ * the servername, connect classes, /ADMIN data, MOTDs and filenames etc.
+ */
+class CoreExport ServerConfig : public Extensible
+{
+  private:
+       /** Creator/owner pointer
+        */
+       InspIRCd* ServerInstance;
+
+       /** This variable holds the names of all
+        * files included from the main one. This
+        * is used to make sure that no files are
+        * recursively included.
+        */
+       std::vector<std::string> include_stack;
+
+       /** This private method processes one line of
+        * configutation, appending errors to errorstream
+        * and setting error if an error has occured.
+        */
+       bool ParseLine(ConfigDataHash &target, std::string &line, long linenumber, std::ostringstream &errorstream);
+  
+       /** Process an include directive
+        */
+       bool DoInclude(ConfigDataHash &target, const std::string &file, std::ostringstream &errorstream);
+
+       /** Check that there is only one of each configuration item
+        */
+       bool CheckOnce(char* tag, bool bail, userrec* user);
+  
+  public:
+
+       InspIRCd* GetInstance();
+         
+       /** This holds all the information in the config file,
+        * it's indexed by tag name to a vector of key/values.
+        */
+       ConfigDataHash config_data;
+
+       /** Max number of WhoWas entries per user.
+        */
+       int WhoWasGroupSize;
+
+       /** Max number of cumulative user-entries in WhoWas.
+        *  When max reached and added to, push out oldest entry FIFO style.
+        */
+       int WhoWasMaxGroups;
+
+       /** Max seconds a user is kept in WhoWas before being pruned.
+        */
+       int WhoWasMaxKeep;
+
+       /** Holds the server name of the local server
+        * as defined by the administrator.
+        */
+       char ServerName[MAXBUF];
+
+       /** Notice to give to users when they are Xlined
+        */
+       char MoronBanner[MAXBUF];
+       
+       /* Holds the network name the local server
+        * belongs to. This is an arbitary field defined
+        * by the administrator.
+        */
+       char Network[MAXBUF];
+
+       /** Holds the description of the local server
+        * as defined by the administrator.
+        */
+       char ServerDesc[MAXBUF];
+
+       /** Holds the admin's name, for output in
+        * the /ADMIN command.
+        */
+       char AdminName[MAXBUF];
+
+       /** Holds the email address of the admin,
+        * for output in the /ADMIN command.
+        */
+       char AdminEmail[MAXBUF];
+
+       /** Holds the admin's nickname, for output
+        * in the /ADMIN command
+        */
+       char AdminNick[MAXBUF];
+
+       /** The admin-configured /DIE password
+        */
+       char diepass[MAXBUF];
+
+       /** The admin-configured /RESTART password
+        */
+       char restartpass[MAXBUF];
+
+       /** The pathname and filename of the message of the
+        * day file, as defined by the administrator.
+        */
+       char motd[MAXBUF];
+
+       /** The pathname and filename of the rules file,
+        * as defined by the administrator.
+        */
+       char rules[MAXBUF];
+
+       /** The quit prefix in use, or an empty string
+        */
+       char PrefixQuit[MAXBUF];
+
+       /** The quit suffix in use, or an empty string
+        */
+       char SuffixQuit[MAXBUF];
+
+       /** The fixed quit message in use, or an empty string
+        */
+       char FixedQuit[MAXBUF];
+
+       /** The last string found within a <die> tag, or
+        * an empty string.
+        */
+       char DieValue[MAXBUF];
+
+       /** The DNS server to use for DNS queries
+        */
+       char DNSServer[MAXBUF];
+
+       /** This variable contains a space-seperated list
+        * of commands which are disabled by the
+        * administrator of the server for non-opers.
+        */
+       char DisabledCommands[MAXBUF];
+
+       /** The full path to the modules directory.
+        * This is either set at compile time, or
+        * overridden in the configuration file via
+        * the <options> tag.
+        */
+       char ModPath[1024];
+
+       /** The full pathname to the executable, as
+        * given in argv[0] when the program starts.
+        */
+       char MyExecutable[1024];
+
+       /** The file handle of the logfile. If this
+        * value is NULL, the log file is not open,
+        * probably due to a permissions error on
+        * startup (this should not happen in normal
+        * operation!).
+        */
+       FILE *log_file;
+
+       /** If this value is true, the owner of the
+        * server specified -nofork on the command
+        * line, causing the daemon to stay in the
+        * foreground.
+        */
+       bool nofork;
+       
+       /** If this value if true then all log
+        * messages will be output, regardless of
+        * the level given in the config file.
+        * This is set with the -debug commandline
+        * option.
+        */
+       bool forcedebug;
+       
+       /** If this is true then log output will be
+        * written to the logfile. This is the default.
+        * If you put -nolog on the commandline then
+        * the logfile will not be written.
+        * This is meant to be used in conjunction with
+        * -debug for debugging without filling up the
+        * hard disk.
+        */
+       bool writelog;
+
+       /** If this value is true, halfops have been
+        * enabled in the configuration file.
+        */
+       bool AllowHalfop;
+
+       /** If this is set to true, then mode lists (e.g
+        * MODE #chan b) are hidden from unprivileged
+        * users.
+        */
+       bool HideModeLists[256];
+
+       /** If this is set to true, then channel operators
+        * are exempt from this channel mode. Used for +Sc etc.
+        */
+       bool ExemptChanOps[256];
+
+       /** The number of seconds the DNS subsystem
+        * will wait before timing out any request.
+        */
+       int dns_timeout;
+
+       /** The size of the read() buffer in the user
+        * handling code, used to read data into a user's
+        * recvQ.
+        */
+       int NetBufferSize;
+
+       /** The value to be used for listen() backlogs
+        * as default.
+        */
+       int MaxConn;
+
+       /** The soft limit value assigned to the irc server.
+        * The IRC server will not allow more than this
+        * number of local users.
+        */
+       unsigned int SoftLimit;
+
+       /** Maximum number of targets for a multi target command
+        * such as PRIVMSG or KICK
+        */
+       unsigned int MaxTargets;
+
+       /** The maximum number of /WHO results allowed
+        * in any single /WHO command.
+        */
+       int MaxWhoResults;
+
+       /** True if the DEBUG loglevel is selected.
+        */
+       int debugging;
+
+       /** The loglevel in use by the IRC server
+        */
+       int LogLevel;
+
+       /** How many seconds to wait before exiting
+        * the program when /DIE is correctly issued.
+        */
+       int DieDelay;
+
+       /** True if we're going to hide netsplits as *.net *.split for non-opers
+        */
+       bool HideSplits;
+
+       /** True if we're going to hide ban reasons for non-opers (e.g. G-Lines,
+        * K-Lines, Z-Lines)
+        */
+       bool HideBans;
+
+       /** Announce invites to the channel with a server notice
+        */
+       bool AnnounceInvites;
+
+       /** If this is enabled then operators will
+        * see invisible (+i) channels in /whois.
+        */
+       bool OperSpyWhois;
+
+       /** Set to a non-empty string to obfuscate the server name of users in WHOIS
+        */
+       char HideWhoisServer[MAXBUF];
+
+       /** Set to a non empty string to obfuscate nicknames prepended to a KILL.
+        */
+       char HideKillsServer[MAXBUF];
+
+       /** The MOTD file, cached in a file_cache type.
+        */
+       file_cache MOTD;
+
+       /** The RULES file, cached in a file_cache type.
+        */
+       file_cache RULES;
+
+       /** The full pathname and filename of the PID
+        * file as defined in the configuration.
+        */
+       char PID[1024];
+
+       /** The connect classes in use by the IRC server.
+        */
+       ClassVector Classes;
+
+       /** A list of module names (names only, no paths)
+        * which are currently loaded by the server.
+        */
+       std::vector<std::string> module_names;
+
+       /** A list of the classes for listening client ports
+        */
+       std::vector<ListenSocket*> ports;
+
+       /** Boolean sets of which modules implement which functions
+        */
+       char implement_lists[255][255];
+
+       /** Global implementation list
+        */
+       char global_implementation[255];
+
+       /** A list of ports claimed by IO Modules
+        */
+       std::map<int,Module*> IOHookModule;
+
+       std::map<InspSocket*, Module*> SocketIOHookModule;
+
+       /** The 005 tokens of this server (ISUPPORT)
+        * populated/repopulated upon loading or unloading
+        * modules.
+        */
+       std::string data005;
+
+       /** isupport strings
+        */
+       std::vector<std::string> isupport;
+
+       /** STATS characters in this list are available
+        * only to operators.
+        */
+       char UserStats[MAXBUF];
+       
+       /** The path and filename of the ircd.log file
+        */
+       std::string logpath;
+
+       /** Default channel modes
+        */
+       char DefaultModes[MAXBUF];
+
+       /** Custom version string, which if defined can replace the system info in VERSION.
+        */
+       char CustomVersion[MAXBUF];
+
+       /** List of u-lined servers
+        */
+       std::map<irc::string, bool> ulines;
+
+       /** Max banlist sizes for channels (the std::string is a glob)
+        */
+       std::map<std::string, int> maxbans;
+
+       /** Directory where the inspircd binary resides
+        */
+       std::string MyDir;
+
+       /** If set to true, no user DNS lookups are to be performed
+        */
+       bool NoUserDns;
+
+       /** If set to true, provide syntax hints for unknown commands
+        */
+       bool SyntaxHints;
+
+       /** If set to true, users appear to quit then rejoin when their hosts change.
+        * This keeps clients synchronized properly.
+        */
+       bool CycleHosts;
+
+       /** If set to true, prefixed channel NOTICEs and PRIVMSGs will have the prefix
+        *  added to the outgoing text for undernet style msg prefixing.
+        */
+       bool UndernetMsgPrefix;
+
+       /** If set to true, the full nick!user@host will be shown in the TOPIC command
+        * for who set the topic last. If false, only the nick is shown.
+        */
+       bool FullHostInTopic;
+
+       /** All oper type definitions from the config file
+        */
+       opertype_t opertypes;
+
+       /** All oper class definitions from the config file
+        */
+       operclass_t operclass;
+
+       /** Saved argv from startup
+        */
+       char** argv;
+
+       /** Saved argc from startup
+        */
+       int argc;
+
+       /** Max channels per user
+        */
+       unsigned int MaxChans;
+
+       /** Oper max channels per user
+        */
+       unsigned int OperMaxChans;
+
+       /** Construct a new ServerConfig
+        */
+       ServerConfig(InspIRCd* Instance);
+
+       /** Clears the include stack in preperation for a Read() call.
+        */
+       void ClearStack();
+
+       /** Update the 005 vector
+        */
+       void Update005();
+
+       /** Send the 005 numerics (ISUPPORT) to a user
+        */
+       void Send005(userrec* user);
+
+       /** Read the entire configuration into memory
+        * and initialize this class. All other methods
+        * should be used only by the core.
+        */
+       void Read(bool bail, userrec* user);
+
+       /** Read a file into a file_cache object
+        */
+       bool ReadFile(file_cache &F, const char* fname);
+
+       /** Report a configuration error given in errormessage.
+        * @param bail If this is set to true, the error is sent to the console, and the program exits
+        * @param user If this is set to a non-null value, and bail is false, the errors are spooled to
+        * this user as SNOTICEs.
+        * If the parameter is NULL, the messages are spooled to all users via WriteOpers as SNOTICEs.
+        */
+       void ReportConfigError(const std::string &errormessage, bool bail, userrec* user);
+
+       /** Load 'filename' into 'target', with the new config parser everything is parsed into
+        * tag/key/value at load-time rather than at read-value time.
+        */
+       bool LoadConf(ConfigDataHash &target, const char* filename, std::ostringstream &errorstream);
+
+       /** Load 'filename' into 'target', with the new config parser everything is parsed into
+        * tag/key/value at load-time rather than at read-value time.
+        */
+       bool LoadConf(ConfigDataHash &target, const std::string &filename, std::ostringstream &errorstream);
+       
+       /* Both these return true if the value existed or false otherwise */
+       
+       /** Writes 'length' chars into 'result' as a string
+        */
+       bool ConfValue(ConfigDataHash &target, const char* tag, const char* var, int index, char* result, int length, bool allow_linefeeds = false);
+       /** Writes 'length' chars into 'result' as a string
+        */
+       bool ConfValue(ConfigDataHash &target, const char* tag, const char* var, const char* default_value, int index, char* result, int length, bool allow_linefeeds = false);
+
+       /** Writes 'length' chars into 'result' as a string
+        */
+       bool ConfValue(ConfigDataHash &target, const std::string &tag, const std::string &var, int index, std::string &result, bool allow_linefeeds = false);
+       /** Writes 'length' chars into 'result' as a string
+        */
+       bool ConfValue(ConfigDataHash &target, const std::string &tag, const std::string &var, const std::string &default_value, int index, std::string &result, bool allow_linefeeds = false);
+       
+       /** Tries to convert the value to an integer and write it to 'result'
+        */
+       bool ConfValueInteger(ConfigDataHash &target, const char* tag, const char* var, int index, int &result);
+       /** Tries to convert the value to an integer and write it to 'result'
+        */
+       bool ConfValueInteger(ConfigDataHash &target, const char* tag, const char* var, const char* default_value, int index, int &result);
+       /** Tries to convert the value to an integer and write it to 'result'
+        */
+       bool ConfValueInteger(ConfigDataHash &target, const std::string &tag, const std::string &var, int index, int &result);
+       /** Tries to convert the value to an integer and write it to 'result'
+        */
+       bool ConfValueInteger(ConfigDataHash &target, const std::string &tag, const std::string &var, const std::string &default_value, int index, int &result);
+       
+       /** Returns true if the value exists and has a true value, false otherwise
+        */
+       bool ConfValueBool(ConfigDataHash &target, const char* tag, const char* var, int index);
+       /** Returns true if the value exists and has a true value, false otherwise
+        */
+       bool ConfValueBool(ConfigDataHash &target, const char* tag, const char* var, const char* default_value, int index);
+       /** Returns true if the value exists and has a true value, false otherwise
+        */
+       bool ConfValueBool(ConfigDataHash &target, const std::string &tag, const std::string &var, int index);
+       /** Returns true if the value exists and has a true value, false otherwise
+        */
+       bool ConfValueBool(ConfigDataHash &target, const std::string &tag, const std::string &var, const std::string &default_value, int index);
+       
+       /** Returns the number of occurences of tag in the config file
+        */
+       int ConfValueEnum(ConfigDataHash &target, const char* tag);
+       /** Returns the number of occurences of tag in the config file
+        */
+       int ConfValueEnum(ConfigDataHash &target, const std::string &tag);
+       
+       /** Returns the numbers of vars inside the index'th 'tag in the config file
+        */
+       int ConfVarEnum(ConfigDataHash &target, const char* tag, int index);
+       /** Returns the numbers of vars inside the index'th 'tag in the config file
+        */
+       int ConfVarEnum(ConfigDataHash &target, const std::string &tag, int index);
+       
+       /** Get a pointer to the module which has hooked the given port.
+        * @parameter port Port number
+        * @return Returns a pointer to the hooking module, or NULL
+        */
+       Module* GetIOHook(int port);
+
+       /** Hook a module to a client port, so that it can receive notifications
+        * of low-level port activity.
+        * @param port The port number
+        * @param Module the module to hook to the port
+        * @return True if the hook was successful.
+        */
+       bool AddIOHook(int port, Module* iomod);
+
+       /** Delete a module hook from a client port.
+        * @param port The port to detatch from
+        * @return True if successful
+        */
+       bool DelIOHook(int port);
+       
+       /** Get a pointer to the module which has hooked the given InspSocket class.
+        * @parameter port Port number
+        * @return Returns a pointer to the hooking module, or NULL
+        */
+       Module* GetIOHook(InspSocket* is);
+
+       /** Hook a module to an InspSocket class, so that it can receive notifications
+        * of low-level socket activity.
+        * @param iomod The module to hook to the socket
+        * @param is The InspSocket to attach to
+        * @return True if the hook was successful.
+        */
+       bool AddIOHook(Module* iomod, InspSocket* is);
+
+       /** Delete a module hook from an InspSocket.
+        * @param is The InspSocket to detatch from.
+        * @return True if the unhook was successful
+        */
+       bool DelIOHook(InspSocket* is);
+
+       /** Returns the fully qualified path to the inspircd directory
+        * @return The full program directory
+        */
+       std::string GetFullProgDir();
+
+       /** Returns true if a directory is valid (within the modules directory).
+        * @param dirandfile The directory and filename to check
+        * @return True if the directory is valid
+        */
+       static bool DirValid(const char* dirandfile);
+
+       /** Clean a filename, stripping the directories (and drives) from string.
+        * @param name Directory to tidy
+        * @return The cleaned filename
+        */
+       static char* CleanFilename(char* name);
+
+       /** Check if a file exists.
+        * @param file The full path to a file
+        * @return True if the file exists and is readable.
+        */
+       static bool FileExists(const char* file);
+       
+};
+
+/** Initialize the disabled commands list
+ */
+CoreExport bool InitializeDisabledCommands(const char* data, InspIRCd* ServerInstance);
+
+/** Initialize the oper types
+ */
+bool InitTypes(ServerConfig* conf, const char* tag);
+
+/** Initialize the oper classes
+ */
+bool InitClasses(ServerConfig* conf, const char* tag);
+
+/** Initialize an oper type 
+ */
+bool DoType(ServerConfig* conf, const char* tag, char** entries, ValueList &values, int* types);
+
+/** Initialize an oper class
+ */
+bool DoClass(ServerConfig* conf, const char* tag, char** entries, ValueList &values, int* types);
+
+/** Finish initializing the oper types and classes
+ */
+bool DoneClassesAndTypes(ServerConfig* conf, const char* tag);
+
+#endif
+
index 1641b976d905b0be7d0acfa7624ffdb8d433ca2e..65d3424478a7d8ccd8b79a7cefc950c5c8208127 100644 (file)
@@ -1 +1,79 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __CONNECTION_H__\r#define __CONNECTION_H__\r\r#include <time.h>\r#include "inspircd_config.h"\r#include "base.h"\r#include "socketengine.h"\r\r/** connection is the base class of userrec, and holds basic user properties.\r * This can be extended for holding other user-like objects in the future.\r */\rclass CoreExport connection : public EventHandler\r{\r public:\r  /** Hostname of connection.\r     * This should be valid as per RFC1035.\r         */\r    char host[65];\r\r        /** Stats counter for bytes inbound\r     */\r    int bytes_in;\r\r /** Stats counter for bytes outbound\r    */\r    int bytes_out;\r\r        /** Stats counter for commands inbound\r  */\r    int cmds_in;\r\r  /** Stats counter for commands outbound\r         */\r    int cmds_out;\r\r /** True if user has authenticated, false if otherwise\r  */\r    bool haspassed;\r\r       /** Used by userrec to indicate the registration status of the connection\r       * It is a bitfield of the REG_NICK, REG_USER and REG_ALL bits to indicate\r      * the connection state.\r        */\r    char registered;\r       \r       /** Time the connection was last pinged\r         */\r    time_t lastping;\r       \r       /** Time the connection was created, set in the constructor. This\r       * may be different from the time the user's classbase object was\r       * created.\r     */\r    time_t signon;\r \r       /** Time that the connection last sent a message, used to calculate idle time\r   */\r    time_t idle_lastmsg;\r   \r       /** Used by PING checking code\r  */\r    time_t nping;\r};\r\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __CONNECTION_H__
+#define __CONNECTION_H__
+
+#include <time.h>
+#include "inspircd_config.h"
+#include "base.h"
+#include "socketengine.h"
+
+/** connection is the base class of userrec, and holds basic user properties.
+ * This can be extended for holding other user-like objects in the future.
+ */
+class CoreExport connection : public EventHandler
+{
+ public:
+       /** Hostname of connection.
+        * This should be valid as per RFC1035.
+        */
+       char host[65];
+
+       /** Stats counter for bytes inbound
+        */
+       int bytes_in;
+
+       /** Stats counter for bytes outbound
+        */
+       int bytes_out;
+
+       /** Stats counter for commands inbound
+        */
+       int cmds_in;
+
+       /** Stats counter for commands outbound
+        */
+       int cmds_out;
+
+       /** True if user has authenticated, false if otherwise
+        */
+       bool haspassed;
+
+       /** Used by userrec to indicate the registration status of the connection
+        * It is a bitfield of the REG_NICK, REG_USER and REG_ALL bits to indicate
+        * the connection state.
+        */
+       char registered;
+       
+       /** Time the connection was last pinged
+        */
+       time_t lastping;
+       
+       /** Time the connection was created, set in the constructor. This
+        * may be different from the time the user's classbase object was
+        * created.
+        */
+       time_t signon;
+       
+       /** Time that the connection last sent a message, used to calculate idle time
+        */
+       time_t idle_lastmsg;
+       
+       /** Used by PING checking code
+        */
+       time_t nping;
+};
+
+
+#endif
index d8d76100e470788b32d2cfeed24e8035acb4ea9c..e8a3337fd2b6e23959ff7988931a7835bd2cd9ac 100644 (file)
@@ -1 +1,172 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r \r#ifndef __CTABLES_H__\r#define __CTABLES_H__\r\r\r#include "inspircd_config.h"\r#include "hash_map.h"\r#include "base.h"\r\r/* Forward declarations - required */\rclass userrec;\rclass InspIRCd;\r\r/** Used to indicate command success codes\r */\renum CmdResult\r{\r        CMD_FAILURE = 0,        /* Command exists, but failed */\r       CMD_SUCCESS = 1,        /* Command exists, and succeeded */\r    CMD_INVALID = 2,        /* Command doesnt exist at all! */\r     CMD_USER_DELETED = 3    /* User was deleted - DEPRECIATED */\r};\r\r/** For commands which should not be replicated to other\r * servers, we usually return CMD_FAILURE. this isnt readable,\r * so we define this alias for CMD_FAILURE called\r * CMD_LOCALONLY, which of course does the same thing but is\r * much more readable.\r */\r#define CMD_LOCALONLY CMD_FAILURE\r\r\r/** A structure that defines a command. Every command available\r * in InspIRCd must be defined as derived from command_t.\r */\rclass CoreExport command_t : public Extensible\r{\r protected:\r      /** Owner/Creator object\r        */\r    InspIRCd* ServerInstance;\r public:\r     /** Command name\r       */\r      std::string command;\r  /** User flags needed to execute the command or 0\r       */\r    char flags_needed;\r     /** Minimum number of parameters command takes\r */\r     int min_params;\r        /** used by /stats m\r    */\r    long use_count;\r        /** used by /stats m\r    */\r    float total_bytes;\r     /** used for resource tracking between modules\r  */\r    std::string source;\r    /** True if the command is disabled to non-opers\r        */\r    bool disabled;\r /** True if the command can be issued before registering\r        */\r    bool works_before_reg;\r /** Syntax string for the command, displayed if non-empty string.\r       * This takes place of the text in the 'not enough parameters' numeric.\r         */\r    std::string syntax;\r\r   /** Create a new command.\r       * @param Instance Pointer to creator class\r     * @param cmd Command name. This must be UPPER CASE.\r    * @param flags User modes required to execute the command.\r     * For oper only commands, set this to 'o', otherwise use 0.\r    * @param minpara Minimum parameters required for the command.\r  * @param before_reg If this is set to true, the command will\r   * be allowed before the user is 'registered' (has sent USER,\r   * NICK, optionally PASS, and been resolved).\r   */\r    command_t(InspIRCd* Instance, const std::string &cmd, char flags, int minpara, int before_reg = false) : ServerInstance(Instance), command(cmd), flags_needed(flags), min_params(minpara), disabled(false), works_before_reg(before_reg)\r       {\r              use_count = 0;\r         total_bytes = 0;\r               source = "<core>";\r             syntax = "";\r   }\r\r     /** Handle the command from a user.\r     * @param parameters The parameters for the command.\r    * @param pcnt The number of parameters available in 'parameters'\r       * @param user The user who issued the command.\r         * @return Return CMD_SUCCESS on success, or CMD_FAILURE on failure.\r    * If the command succeeds but should remain local to this server,\r      * return CMD_LOCALONLY.\r        */\r    virtual CmdResult Handle(const char** parameters, int pcnt, userrec* user) = 0;\r\r       /** Handle an internal request from another command, the core, or a module\r      * @param Command ID\r    * @param Zero or more parameters, whos form is specified by the command ID.\r    * @return Return CMD_SUCCESS on success, or CMD_FAILURE on failure.\r    * If the command succeeds but should remain local to this server,\r      * return CMD_LOCALONLY.\r        */\r    virtual CmdResult HandleInternal(const unsigned int id, const std::deque<classbase*> &params)\r  {\r              return CMD_INVALID;\r    }\r\r     /** Handle the command from a server.\r   * Not currently used in this version of InspIRCd.\r      * @param parameters The parameters given\r       * @param pcnt The number of parameters available\r       * @param servername The server name which issued the command\r   * @return Return CMD_SUCCESS on success, or CMD_FAILURE on failure.\r    * If the command succeeds but should remain local to this server,\r      * return CMD_LOCALONLY.\r        */\r    virtual CmdResult HandleServer(const char** parameters, int pcnt, const std::string &servername)\r       {\r              return CMD_INVALID;\r    }\r\r     /** Disable or enable this command.\r     * @param setting True to disable the command.\r  */\r    void Disable(bool setting)\r     {\r              disabled = setting;\r    }\r\r     /** Obtain this command's disable state.\r        * @return true if the command is currently disabled\r    * (disabled commands can be used only by operators)\r    */\r    bool IsDisabled()\r      {\r              return disabled;\r       }\r\r     /** @return true if the command works before registration.\r      */\r    bool WorksBeforeReg()\r  {\r              return works_before_reg;\r       }\r\r     /** Standard constructor gubbins\r        */\r    virtual ~command_t() {}\r};\r\r/** A hash of commands used by the core\r */\rtypedef nspace::hash_map<std::string,command_t*> command_table;\r\r#endif\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+#ifndef __CTABLES_H__
+#define __CTABLES_H__
+
+
+#include "inspircd_config.h"
+#include "hash_map.h"
+#include "base.h"
+
+/* Forward declarations - required */
+class userrec;
+class InspIRCd;
+
+/** Used to indicate command success codes
+ */
+enum CmdResult
+{
+       CMD_FAILURE = 0,        /* Command exists, but failed */
+       CMD_SUCCESS = 1,        /* Command exists, and succeeded */
+       CMD_INVALID = 2,        /* Command doesnt exist at all! */
+       CMD_USER_DELETED = 3    /* User was deleted - DEPRECIATED */
+};
+
+/** For commands which should not be replicated to other
+ * servers, we usually return CMD_FAILURE. this isnt readable,
+ * so we define this alias for CMD_FAILURE called
+ * CMD_LOCALONLY, which of course does the same thing but is
+ * much more readable.
+ */
+#define CMD_LOCALONLY CMD_FAILURE
+
+
+/** A structure that defines a command. Every command available
+ * in InspIRCd must be defined as derived from command_t.
+ */
+class CoreExport command_t : public Extensible
+{
+ protected:
+       /** Owner/Creator object
+        */
+       InspIRCd* ServerInstance;
+ public:
+       /** Command name
+       */
+        std::string command;
+       /** User flags needed to execute the command or 0
+        */
+       char flags_needed;
+       /** Minimum number of parameters command takes
+       */
+       int min_params;
+       /** used by /stats m
+        */
+       long use_count;
+       /** used by /stats m
+        */
+       float total_bytes;
+       /** used for resource tracking between modules
+        */
+       std::string source;
+       /** True if the command is disabled to non-opers
+        */
+       bool disabled;
+       /** True if the command can be issued before registering
+        */
+       bool works_before_reg;
+       /** Syntax string for the command, displayed if non-empty string.
+        * This takes place of the text in the 'not enough parameters' numeric.
+        */
+       std::string syntax;
+
+       /** Create a new command.
+        * @param Instance Pointer to creator class
+        * @param cmd Command name. This must be UPPER CASE.
+        * @param flags User modes required to execute the command.
+        * For oper only commands, set this to 'o', otherwise use 0.
+        * @param minpara Minimum parameters required for the command.
+        * @param before_reg If this is set to true, the command will
+        * be allowed before the user is 'registered' (has sent USER,
+        * NICK, optionally PASS, and been resolved).
+        */
+       command_t(InspIRCd* Instance, const std::string &cmd, char flags, int minpara, int before_reg = false) : ServerInstance(Instance), command(cmd), flags_needed(flags), min_params(minpara), disabled(false), works_before_reg(before_reg)
+       {
+               use_count = 0;
+               total_bytes = 0;
+               source = "<core>";
+               syntax = "";
+       }
+
+       /** Handle the command from a user.
+        * @param parameters The parameters for the command.
+        * @param pcnt The number of parameters available in 'parameters'
+        * @param user The user who issued the command.
+        * @return Return CMD_SUCCESS on success, or CMD_FAILURE on failure.
+        * If the command succeeds but should remain local to this server,
+        * return CMD_LOCALONLY.
+        */
+       virtual CmdResult Handle(const char** parameters, int pcnt, userrec* user) = 0;
+
+       /** Handle an internal request from another command, the core, or a module
+        * @param Command ID
+        * @param Zero or more parameters, whos form is specified by the command ID.
+        * @return Return CMD_SUCCESS on success, or CMD_FAILURE on failure.
+        * If the command succeeds but should remain local to this server,
+        * return CMD_LOCALONLY.
+        */
+       virtual CmdResult HandleInternal(const unsigned int id, const std::deque<classbase*> &params)
+       {
+               return CMD_INVALID;
+       }
+
+       /** Handle the command from a server.
+        * Not currently used in this version of InspIRCd.
+        * @param parameters The parameters given
+        * @param pcnt The number of parameters available
+        * @param servername The server name which issued the command
+        * @return Return CMD_SUCCESS on success, or CMD_FAILURE on failure.
+        * If the command succeeds but should remain local to this server,
+        * return CMD_LOCALONLY.
+        */
+       virtual CmdResult HandleServer(const char** parameters, int pcnt, const std::string &servername)
+       {
+               return CMD_INVALID;
+       }
+
+       /** Disable or enable this command.
+        * @param setting True to disable the command.
+        */
+       void Disable(bool setting)
+       {
+               disabled = setting;
+       }
+
+       /** Obtain this command's disable state.
+        * @return true if the command is currently disabled
+        * (disabled commands can be used only by operators)
+        */
+       bool IsDisabled()
+       {
+               return disabled;
+       }
+
+       /** @return true if the command works before registration.
+        */
+       bool WorksBeforeReg()
+       {
+               return works_before_reg;
+       }
+
+       /** Standard constructor gubbins
+        */
+       virtual ~command_t() {}
+};
+
+/** A hash of commands used by the core
+ */
+typedef nspace::hash_map<std::string,command_t*> command_table;
+
+#endif
+
index b2742e3905d8ee18c42439b3cc2d252bbd2f543d..129f0d43db9e1bd46a0d9e29de7f01e3030713aa 100644 (file)
@@ -1 +1,162 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __CULLLIST_H__\r#define __CULLLIST_H__\r\r// include the common header files\r\r#include <string>\r#include <deque>\r#include <vector>\r#include "users.h"\r#include "channels.h"\r\rclass InspIRCd;\r\r/** The CullItem class holds a user and their quitmessage,\r * and is used internally by the CullList class to compile\r * a list of users which are to be culled when a long\r * operation (such as a netsplit) has completed.\r */\rclass CoreExport CullItem : public classbase\r{\r private:\r      /** Holds a pointer to the user,\r        * must be valid and can be a local or remote user.\r     */\r    userrec* user;\r /** Holds the quit reason to use for this user.\r         */\r    std::string reason;\r    /** Holds the quit reason opers see, if different from users\r    */\r    std::string oper_reason;\r       /** Silent items dont generate an snotice.\r      */\r    bool silent;\r public:\r  /** Constrcutor.\r       * Initializes the CullItem with a user pointer\r * and their quit reason\r        * @param u The user to add\r     * @param r The quit reason of the added user\r   * @param ro The quit reason to show to opers only\r      */\r     CullItem(userrec* u, std::string &r, const char* ro = "");\r     /** Constrcutor.\r        * Initializes the CullItem with a user pointer\r         * and their quit reason\r        * @param u The user to add\r     * @param r The quit reason of the added user\r   * @param ro The quit reason to show to opers only\r      */\r    CullItem(userrec* u, const char* r, const char* ro = "");\r\r     /** Make the quit silent a module is dealing with\r       * displaying this users quit, so we shouldn't\r  * send anything out.\r   */\r    void MakeSilent();\r\r    /** Returns true if the quit for this user has been set\r         * to silent.\r   */\r    bool IsSilent();\r\r      /** Destructor\r  */\r    ~CullItem();\r\r  /** Returns a pointer to the user\r      */\r     userrec* GetUser();\r    /** Returns the user's quit reason\r     */\r     std::string& GetReason();\r      /** Returns oper reason\r         */\r    std::string& GetOperReason();\r};\r\r/** The CullList class can be used by modules, and is used\r * by the core, to compile large lists of users in preperation\r * to quitting them all at once. This is faster than quitting\r * them within the loop, as the loops become tighter with\r * little or no comparisons within them. The CullList class\r * operates by allowing the programmer to push users onto\r * the list, each with a seperate quit reason, and then, once\r * the list is complete, call a method to flush the list,\r * quitting all the users upon it. A CullList may hold local\r * or remote users, but it may only hold each user once. If\r * you attempt to add the same user twice, then the second\r * attempt will be ignored.\r */\rclass CoreExport CullList : public classbase\r{\r private:\r /** Creator of this CullList\r    */\r    InspIRCd* ServerInstance;\r\r     /** Holds a list of users already added for quick lookup\r        */\r    std::map<userrec*, userrec*> exempt;\r\r  /** Holds a list of users being quit.\r   * See the information for CullItem for\r         * more information.\r    */\r    std::vector<CullItem> list;\r\r public:\r  /** Constructor.\r        * Clears the CullList::list and CullList::exempt\r       * items.\r       * @param Instance Creator of this CullList object\r      */\r    CullList(InspIRCd* Instance);\r\r /** Adds a user to the cull list for later\r      * removal via QUIT.\r    * @param user The user to add\r  * @param reason The quit reason of the user being added\r        * @param o_reason The quit reason to show only to opers\r        */\r    void AddItem(userrec* user, std::string &reason, const char* o_reason = "");\r\r  /** Adds a user to the cull list for later\r      * removal via QUIT.\r    * @param user The user to add\r  * @param reason The quit reason of the user being added\r        * @param o_reason The quit reason to show only to opers\r        */\r    void AddItem(userrec* user, const char* reason, const char* o_reason = "");\r\r   /* Turn an item into a silent item (don't send out QUIT for this user)\r  */\r    void MakeSilent(userrec* user);\r\r       /** Applies the cull list, quitting all the users\r       * on the list with their quit reasons all at once.\r     * This is a very fast operation compared to\r    * iterating the user list and comparing each one,\r      * especially if there are multiple comparisons\r         * to be done, or recursion.\r    * @returns The number of users removed from IRC.\r       */\r    int Apply();\r};\r\r#endif\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __CULLLIST_H__
+#define __CULLLIST_H__
+
+// include the common header files
+
+#include <string>
+#include <deque>
+#include <vector>
+#include "users.h"
+#include "channels.h"
+
+class InspIRCd;
+
+/** The CullItem class holds a user and their quitmessage,
+ * and is used internally by the CullList class to compile
+ * a list of users which are to be culled when a long
+ * operation (such as a netsplit) has completed.
+ */
+class CoreExport CullItem : public classbase
+{
+ private:
+       /** Holds a pointer to the user,
+        * must be valid and can be a local or remote user.
+        */
+       userrec* user;
+       /** Holds the quit reason to use for this user.
+        */
+       std::string reason;
+       /** Holds the quit reason opers see, if different from users
+        */
+       std::string oper_reason;
+       /** Silent items dont generate an snotice.
+        */
+       bool silent;
+ public:
+       /** Constrcutor.
+       * Initializes the CullItem with a user pointer
+       * and their quit reason
+       * @param u The user to add
+       * @param r The quit reason of the added user
+       * @param ro The quit reason to show to opers only
+       */
+       CullItem(userrec* u, std::string &r, const char* ro = "");
+       /** Constrcutor.
+        * Initializes the CullItem with a user pointer
+        * and their quit reason
+        * @param u The user to add
+        * @param r The quit reason of the added user
+        * @param ro The quit reason to show to opers only
+        */
+       CullItem(userrec* u, const char* r, const char* ro = "");
+
+       /** Make the quit silent a module is dealing with
+        * displaying this users quit, so we shouldn't
+        * send anything out.
+        */
+       void MakeSilent();
+
+       /** Returns true if the quit for this user has been set
+        * to silent.
+        */
+       bool IsSilent();
+
+       /** Destructor
+        */
+       ~CullItem();
+
+       /** Returns a pointer to the user
+       */
+       userrec* GetUser();
+       /** Returns the user's quit reason
+       */
+       std::string& GetReason();
+       /** Returns oper reason
+        */
+       std::string& GetOperReason();
+};
+
+/** The CullList class can be used by modules, and is used
+ * by the core, to compile large lists of users in preperation
+ * to quitting them all at once. This is faster than quitting
+ * them within the loop, as the loops become tighter with
+ * little or no comparisons within them. The CullList class
+ * operates by allowing the programmer to push users onto
+ * the list, each with a seperate quit reason, and then, once
+ * the list is complete, call a method to flush the list,
+ * quitting all the users upon it. A CullList may hold local
+ * or remote users, but it may only hold each user once. If
+ * you attempt to add the same user twice, then the second
+ * attempt will be ignored.
+ */
+class CoreExport CullList : public classbase
+{
+ private:
+       /** Creator of this CullList
+        */
+       InspIRCd* ServerInstance;
+
+       /** Holds a list of users already added for quick lookup
+        */
+       std::map<userrec*, userrec*> exempt;
+
+       /** Holds a list of users being quit.
+        * See the information for CullItem for
+        * more information.
+        */
+       std::vector<CullItem> list;
+
+ public:
+       /** Constructor.
+        * Clears the CullList::list and CullList::exempt
+        * items.
+        * @param Instance Creator of this CullList object
+        */
+       CullList(InspIRCd* Instance);
+
+       /** Adds a user to the cull list for later
+        * removal via QUIT.
+        * @param user The user to add
+        * @param reason The quit reason of the user being added
+        * @param o_reason The quit reason to show only to opers
+        */
+       void AddItem(userrec* user, std::string &reason, const char* o_reason = "");
+
+       /** Adds a user to the cull list for later
+        * removal via QUIT.
+        * @param user The user to add
+        * @param reason The quit reason of the user being added
+        * @param o_reason The quit reason to show only to opers
+        */
+       void AddItem(userrec* user, const char* reason, const char* o_reason = "");
+
+       /* Turn an item into a silent item (don't send out QUIT for this user)
+        */
+       void MakeSilent(userrec* user);
+
+       /** Applies the cull list, quitting all the users
+        * on the list with their quit reasons all at once.
+        * This is a very fast operation compared to
+        * iterating the user list and comparing each one,
+        * especially if there are multiple comparisons
+        * to be done, or recursion.
+        * @returns The number of users removed from IRC.
+        */
+       int Apply();
+};
+
+#endif
+
index 279c2bc615ec15f07288b54fedd54ccd311fcff0..b00c57201f1062b0079052904f65fea830ad82b5 100644 (file)
@@ -1 +1,520 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r/*\rdns.h - dns library very very loosely based on\rfiredns, Copyright (C) 2002 Ian Gulliver\r\rThis program is free software; you can redistribute it and/or modify\rit under the terms of version 2 of the GNU General Public License as\rpublished by the Free Software Foundation.\r\rThis program is distributed in the hope that it will be useful,\rbut WITHOUT ANY WARRANTY; without even the implied warranty of\rMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\rGNU General Public License for more details.\r\rYou should have received a copy of the GNU General Public License\ralong with this program; if not, write to the Free Software\rFoundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r*/\r\r#ifndef _DNS_H\r#define _DNS_H\r\r#include <string>\r#include "inspircd_config.h"\r#include "base.h"\r#include "socketengine.h"\r#include "socket.h"\r#include "hash_map.h"\r#include "hashcomp.h"\r\rusing namespace std;\rusing irc::sockets::insp_aton;\rusing irc::sockets::insp_ntoa;\rusing irc::sockets::insp_sockaddr;\rusing irc::sockets::insp_inaddr;\r\rclass InspIRCd;\rclass Module;\r\r/**\r * Result status, used internally\r */\rclass CoreExport DNSResult : public classbase\r{\r public:\r     /** Result ID\r   */\r    int id;\r        /** Result body, a hostname or IP address\r       */\r    std::string result;\r    /** Time-to-live value of the result\r    */\r    unsigned long ttl;\r     /** The original request, a hostname or IP address\r      */\r    std::string original;\r\r /** Build a DNS result.\r         * @param i The request ID\r      * @param res The request result, a hostname or IP\r      * @param timetolive The request time-to-live\r   * @param orig The original request, a hostname or IP\r   */\r    DNSResult(int i, const std::string &res, unsigned long timetolive, const std::string &orig) : id(i), result(res), ttl(timetolive), original(orig) { }\r};\r\r/**\r * Information on a completed lookup, used internally\r */\rtypedef std::pair<unsigned char*, std::string> DNSInfo;\r\r/** Cached item stored in the query cache.\r */\rclass CoreExport CachedQuery\r{\r public:\r        /** The cached result data, an IP or hostname\r   */\r    std::string data;\r      /** The time when the item is due to expire\r     */\r    time_t expires;\r\r       /** Build a cached query\r        * @param res The result data, an IP or hostname\r        * @param ttl The time-to-live value of the query result\r        */\r    CachedQuery(const std::string &res, unsigned int ttl) : data(res)\r      {\r              expires = time(NULL) + ttl;\r    }\r\r     /** Returns the number of seconds remaining before this\r         * cache item has expired and should be removed.\r        */\r    int CalcTTLRemaining()\r {\r              int n = (int)expires - (int)time(NULL);\r                return (n < 0 ? 0 : n);\r        }\r};\r\r/** DNS cache information. Holds IPs mapped to hostnames, and hostnames mapped to IPs.\r */\r#ifndef WIN32\rtypedef nspace::hash_map<irc::string, CachedQuery, nspace::hash<irc::string> > dnscache;\r#else\rtypedef nspace::hash_map<irc::string, CachedQuery, nspace::hash_compare<irc::string> > dnscache;\r#endif\r\r/**\r * Error types that class Resolver can emit to its error method.\r */\renum ResolverError\r{\r   RESOLVER_NOERROR        =       0,\r     RESOLVER_NSDOWN         =       1,\r     RESOLVER_NXDOMAIN       =       2,\r     RESOLVER_NOTREADY       =       3,\r     RESOLVER_BADIP          =       4,\r     RESOLVER_TIMEOUT        =       5,\r     RESLOVER_FORCEUNLOAD    =       6\r};\r\r/**\r * A DNS request\r */\rclass DNSRequest;\r\r/**\r * A DNS packet header\r */\rclass DNSHeader;\r\r/**\r * A DNS Resource Record (rr)\r */\rstruct ResourceRecord;\r\r/**\r * Query and resource record types\r */\renum QueryType\r{\r   DNS_QUERY_NONE  = 0,            /* Uninitialized Query */\r      DNS_QUERY_A     = 1,            /* 'A' record: an ipv4 address */\r      DNS_QUERY_CNAME = 5,            /* 'CNAME' record: An alias */\r DNS_QUERY_PTR   = 12,           /* 'PTR' record: a hostname */\r DNS_QUERY_AAAA  = 28,           /* 'AAAA' record: an ipv6 address */\r\r  DNS_QUERY_PTR4  = 0xFFFD,       /* Force 'PTR' to use IPV4 scemantics */\r       DNS_QUERY_PTR6  = 0xFFFE        /* Force 'PTR' to use IPV6 scemantics */\r};\r\r#ifdef IPV6\rconst QueryType DNS_QUERY_FORWARD = DNS_QUERY_AAAA;\r#else\rconst QueryType DNS_QUERY_FORWARD = DNS_QUERY_A;\r#endif\rconst QueryType DNS_QUERY_REVERSE = DNS_QUERY_PTR;\r/**\r * Used internally to force PTR lookups to use a certain protocol scemantics,\r * e.g. x.x.x.x.in-addr.arpa for v4, and *.ip6.arpa for v6.\r */\renum ForceProtocol\r{\r   PROTOCOL_IPV4 = 0,      /* Forced to use ipv4 */\r       PROTOCOL_IPV6 = 1       /* Forced to use ipv6 */\r};\r\r/**\r * The Resolver class is a high-level abstraction for resolving DNS entries.\r * It can do forward and reverse IPv4 lookups, and where IPv6 is supported, will\r * also be able to do those, transparent of protocols. Module developers must\r * extend this class via inheritence, and then insert a pointer to their derived\r * class into the core using Server::AddResolver(). Once you have done this,\r * the class will be able to receive callbacks. There are two callbacks which\r * can occur by calling virtual methods, one is a success situation, and the other\r * an error situation.\r */\rclass CoreExport Resolver : public Extensible\r{\r protected:\r     /**\r     * Pointer to creator\r   */\r    InspIRCd* ServerInstance;\r      /**\r     * Pointer to creator module (if any, or NULL)\r  */\r    Module* Creator;\r       /**\r     * The input data, either a host or an IP address\r       */\r    std::string input;\r     /**\r     * True if a forward lookup is being performed, false if otherwise\r      */\r    QueryType querytype;\r   /**\r     * The DNS erver being used for lookups. If this is an empty string,\r    * the value of ServerConfig::DNSServer is used instead.\r        */\r    std::string server;\r    /**\r     * The ID allocated to your lookup. This is a pseudo-random number\r      * between 0 and 65535, a value of -1 indicating a failure.\r     * The core uses this to route results to the correct objects.\r  */\r    int myid;\r\r     /**\r     * Cached result, if there is one\r       */\r    CachedQuery *CQ;\r\r      /**\r     * Time left before cache expiry\r        */\r    int time_left;\r public:\r        /**\r     * Initiate DNS lookup. Your class should not attempt to delete or free these\r   * objects, as the core will do this for you. They must always be created upon\r  * the heap using new, as you cannot be sure at what time they will be deleted.\r         * Allocating them on the stack or attempting to delete them yourself could cause\r       * the object to go 'out of scope' and cause a segfault in the core if the result\r       * arrives at a later time.\r     * @param source The IP or hostname to resolve\r  * @param qt The query type to perform. If you just want to perform a forward\r   * or reverse lookup, and you don't care wether you get ipv4 or ipv6, then use\r  * the constants DNS_QUERY_FORWARD and DNS_QUERY_REVERSE, which automatically\r   * select from 'A' record or 'AAAA' record lookups. However, if you want to resolve\r     * a specific record type, resolution of 'A', 'AAAA', 'PTR' and 'CNAME' records\r         * is supported. Use one of the QueryType enum values to initiate this type of\r  * lookup. Resolution of 'AAAA' ipv6 records is always supported, regardless of\r         * wether InspIRCd is built with ipv6 support.\r  * If you attempt to resolve a 'PTR' record using DNS_QUERY_PTR, and InspIRCd is\r        * built with ipv6 support, the 'PTR' record will be formatted to ipv6 specs,\r   * e.g. x.x.x.x.x....ip6.arpa. otherwise it will be formatted to ipv4 specs,\r    * e.g. x.x.x.x.in-addr.arpa. This translation is automatic.\r    * To get around this automatic behaviour, you must use one of the values\r       * DNS_QUERY_PTR4 or DNS_QUERY_PTR6 to force ipv4 or ipv6 behaviour on the lookup,\r      * irrespective of what protocol InspIRCd has been built for.\r   * @param cached The constructor will set this boolean to true or false depending\r       * on whether the DNS lookup you are attempting is cached (and not expired) or not.\r     * If the value is cached, upon return this will be set to true, otherwise it will\r      * be set to false. You should pass this value to InspIRCd::AddResolver(), which\r        * will then influence the behaviour of the method and determine whether a cached\r       * or non-cached result is obtained. The value in this variable is always correct\r       * for the given request when the constructor exits.\r    * @param creator See the note below.\r   * @throw ModuleException This class may throw an instance of ModuleException, in the\r   * event a lookup could not be allocated, or a similar hard error occurs such as\r        * the network being down. This will also be thrown if an invalid IP address is\r         * passed when resolving a 'PTR' record.\r        *\r      * NOTE: If you are instantiating your DNS lookup from a module, you should set the\r     * value of creator to point at your Module class. This way if your module is unloaded\r  * whilst lookups are in progress, they can be safely removed and your module will not\r  * crash the server.\r    */\r    Resolver(InspIRCd* Instance, const std::string &source, QueryType qt, bool &cached, Module* creator = NULL);\r\r  /**\r     * The default destructor does nothing.\r         */\r    virtual ~Resolver();\r   /**\r     * When your lookup completes, this method will be called.\r      * @param result The resulting DNS lookup, either an IP address or a hostname.\r  * @param ttl The time-to-live value of the result, in the instance of a cached\r         * result, this is the number of seconds remaining before refresh/expiry.\r       * @param cached True if the result is a cached result, false if it was requested\r       * from the DNS server.\r         */\r    virtual void OnLookupComplete(const std::string &result, unsigned int ttl, bool cached) = 0;\r   /**\r     * If an error occurs (such as NXDOMAIN, no domain name found) then this method\r         * will be called.\r      * @param e A ResolverError enum containing the error type which has occured.\r   * @param errormessage The error text of the error that occured.\r        */\r    virtual void OnError(ResolverError e, const std::string &errormessage);\r        /**\r     * Returns the id value of this class. This is primarily used by the core\r       * to determine where in various tables to place a pointer to your class, but it\r        * is safe to call and use this method.\r         * As specified in RFC1035, each dns request has a 16 bit ID value, ranging\r     * from 0 to 65535. If there is an issue and the core cannot send your request,\r         * this method will return -1.\r  */\r    int GetId();\r   /**\r     * Returns the creator module, or NULL\r  */\r    Module* GetCreator();\r  /**\r     * If the result is a cached result, this triggers the objects\r  * OnLookupComplete. This is done because it is not safe to call\r        * the abstract virtual method from the constructor.\r    */\r    void TriggerCachedResult();\r};\r\r/** DNS is a singleton class used by the core to dispatch dns\r * requests to the dns server, and route incoming dns replies\r * back to Resolver objects, based upon the request ID. You\r * should never use this class yourself.\r */\rclass CoreExport DNS : public EventHandler\r{\r private:\r\r   /**\r     * Creator/Owner object\r         */\r    InspIRCd* ServerInstance;\r\r     /**\r     * The maximum value of a dns request id,\r       * 16 bits wide, 0xFFFF.\r        */\r    static const int MAX_REQUEST_ID = 0xFFFF;\r\r     /**\r     * A counter used to form part of the pseudo-random id\r  */\r    int currid;\r\r   /**\r     * We have to turn off a few checks on received packets\r         * when people are using 4in6 (e.g. ::ffff:xxxx). This is\r       * a temporary kludge, Please let me know if you know how\r       * to fix it.\r   */\r    bool ip6munge;\r\r        /**\r     * Currently cached items\r       */\r    dnscache* cache;\r\r      /** A timer which ticks every hour to remove expired\r    * items from the DNS cache.\r    */\r    class CacheTimer* PruneTimer;\r\r /**\r     * Build a dns packet payload\r   */\r    int MakePayload(const char* name, const QueryType rr, const unsigned short rr_class, unsigned char* payload);\r\r public:\r\r       /**\r     * Server address being used currently\r  */\r    int socketfamily;\r#ifdef IPV6\r  in6_addr myserver6;\r#endif\r     in_addr myserver4;\r\r    /**\r     * Currently active Resolver classes\r    */\r    Resolver* Classes[MAX_REQUEST_ID];\r\r    /**\r     * Requests that are currently 'in flight'\r      */\r    DNSRequest* requests[MAX_REQUEST_ID];\r\r /**\r     * The port number DNS requests are made on,\r    * and replies have as a source-port number.\r    */\r    static const int QUERY_PORT = 53;\r\r     /**\r     * Fill an rr (resource record) with data from input\r    */\r    static void FillResourceRecord(ResourceRecord* rr, const unsigned char* input);\r\r       /**\r     * Fill a header with data from input limited by a length\r       */\r    static void FillHeader(DNSHeader *header, const unsigned char *input, const int length);\r\r      /**\r     * Empty out a header into a data stream ready for transmission "on the wire"\r   */\r    static void EmptyHeader(unsigned char *output, const DNSHeader *header, const int length);\r\r    /**\r     * Start the lookup of an ipv4 from a hostname\r  */\r    int GetIP(const char* name);\r\r  /**\r     * Start the lookup of a hostname from an ip,\r   * always using the protocol inspircd is built for,\r     * e.g. use ipv6 reverse lookup when built for ipv6,\r    * or ipv4 lookup when built for ipv4.\r  */\r    int GetName(const insp_inaddr* ip);\r\r   /**\r     * Start lookup of a hostname from an ip, but\r   * force a specific protocol to be used for the lookup\r  * for example to perform an ipv6 reverse lookup.\r       */\r    int GetNameForce(const char *ip, ForceProtocol fp);\r\r   /**\r     * Start lookup of an ipv6 from a hostname\r      */\r    int GetIP6(const char *name);\r\r /**\r     * Start lookup of a CNAME from another hostname\r        */\r    int GetCName(const char* alias);\r\r      /**\r     * Fetch the result string (an ip or host)\r      * and/or an error message to go with it.\r       */\r    DNSResult GetResult();\r\r        /**\r     * Handle a SocketEngine read event\r     * Inherited from EventHandler\r  */\r    void HandleEvent(EventType et, int errornum = 0);\r\r     /**\r     * Add a Resolver* to the list of active classes\r        */\r    bool AddResolverClass(Resolver* r);\r\r   /**\r     * Add a query to the list to be sent\r   */\r    DNSRequest* AddQuery(DNSHeader *header, int &id, const char* original);\r\r       /**\r     * The constructor initialises the dns socket,\r  * and clears the request lists.\r        */\r    DNS(InspIRCd* Instance);\r\r      /**\r     * Re-initialize the DNS subsystem.\r     */\r    void Rehash();\r\r        /**\r     * Destructor\r   */\r    ~DNS();\r\r       /** Portable random number generator, generates\r         * its random number from the ircd stats counters,\r      * effective user id, time of day and the rollover\r      * counter (currid)\r     */\r    unsigned long PRNG();\r\r /**\r     * Turn an in6_addr into a .ip6.arpa domain\r     */\r    static void MakeIP6Int(char* query, const in6_addr *ip);\r\r      /**\r     * Clean out all dns resolvers owned by a particular\r    * module, to make unloading a module safe if there\r     * are dns requests currently in progress.\r      */\r    void CleanResolvers(Module* module);\r\r  /** Return the cached value of an IP or hostname\r        * @param source An IP or hostname to find in the cache.\r        * @return A pointer to a CachedQuery if the item exists,\r       * otherwise NULL.\r      */\r    CachedQuery* GetCache(const std::string &source);\r\r     /** Delete a cached item from the DNS cache.\r    * @param source An IP or hostname to remove\r    */\r    void DelCache(const std::string &source);\r\r     /** Clear all items from the DNS cache immediately.\r     */\r    int ClearCache();\r\r     /** Prune the DNS cache, e.g. remove all expired\r        * items and rehash the cache buckets, but leave\r        * items in the hash which are still valid.\r     */\r    int PruneCache();\r};\r\r#endif\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+/*
+dns.h - dns library very very loosely based on
+firedns, Copyright (C) 2002 Ian Gulliver
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of version 2 of the GNU General Public License as
+published by the Free Software Foundation.
+
+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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#ifndef _DNS_H
+#define _DNS_H
+
+#include <string>
+#include "inspircd_config.h"
+#include "base.h"
+#include "socketengine.h"
+#include "socket.h"
+#include "hash_map.h"
+#include "hashcomp.h"
+
+using namespace std;
+using irc::sockets::insp_aton;
+using irc::sockets::insp_ntoa;
+using irc::sockets::insp_sockaddr;
+using irc::sockets::insp_inaddr;
+
+class InspIRCd;
+class Module;
+
+/**
+ * Result status, used internally
+ */
+class CoreExport DNSResult : public classbase
+{
+ public:
+       /** Result ID
+        */
+       int id;
+       /** Result body, a hostname or IP address
+        */
+       std::string result;
+       /** Time-to-live value of the result
+        */
+       unsigned long ttl;
+       /** The original request, a hostname or IP address
+        */
+       std::string original;
+
+       /** Build a DNS result.
+        * @param i The request ID
+        * @param res The request result, a hostname or IP
+        * @param timetolive The request time-to-live
+        * @param orig The original request, a hostname or IP
+        */
+       DNSResult(int i, const std::string &res, unsigned long timetolive, const std::string &orig) : id(i), result(res), ttl(timetolive), original(orig) { }
+};
+
+/**
+ * Information on a completed lookup, used internally
+ */
+typedef std::pair<unsigned char*, std::string> DNSInfo;
+
+/** Cached item stored in the query cache.
+ */
+class CoreExport CachedQuery
+{
+ public:
+       /** The cached result data, an IP or hostname
+        */
+       std::string data;
+       /** The time when the item is due to expire
+        */
+       time_t expires;
+
+       /** Build a cached query
+        * @param res The result data, an IP or hostname
+        * @param ttl The time-to-live value of the query result
+        */
+       CachedQuery(const std::string &res, unsigned int ttl) : data(res)
+       {
+               expires = time(NULL) + ttl;
+       }
+
+       /** Returns the number of seconds remaining before this
+        * cache item has expired and should be removed.
+        */
+       int CalcTTLRemaining()
+       {
+               int n = (int)expires - (int)time(NULL);
+               return (n < 0 ? 0 : n);
+       }
+};
+
+/** DNS cache information. Holds IPs mapped to hostnames, and hostnames mapped to IPs.
+ */
+#ifndef WIN32
+typedef nspace::hash_map<irc::string, CachedQuery, nspace::hash<irc::string> > dnscache;
+#else
+typedef nspace::hash_map<irc::string, CachedQuery, nspace::hash_compare<irc::string> > dnscache;
+#endif
+
+/**
+ * Error types that class Resolver can emit to its error method.
+ */
+enum ResolverError
+{
+       RESOLVER_NOERROR        =       0,
+       RESOLVER_NSDOWN         =       1,
+       RESOLVER_NXDOMAIN       =       2,
+       RESOLVER_NOTREADY       =       3,
+       RESOLVER_BADIP          =       4,
+       RESOLVER_TIMEOUT        =       5,
+       RESLOVER_FORCEUNLOAD    =       6
+};
+
+/**
+ * A DNS request
+ */
+class DNSRequest;
+
+/**
+ * A DNS packet header
+ */
+class DNSHeader;
+
+/**
+ * A DNS Resource Record (rr)
+ */
+struct ResourceRecord;
+
+/**
+ * Query and resource record types
+ */
+enum QueryType
+{
+       DNS_QUERY_NONE  = 0,            /* Uninitialized Query */
+       DNS_QUERY_A     = 1,            /* 'A' record: an ipv4 address */
+       DNS_QUERY_CNAME = 5,            /* 'CNAME' record: An alias */
+       DNS_QUERY_PTR   = 12,           /* 'PTR' record: a hostname */
+       DNS_QUERY_AAAA  = 28,           /* 'AAAA' record: an ipv6 address */
+
+       DNS_QUERY_PTR4  = 0xFFFD,       /* Force 'PTR' to use IPV4 scemantics */
+       DNS_QUERY_PTR6  = 0xFFFE        /* Force 'PTR' to use IPV6 scemantics */
+};
+
+#ifdef IPV6
+const QueryType DNS_QUERY_FORWARD = DNS_QUERY_AAAA;
+#else
+const QueryType DNS_QUERY_FORWARD = DNS_QUERY_A;
+#endif
+const QueryType DNS_QUERY_REVERSE = DNS_QUERY_PTR;
+/**
+ * Used internally to force PTR lookups to use a certain protocol scemantics,
+ * e.g. x.x.x.x.in-addr.arpa for v4, and *.ip6.arpa for v6.
+ */
+enum ForceProtocol
+{
+       PROTOCOL_IPV4 = 0,      /* Forced to use ipv4 */
+       PROTOCOL_IPV6 = 1       /* Forced to use ipv6 */
+};
+
+/**
+ * The Resolver class is a high-level abstraction for resolving DNS entries.
+ * It can do forward and reverse IPv4 lookups, and where IPv6 is supported, will
+ * also be able to do those, transparent of protocols. Module developers must
+ * extend this class via inheritence, and then insert a pointer to their derived
+ * class into the core using Server::AddResolver(). Once you have done this,
+ * the class will be able to receive callbacks. There are two callbacks which
+ * can occur by calling virtual methods, one is a success situation, and the other
+ * an error situation.
+ */
+class CoreExport Resolver : public Extensible
+{
+ protected:
+       /**
+        * Pointer to creator
+        */
+       InspIRCd* ServerInstance;
+       /**
+        * Pointer to creator module (if any, or NULL)
+        */
+       Module* Creator;
+       /**
+        * The input data, either a host or an IP address
+        */
+       std::string input;
+       /**
+        * True if a forward lookup is being performed, false if otherwise
+        */
+       QueryType querytype;
+       /**
+        * The DNS erver being used for lookups. If this is an empty string,
+        * the value of ServerConfig::DNSServer is used instead.
+        */
+       std::string server;
+       /**
+        * The ID allocated to your lookup. This is a pseudo-random number
+        * between 0 and 65535, a value of -1 indicating a failure.
+        * The core uses this to route results to the correct objects.
+        */
+       int myid;
+
+       /**
+        * Cached result, if there is one
+        */
+       CachedQuery *CQ;
+
+       /**
+        * Time left before cache expiry
+        */
+       int time_left;
+ public:
+       /**
+        * Initiate DNS lookup. Your class should not attempt to delete or free these
+        * objects, as the core will do this for you. They must always be created upon
+        * the heap using new, as you cannot be sure at what time they will be deleted.
+        * Allocating them on the stack or attempting to delete them yourself could cause
+        * the object to go 'out of scope' and cause a segfault in the core if the result
+        * arrives at a later time.
+        * @param source The IP or hostname to resolve
+        * @param qt The query type to perform. If you just want to perform a forward
+        * or reverse lookup, and you don't care wether you get ipv4 or ipv6, then use
+        * the constants DNS_QUERY_FORWARD and DNS_QUERY_REVERSE, which automatically
+        * select from 'A' record or 'AAAA' record lookups. However, if you want to resolve
+        * a specific record type, resolution of 'A', 'AAAA', 'PTR' and 'CNAME' records
+        * is supported. Use one of the QueryType enum values to initiate this type of
+        * lookup. Resolution of 'AAAA' ipv6 records is always supported, regardless of
+        * wether InspIRCd is built with ipv6 support.
+        * If you attempt to resolve a 'PTR' record using DNS_QUERY_PTR, and InspIRCd is
+        * built with ipv6 support, the 'PTR' record will be formatted to ipv6 specs,
+        * e.g. x.x.x.x.x....ip6.arpa. otherwise it will be formatted to ipv4 specs,
+        * e.g. x.x.x.x.in-addr.arpa. This translation is automatic.
+        * To get around this automatic behaviour, you must use one of the values
+        * DNS_QUERY_PTR4 or DNS_QUERY_PTR6 to force ipv4 or ipv6 behaviour on the lookup,
+        * irrespective of what protocol InspIRCd has been built for.
+        * @param cached The constructor will set this boolean to true or false depending
+        * on whether the DNS lookup you are attempting is cached (and not expired) or not.
+        * If the value is cached, upon return this will be set to true, otherwise it will
+        * be set to false. You should pass this value to InspIRCd::AddResolver(), which
+        * will then influence the behaviour of the method and determine whether a cached
+        * or non-cached result is obtained. The value in this variable is always correct
+        * for the given request when the constructor exits.
+        * @param creator See the note below.
+        * @throw ModuleException This class may throw an instance of ModuleException, in the
+        * event a lookup could not be allocated, or a similar hard error occurs such as
+        * the network being down. This will also be thrown if an invalid IP address is
+        * passed when resolving a 'PTR' record.
+        *
+        * NOTE: If you are instantiating your DNS lookup from a module, you should set the
+        * value of creator to point at your Module class. This way if your module is unloaded
+        * whilst lookups are in progress, they can be safely removed and your module will not
+        * crash the server.
+        */
+       Resolver(InspIRCd* Instance, const std::string &source, QueryType qt, bool &cached, Module* creator = NULL);
+
+       /**
+        * The default destructor does nothing.
+        */
+       virtual ~Resolver();
+       /**
+        * When your lookup completes, this method will be called.
+        * @param result The resulting DNS lookup, either an IP address or a hostname.
+        * @param ttl The time-to-live value of the result, in the instance of a cached
+        * result, this is the number of seconds remaining before refresh/expiry.
+        * @param cached True if the result is a cached result, false if it was requested
+        * from the DNS server.
+        */
+       virtual void OnLookupComplete(const std::string &result, unsigned int ttl, bool cached) = 0;
+       /**
+        * If an error occurs (such as NXDOMAIN, no domain name found) then this method
+        * will be called.
+        * @param e A ResolverError enum containing the error type which has occured.
+        * @param errormessage The error text of the error that occured.
+        */
+       virtual void OnError(ResolverError e, const std::string &errormessage);
+       /**
+        * Returns the id value of this class. This is primarily used by the core
+        * to determine where in various tables to place a pointer to your class, but it
+        * is safe to call and use this method.
+        * As specified in RFC1035, each dns request has a 16 bit ID value, ranging
+        * from 0 to 65535. If there is an issue and the core cannot send your request,
+        * this method will return -1.
+        */
+       int GetId();
+       /**
+        * Returns the creator module, or NULL
+        */
+       Module* GetCreator();
+       /**
+        * If the result is a cached result, this triggers the objects
+        * OnLookupComplete. This is done because it is not safe to call
+        * the abstract virtual method from the constructor.
+        */
+       void TriggerCachedResult();
+};
+
+/** DNS is a singleton class used by the core to dispatch dns
+ * requests to the dns server, and route incoming dns replies
+ * back to Resolver objects, based upon the request ID. You
+ * should never use this class yourself.
+ */
+class CoreExport DNS : public EventHandler
+{
+ private:
+
+       /**
+        * Creator/Owner object
+        */
+       InspIRCd* ServerInstance;
+
+       /**
+        * The maximum value of a dns request id,
+        * 16 bits wide, 0xFFFF.
+        */
+       static const int MAX_REQUEST_ID = 0xFFFF;
+
+       /**
+        * A counter used to form part of the pseudo-random id
+        */
+       int currid;
+
+       /**
+        * We have to turn off a few checks on received packets
+        * when people are using 4in6 (e.g. ::ffff:xxxx). This is
+        * a temporary kludge, Please let me know if you know how
+        * to fix it.
+        */
+       bool ip6munge;
+
+       /**
+        * Currently cached items
+        */
+       dnscache* cache;
+
+       /** A timer which ticks every hour to remove expired
+        * items from the DNS cache.
+        */
+       class CacheTimer* PruneTimer;
+
+       /**
+        * Build a dns packet payload
+        */
+       int MakePayload(const char* name, const QueryType rr, const unsigned short rr_class, unsigned char* payload);
+
+ public:
+
+       /**
+        * Server address being used currently
+        */
+       int socketfamily;
+#ifdef IPV6
+       in6_addr myserver6;
+#endif
+       in_addr myserver4;
+
+       /**
+        * Currently active Resolver classes
+        */
+       Resolver* Classes[MAX_REQUEST_ID];
+
+       /**
+        * Requests that are currently 'in flight'
+        */
+       DNSRequest* requests[MAX_REQUEST_ID];
+
+       /**
+        * The port number DNS requests are made on,
+        * and replies have as a source-port number.
+        */
+       static const int QUERY_PORT = 53;
+
+       /**
+        * Fill an rr (resource record) with data from input
+        */
+       static void FillResourceRecord(ResourceRecord* rr, const unsigned char* input);
+
+       /**
+        * Fill a header with data from input limited by a length
+        */
+       static void FillHeader(DNSHeader *header, const unsigned char *input, const int length);
+
+       /**
+        * Empty out a header into a data stream ready for transmission "on the wire"
+        */
+       static void EmptyHeader(unsigned char *output, const DNSHeader *header, const int length);
+
+       /**
+        * Start the lookup of an ipv4 from a hostname
+        */
+       int GetIP(const char* name);
+
+       /**
+        * Start the lookup of a hostname from an ip,
+        * always using the protocol inspircd is built for,
+        * e.g. use ipv6 reverse lookup when built for ipv6,
+        * or ipv4 lookup when built for ipv4.
+        */
+       int GetName(const insp_inaddr* ip);
+
+       /**
+        * Start lookup of a hostname from an ip, but
+        * force a specific protocol to be used for the lookup
+        * for example to perform an ipv6 reverse lookup.
+        */
+       int GetNameForce(const char *ip, ForceProtocol fp);
+
+       /**
+        * Start lookup of an ipv6 from a hostname
+        */
+       int GetIP6(const char *name);
+
+       /**
+        * Start lookup of a CNAME from another hostname
+        */
+       int GetCName(const char* alias);
+
+       /**
+        * Fetch the result string (an ip or host)
+        * and/or an error message to go with it.
+        */
+       DNSResult GetResult();
+
+       /**
+        * Handle a SocketEngine read event
+        * Inherited from EventHandler
+        */
+       void HandleEvent(EventType et, int errornum = 0);
+
+       /**
+        * Add a Resolver* to the list of active classes
+        */
+       bool AddResolverClass(Resolver* r);
+
+       /**
+        * Add a query to the list to be sent
+        */
+       DNSRequest* AddQuery(DNSHeader *header, int &id, const char* original);
+
+       /**
+        * The constructor initialises the dns socket,
+        * and clears the request lists.
+        */
+       DNS(InspIRCd* Instance);
+
+       /**
+        * Re-initialize the DNS subsystem.
+        */
+       void Rehash();
+
+       /**
+        * Destructor
+        */
+       ~DNS();
+
+       /** Portable random number generator, generates
+        * its random number from the ircd stats counters,
+        * effective user id, time of day and the rollover
+        * counter (currid)
+        */
+       unsigned long PRNG();
+
+       /**
+        * Turn an in6_addr into a .ip6.arpa domain
+        */
+       static void MakeIP6Int(char* query, const in6_addr *ip);
+
+       /**
+        * Clean out all dns resolvers owned by a particular
+        * module, to make unloading a module safe if there
+        * are dns requests currently in progress.
+        */
+       void CleanResolvers(Module* module);
+
+       /** Return the cached value of an IP or hostname
+        * @param source An IP or hostname to find in the cache.
+        * @return A pointer to a CachedQuery if the item exists,
+        * otherwise NULL.
+        */
+       CachedQuery* GetCache(const std::string &source);
+
+       /** Delete a cached item from the DNS cache.
+        * @param source An IP or hostname to remove
+        */
+       void DelCache(const std::string &source);
+
+       /** Clear all items from the DNS cache immediately.
+        */
+       int ClearCache();
+
+       /** Prune the DNS cache, e.g. remove all expired
+        * items and rehash the cache buckets, but leave
+        * items in the hash which are still valid.
+        */
+       int PruneCache();
+};
+
+#endif
+
index 8f0f9e13269bdb2ccb2f5c92bb9f5f7a0ae26f12..db46291c4b888f34acec0d1101ec725431c5383f 100644 (file)
@@ -1 +1,127 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __DLL_H\r#define __DLL_H\r\r/** This typedef represents the init_module function within each module.\r * The init_module function is the only exported extern "C" declaration\r * in any module file.\r */\rtypedef void * (initfunc) (void);\r\r#include "inspircd_config.h"\r\rclass InspIRCd;\r\r/** The DLLManager class is able to load a module file by filename,\r * and locate its init_module symbol.\r */\rclass CoreExport DLLManager\r{\r public:\r       /** This constructor loads the module using dlopen()\r    * @param ServerInstance The creator class of this object\r       * @param fname The filename to load. This should be within\r     * the modules dir.\r     */\r    DLLManager(InspIRCd* ServerInstance, const char *fname);\r       virtual ~DLLManager();\r\r        /** Get a symbol using dynamic linking.\r         * @param v A function pointer, pointing at an init_module function\r     * @param sym_name The symbol name to find, usually "init_module"\r       * @return true if the symbol can be found, also the symbol will be put into v.\r         */\r    bool GetSymbol(void **v, const char *sym_name);\r\r       /** Get the last error from dlopen() or dlsym().\r        * @return The last error string, or NULL if no error has occured.\r      */\r    char* LastError() \r     {\r               return err;\r   }\r\r     /** The module handle.\r  * This is OS dependent, on POSIX platforms it is a pointer to a function\r       * pointer (yes, really!) and on windows it is a library handle.\r        */\r    void *h;\r\r protected:\r\r /** The last error string, or NULL\r      */\r    char *err;\r};\r\r/** This class is a specialized form of DLLManager designed to load InspIRCd modules.\r * It's job is to call the init_module function and receive a factory pointer.\r */\rclass CoreExport DLLFactoryBase : public DLLManager\r{\r public:\r /** Default constructor.\r        * This constructor loads a module file by calling its DLLManager subclass constructor,\r         * then finds the symbol using DLLManager::GetSymbol(), and calls the symbol,\r   * obtaining a valid pointer to the init_module function\r        */\r    DLLFactoryBase(InspIRCd* Instance, const char *fname, const char *func_name = 0);\r\r     /** Default destructor.\r         */\r    virtual ~DLLFactoryBase();\r\r    /** A function pointer to the factory function.\r         */\r    void * (*factory_func)(void);   \r};\r\r/** This is the highest-level class of the DLLFactory system used to load InspIRCd modules.\r * Its job is to finally call the init_module function and obtain a pointer to a ModuleFactory.\r * This template is a container for ModuleFactory itself, so that it may 'plug' into ModuleFactory\r * and provide module loading capabilities transparently.\r */\rtemplate <class T> class CoreExport DLLFactory : public DLLFactoryBase\r{\r public:\r    /** Default constructor.\r        * This constructor passes its paramerers down through DLLFactoryBase and then DLLManager\r       * to load the module, then calls the factory function to retrieve a pointer to a ModuleFactory\r         * class. It is then down to the core to call the ModuleFactory::CreateModule() method and\r      * receive a Module* which it can insert into its module lists.\r         */\r    DLLFactory(InspIRCd* Instance, const char *fname, const char *func_name=0) : DLLFactoryBase(Instance, fname, func_name)\r        {\r              if (factory_func)\r                      factory = reinterpret_cast<T*>(factory_func());\r                else\r                   factory = reinterpret_cast<T*>(-1);\r    }\r      \r       /** The destructor deletes the ModuleFactory pointer.\r   */\r    ~DLLFactory()\r  {\r              if (factory)\r                   delete factory;\r        }\r\r     /** The ModuleFactory pointer.\r  */\r    T *factory;\r};\r\r#endif\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __DLL_H
+#define __DLL_H
+
+/** This typedef represents the init_module function within each module.
+ * The init_module function is the only exported extern "C" declaration
+ * in any module file.
+ */
+typedef void * (initfunc) (void);
+
+#include "inspircd_config.h"
+
+class InspIRCd;
+
+/** The DLLManager class is able to load a module file by filename,
+ * and locate its init_module symbol.
+ */
+class CoreExport DLLManager
+{
+ public:
+       /** This constructor loads the module using dlopen()
+        * @param ServerInstance The creator class of this object
+        * @param fname The filename to load. This should be within
+        * the modules dir.
+        */
+       DLLManager(InspIRCd* ServerInstance, const char *fname);
+       virtual ~DLLManager();
+
+       /** Get a symbol using dynamic linking.
+        * @param v A function pointer, pointing at an init_module function
+        * @param sym_name The symbol name to find, usually "init_module"
+        * @return true if the symbol can be found, also the symbol will be put into v.
+        */
+       bool GetSymbol(void **v, const char *sym_name);
+
+       /** Get the last error from dlopen() or dlsym().
+        * @return The last error string, or NULL if no error has occured.
+        */
+       char* LastError() 
+       {
+                return err;
+       }
+
+       /** The module handle.
+        * This is OS dependent, on POSIX platforms it is a pointer to a function
+        * pointer (yes, really!) and on windows it is a library handle.
+        */
+       void *h;
+
+ protected:
+
+       /** The last error string, or NULL
+        */
+       char *err;
+};
+
+/** This class is a specialized form of DLLManager designed to load InspIRCd modules.
+ * It's job is to call the init_module function and receive a factory pointer.
+ */
+class CoreExport DLLFactoryBase : public DLLManager
+{
+ public:
+       /** Default constructor.
+        * This constructor loads a module file by calling its DLLManager subclass constructor,
+        * then finds the symbol using DLLManager::GetSymbol(), and calls the symbol,
+        * obtaining a valid pointer to the init_module function
+        */
+       DLLFactoryBase(InspIRCd* Instance, const char *fname, const char *func_name = 0);
+
+       /** Default destructor.
+        */
+       virtual ~DLLFactoryBase();
+
+       /** A function pointer to the factory function.
+        */
+       void * (*factory_func)(void);   
+};
+
+/** This is the highest-level class of the DLLFactory system used to load InspIRCd modules.
+ * Its job is to finally call the init_module function and obtain a pointer to a ModuleFactory.
+ * This template is a container for ModuleFactory itself, so that it may 'plug' into ModuleFactory
+ * and provide module loading capabilities transparently.
+ */
+template <class T> class CoreExport DLLFactory : public DLLFactoryBase
+{
+ public:
+       /** Default constructor.
+        * This constructor passes its paramerers down through DLLFactoryBase and then DLLManager
+        * to load the module, then calls the factory function to retrieve a pointer to a ModuleFactory
+        * class. It is then down to the core to call the ModuleFactory::CreateModule() method and
+        * receive a Module* which it can insert into its module lists.
+        */
+       DLLFactory(InspIRCd* Instance, const char *fname, const char *func_name=0) : DLLFactoryBase(Instance, fname, func_name)
+       {
+               if (factory_func)
+                       factory = reinterpret_cast<T*>(factory_func());
+               else
+                       factory = reinterpret_cast<T*>(-1);
+       }
+       
+       /** The destructor deletes the ModuleFactory pointer.
+        */
+       ~DLLFactory()
+       {
+               if (factory)
+                       delete factory;
+       }
+
+       /** The ModuleFactory pointer.
+        */
+       T *factory;
+};
+
+#endif
+
index 84132c5ca993da234f3d0874a20876e3be79a5ab..d6830198448723e0283667159cc20dc2995a5dd6 100644 (file)
@@ -1 +1,45 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __EXITCODE_H__\r#define __EXITCODE_H__\r\r/** Valid exit codes to be used with InspIRCd::Exit()\r */\renum ExitStatus\r{\r        EXIT_STATUS_NOERROR = 0,        /* No error */\r EXIT_STATUS_DIE = 1,            /* Operator issued DIE */\r      EXIT_STATUS_FAILED_EXEC = 2,    /* execv() failed */\r   EXIT_STATUS_INTERNAL = 3,       /* Internal error */\r   EXIT_STATUS_CONFIG = 4,         /* Config error */\r     EXIT_STATUS_LOG = 5,            /* Log file error */\r   EXIT_STATUS_FORK = 6,           /* fork() failed */\r    EXIT_STATUS_ARGV = 7,           /* Invalid program arguments */\r        EXIT_STATUS_BIND = 8,           /* Port binding failed on all ports */\r EXIT_STATUS_PID = 9,            /* Couldn't write PID file */\r  EXIT_STATUS_SOCKETENGINE = 10,  /* Couldn't start socket engine */\r     EXIT_STATUS_ROOT = 11,          /* Refusing to start as root */\r        EXIT_STATUS_DIETAG = 12,        /* Found a die tag in the config file */\r       EXIT_STATUS_MODULE = 13,        /* Couldn't load a required module */\r  EXIT_STATUS_CREATEPROCESS = 14, /* CreateProcess failed (windows) */\r   EXIT_STATUS_SIGTERM = 15        /* Note: dont move this value. It corresponds with the value of #define SIGTERM. */\r};\r\r/** Array that maps exit codes (ExitStatus types) to\r * human-readable strings to be shown on shutdown.\r */\rextern const char * ExitCodes[];\r\r#endif\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __EXITCODE_H__
+#define __EXITCODE_H__
+
+/** Valid exit codes to be used with InspIRCd::Exit()
+ */
+enum ExitStatus
+{
+       EXIT_STATUS_NOERROR = 0,        /* No error */
+       EXIT_STATUS_DIE = 1,            /* Operator issued DIE */
+       EXIT_STATUS_FAILED_EXEC = 2,    /* execv() failed */
+       EXIT_STATUS_INTERNAL = 3,       /* Internal error */
+       EXIT_STATUS_CONFIG = 4,         /* Config error */
+       EXIT_STATUS_LOG = 5,            /* Log file error */
+       EXIT_STATUS_FORK = 6,           /* fork() failed */
+       EXIT_STATUS_ARGV = 7,           /* Invalid program arguments */
+       EXIT_STATUS_BIND = 8,           /* Port binding failed on all ports */
+       EXIT_STATUS_PID = 9,            /* Couldn't write PID file */
+       EXIT_STATUS_SOCKETENGINE = 10,  /* Couldn't start socket engine */
+       EXIT_STATUS_ROOT = 11,          /* Refusing to start as root */
+       EXIT_STATUS_DIETAG = 12,        /* Found a die tag in the config file */
+       EXIT_STATUS_MODULE = 13,        /* Couldn't load a required module */
+       EXIT_STATUS_CREATEPROCESS = 14, /* CreateProcess failed (windows) */
+       EXIT_STATUS_SIGTERM = 15        /* Note: dont move this value. It corresponds with the value of #define SIGTERM. */
+};
+
+/** Array that maps exit codes (ExitStatus types) to
+ * human-readable strings to be shown on shutdown.
+ */
+extern const char * ExitCodes[];
+
+#endif
+
index 5755c1fd0e2455292ca8d4970ee153d4dee150d9..4a01e454eed81eef909734d8f9b0c99a36708bc1 100644 (file)
@@ -1 +1,39 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __WORLD_H\r#define __WORLD_H\r\r#include <string>\r#include <deque>\r#include <map>\r#include <vector>\r\r/** A cached text file stored with its contents as lines\r */\rtypedef std::deque<std::string> file_cache;\r\r/** A configuration key and value pair\r */\rtypedef std::pair< std::string, std::string > KeyVal;\r\r/** A list of related configuration keys and values\r */\rtypedef std::vector< KeyVal > KeyValList;\r\r/** An entire config file, built up of KeyValLists\r */\rtypedef std::multimap< std::string, KeyValList > ConfigDataHash;\r\r#endif\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __WORLD_H
+#define __WORLD_H
+
+#include <string>
+#include <deque>
+#include <map>
+#include <vector>
+
+/** A cached text file stored with its contents as lines
+ */
+typedef std::deque<std::string> file_cache;
+
+/** A configuration key and value pair
+ */
+typedef std::pair< std::string, std::string > KeyVal;
+
+/** A list of related configuration keys and values
+ */
+typedef std::vector< KeyVal > KeyValList;
+
+/** An entire config file, built up of KeyValLists
+ */
+typedef std::multimap< std::string, KeyValList > ConfigDataHash;
+
+#endif
+
index 36e0b2b028b7db2fd826ad917372d5aaab743a3b..784a8bc3b2a21b7925d7786cffebdf035297a473 100644 (file)
@@ -1 +1,33 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r \r#ifndef INSPIRCD_HASHMAP_H\r#define INSPIRCD_HASHMAP_H\r\r#include "inspircd_config.h"\r\r/** Where hash_map is varies from compiler to compiler\r * as it is not standard.\r */\r#ifndef WIN32\r#include <ext/hash_map>\r/** Oddball linux namespace for hash_map */\r#define nspace __gnu_cxx\r#else\r#include <hash_map>\r#define nspace stdext\r/** Oddball windows namespace for hash_map */\rusing stdext::hash_map;\r#endif\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+#ifndef INSPIRCD_HASHMAP_H
+#define INSPIRCD_HASHMAP_H
+
+#include "inspircd_config.h"
+
+/** Where hash_map is varies from compiler to compiler
+ * as it is not standard.
+ */
+#ifndef WIN32
+#include <ext/hash_map>
+/** Oddball linux namespace for hash_map */
+#define nspace __gnu_cxx
+#else
+#include <hash_map>
+#define nspace stdext
+/** Oddball windows namespace for hash_map */
+using stdext::hash_map;
+#endif
+
+#endif
index 47f051c804562d9392f8166407662a403d30e3c8..0556f4399aefda9fb46042f0a0f24942fbfd3755 100644 (file)
@@ -1 +1,710 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *        the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef _HASHCOMP_H_\r#define _HASHCOMP_H_\r\r#include "inspircd_config.h"\r#include "socket.h"\r#include "hash_map.h"\r\r/*******************************************************\r * This file contains classes and templates that deal\r * with the comparison and hashing of 'irc strings'.\r * An 'irc string' is a string which compares in a\r * case insensitive manner, and as per RFC 1459 will\r * treat [ identical to {, ] identical to }, and \\r * as identical to |.\r *\r * Our hashing functions are designed  to accept\r * std::string and compare/hash them as type irc::string\r * by converting them internally. This makes them\r * backwards compatible with other code which is not\r * aware of irc::string.\r *******************************************************/\r\r/** Required namespaces and symbols */\rusing namespace std;\r\r/** aton() */\rusing irc::sockets::insp_aton;\r\r/** nota() */\rusing irc::sockets::insp_ntoa;\r\r#ifndef LOWERMAP\r#define LOWERMAP\r/** A mapping of uppercase to lowercase, including scandinavian\r * 'oddities' as specified by RFC1459, e.g. { -> [, and | -> \\r */\runsigned const char lowermap[256] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,                              /* 0-19 */\r                             20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,                         /* 20-39 */\r                            40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,                         /* 40-59 */\r                            60, 61, 62, 63, 64, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,             /* 60-79 */\r                            112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 94, 95, 96, 97, 98, 99,           /* 80-99 */\r                            100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,     /* 100-119 */\r                          120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139,     /* 120-139 */\r                          140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,     /* 140-159 */\r                          160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179,     /* 160-179 */\r                          180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199,     /* 180-199 */\r                          200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219,     /* 200-219 */\r                          220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,     /* 220-239 */\r                          240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255                          /* 240-255 */\r};\r#endif\r\r/** The irc namespace contains a number of helper classes.\r */\rnamespace irc\r{\r\r       /** This class returns true if two strings match.\r       * Case sensitivity is ignored, and the RFC 'character set'\r     * is adhered to\r        */\r    struct StrHashComp\r     {\r              /** The operator () does the actual comparison in hash_map\r              */\r            bool operator()(const std::string& s1, const std::string& s2) const;\r   };\r\r    /** The irc_char_traits class is used for RFC-style comparison of strings.\r      * This class is used to implement irc::string, a case-insensitive, RFC-\r        * comparing string class.\r      */\r    struct irc_char_traits : std::char_traits<char> {\r\r             /** Check if two chars match.\r           * @param c1st First character\r          * @param c2nd Second character\r                 * @return true if the characters are equal\r             */\r            static bool eq(char c1st, char c2nd);\r\r         /** Check if two chars do NOT match.\r            * @param c1st First character\r          * @param c2nd Second character\r                 * @return true if the characters are unequal\r           */\r            static bool ne(char c1st, char c2nd);\r\r         /** Check if one char is less than another.\r             * @param c1st First character\r          * @param c2nd Second character\r                 * @return true if c1st is less than c2nd\r               */\r            static bool lt(char c1st, char c2nd);\r\r         /** Compare two strings of size n.\r              * @param str1 First string\r             * @param str2 Second string\r            * @param n Length to compare to\r                * @return similar to strcmp, zero for equal, less than zero for str1\r           * being less and greater than zero for str1 being greater than str2.\r           */\r            static CoreExport int compare(const char* str1, const char* str2, size_t n);\r\r          /** Find a char within a string up to position n.\r               * @param s1 String to find in\r          * @param n Position to search up to\r            * @param c Character to search for\r             * @return Pointer to the first occurance of c in s1\r            */\r            static CoreExport const char* find(const char* s1, int  n, char c);\r    };\r\r    /** Compose a hex string from raw data.\r         * @param raw The raw data to compose hex from\r  * @pram rawsz The size of the raw data buffer\r  * @return The hex string.\r      */\r    CoreExport std::string hex(const unsigned char *raw, size_t rawsz);\r\r   /** This typedef declares irc::string based upon irc_char_traits.\r       */\r    typedef basic_string<char, irc_char_traits, allocator<char> > string;\r\r /** irc::stringjoiner joins string lists into a string, using\r   * the given seperator string.\r  * This class can join a vector of std::string, a deque of\r      * std::string, or a const char** array, using overloaded\r       * constructors.\r        */\r    class CoreExport stringjoiner\r  {\r       private:\r              /** Output string\r               */\r            std::string joined;\r     public:\r               /** Join elements of a vector, between (and including) begin and end\r            * @param seperator The string to seperate values with\r          * @param sequence One or more items to seperate\r                * @param begin The starting element in the sequence to be joined\r               * @param end The ending element in the sequence to be joined\r           */\r            stringjoiner(const std::string &seperator, const std::vector<std::string> &sequence, int begin, int end);\r              /** Join elements of a deque, between (and including) begin and end\r             * @param seperator The string to seperate values with\r          * @param sequence One or more items to seperate\r                * @param begin The starting element in the sequence to be joined\r               * @param end The ending element in the sequence to be joined\r           */\r            stringjoiner(const std::string &seperator, const std::deque<std::string> &sequence, int begin, int end);\r               /** Join elements of an array of char arrays, between (and including) begin and end\r             * @param seperator The string to seperate values with\r          * @param sequence One or more items to seperate\r                * @param begin The starting element in the sequence to be joined\r               * @param end The ending element in the sequence to be joined\r           */\r            stringjoiner(const std::string &seperator, const char** sequence, int begin, int end);\r\r                /** Get the joined sequence\r             * @return A reference to the joined string\r             */\r            std::string& GetJoined();\r      };\r\r    /** irc::modestacker stacks mode sequences into a list.\r         * It can then reproduce this list, clamped to a maximum of MAXMODES\r    * values per line.\r     */\r    class CoreExport modestacker\r   {\r       private:\r              /** The mode sequence and its parameters\r                */\r            std::deque<std::string> sequence;\r              /** True if the mode sequence is initially adding\r               * characters, false if it is initially removing\r                * them\r                 */\r            bool adding;\r    public:\r               /** Construct a new modestacker.\r                * @param add True if the stack is adding modes,\r                * false if it is removing them\r                 */\r            modestacker(bool add);\r         /** Push a modeletter and its parameter onto the stack.\r                 * No checking is performed as to if this mode actually\r                 * requires a parameter. If you stack invalid mode\r              * sequences, they will be tidied if and when they are\r          * passed to a mode parser.\r             * @param modeletter The mode letter to insert\r          * @param parameter The parameter for the mode\r          */\r            void Push(char modeletter, const std::string &parameter);\r              /** Push a modeletter without parameter onto the stack.\r                 * No checking is performed as to if this mode actually\r                 * requires a parameter. If you stack invalid mode\r              * sequences, they will be tidied if and when they are\r          * passed to a mode parser.\r             * @param modeletter The mode letter to insert\r          */\r            void Push(char modeletter);\r            /** Push a '+' symbol onto the stack.\r           */\r            void PushPlus();\r               /** Push a '-' symbol onto the stack.\r           */\r            void PushMinus();\r              /** Return zero or more elements which form the\r                 * mode line. This will be clamped to a max of\r          * MAXMODES items (MAXMODES-1 mode parameters and\r               * one mode sequence string), and max_line_size\r                 * characters. As specified below, this function\r                * should be called in a loop until it returns zero,\r            * indicating there are no more modes to return.\r                * @param result The deque to populate. This will\r               * be cleared before it is used.\r                * @param max_line_size The maximum size of the line\r            * to build, in characters, seperate to MAXMODES.\r               * @return The number of elements in the deque.\r                 * The function should be called repeatedly until it\r            * returns 0, in case there are multiple lines of\r               * mode changes to be obtained.\r                 */\r            int GetStackedLine(std::deque<std::string> &result, int max_line_size = 360);\r  };\r\r    /** irc::tokenstream reads a string formatted as per RFC1459 and RFC2812.\r       * It will split the string into 'tokens' each containing one parameter\r         * from the string.\r     * For instance, if it is instantiated with the string:\r         * "PRIVMSG #test :foo bar baz qux"\r     * then each successive call to tokenstream::GetToken() will return\r     * "PRIVMSG", "#test", "foo bar baz qux", "".\r   * Note that if the whole string starts with a colon this is not taken\r  * to mean the string is all one parameter, and the first item in the\r   * list will be ":item". This is to allow for parsing 'source' fields\r   * from data.\r   */\r    class CoreExport tokenstream\r   {\r       private:\r              /** Original string\r             */\r            std::string tokens;\r            /** Last position of a seperator token\r          */\r            std::string::iterator last_starting_position;\r          /** Current string position\r             */\r            std::string::iterator n;\r               /** True if the last value was an ending value\r          */\r            bool last_pushed;\r       public:\r               /** Create a tokenstream and fill it with the provided data\r             */\r            tokenstream(const std::string &source);\r                ~tokenstream();\r\r               /** Fetch the next token from the stream as a std::string\r               * @param token The next token available, or an empty string if none remain\r             * @return True if tokens are left to be read, false if the last token was just retrieved.\r              */\r            bool GetToken(std::string &token);\r\r            /** Fetch the next token from the stream as an irc::string\r              * @param token The next token available, or an empty string if none remain\r             * @return True if tokens are left to be read, false if the last token was just retrieved.\r              */\r            bool GetToken(irc::string &token);\r\r            /** Fetch the next token from the stream as an integer\r          * @param token The next token available, or undefined if none remain\r           * @return True if tokens are left to be read, false if the last token was just retrieved.\r              */\r            bool GetToken(int &token);\r\r            /** Fetch the next token from the stream as a long integer\r              * @param token The next token available, or undefined if none remain\r           * @return True if tokens are left to be read, false if the last token was just retrieved.\r              */\r            bool GetToken(long &token);\r    };\r\r    /** irc::sepstream allows for splitting token seperated lists.\r  * Each successive call to sepstream::GetToken() returns\r        * the next token, until none remain, at which point the method returns\r         * an empty string.\r     */\r    class CoreExport sepstream : public classbase\r  {\r       private:\r              /** Original string.\r            */\r            std::string tokens;\r            /** Last position of a seperator token\r          */\r            std::string::iterator last_starting_position;\r          /** Current string position\r             */\r            std::string::iterator n;\r               /** Seperator value\r             */\r            char sep;\r       public:\r               /** Create a sepstream and fill it with the provided data\r               */\r            sepstream(const std::string &source, char seperator);\r          virtual ~sepstream();\r\r         /** Fetch the next token from the stream\r                * @return The next token is returned, or an empty string if none remain\r                */\r            virtual const std::string GetToken();\r          \r               /** Fetch the entire remaining stream, without tokenizing\r               * @return The remaining part of the stream\r             */\r            virtual const std::string GetRemaining();\r              \r               /** Returns true if the end of the stream has been reached\r              * @return True if the end of the stream has been reached, otherwise false\r              */\r            virtual bool StreamEnd();\r      };\r\r    /** A derived form of sepstream, which seperates on commas\r      */\r    class CoreExport commasepstream : public sepstream\r     {\r       public:\r               /** Initialize with comma seperator\r             */\r            commasepstream(const std::string &source) : sepstream(source, ',')\r             {\r              }\r      };\r\r    /** A derived form of sepstream, which seperates on spaces\r      */\r    class CoreExport spacesepstream : public sepstream\r     {\r       public:\r               /** Initialize with space seperator\r             */\r            spacesepstream(const std::string &source) : sepstream(source, ' ')\r             {\r              }\r      };\r\r    /** The portparser class seperates out a port range into integers.\r      * A port range may be specified in the input string in the form\r        * "6660,6661,6662-6669,7020". The end of the stream is indicated by\r    * a return value of 0 from portparser::GetToken(). If you attempt\r      * to specify an illegal range (e.g. one where start >= end, or\r         * start or end < 0) then GetToken() will return the first element\r      * of the pair of numbers.\r      */\r    class CoreExport portparser : public classbase\r {\r       private:\r              /** Used to split on commas\r             */\r            commasepstream* sep;\r           /** Current position in a range of ports\r                */\r            long in_range;\r         /** Starting port in a range of ports\r           */\r            long range_begin;\r              /** Ending port in a range of ports\r             */\r            long range_end;\r                /** Allow overlapped port ranges\r                */\r            bool overlapped;\r               /** Used to determine overlapping of ports\r              * without O(n) algorithm being used\r            */\r            std::map<long, bool> overlap_set;\r              /** Returns true if val overlaps an existing range\r              */\r            bool Overlaps(long val);\r        public:\r               /** Create a portparser and fill it with the provided data\r              * @param source The source text to parse from\r          * @param allow_overlapped Allow overlapped ranges\r              */\r            portparser(const std::string &source, bool allow_overlapped = true);\r           /** Frees the internal commasepstream object\r            */\r            ~portparser();\r         /** Fetch the next token from the stream\r                * @return The next port number is returned, or 0 if none remain\r                */\r            long GetToken();\r       };\r\r    /** Used to hold a bitfield definition in dynamicbitmask.\r       * You must be allocated one of these by dynamicbitmask::Allocate(),\r    * you should not fill the values yourself!\r     */\r    typedef std::pair<size_t, unsigned char> bitfield;\r\r    /** The irc::dynamicbitmask class is used to maintain a bitmap of\r       * boolean values, which can grow to any reasonable size no matter\r      * how many bitfields are in it.\r        *\r      * It starts off at 32 bits in size, large enough to hold 32 boolean\r    * values, with a memory allocation of 8 bytes. If you allocate more\r    * than 32 bits, the class will grow the bitmap by 8 bytes at a time\r    * for each set of 8 bitfields you allocate with the Allocate()\r         * method.\r      *\r      * This method is designed so that multiple modules can be allocated\r    * bit values in a bitmap dynamically, rather than having to define\r     * costs in a fixed size unsigned integer and having the possibility\r    * of collisions of values in different third party modules.\r    *\r      * IMPORTANT NOTE:\r      *\r      * To use this class, you must derive from it.\r  * This is because each derived instance has its own freebits array\r     * which can determine what bitfields are allocated on a TYPE BY TYPE\r   * basis, e.g. an irc::dynamicbitmask type for userrecs, and one for\r    * chanrecs, etc. You should inheret it in a very simple way as follows.\r        * The base class will resize and maintain freebits as required, you are\r        * just required to make the pointer static and specific to this class\r  * type.\r        *\r      * \code\r        * class mydbitmask : public irc::dynamicbitmask\r        * {\r    *  private:\r    *\r      *      static unsigned char* freebits;\r         *\r      *  public:\r     *\r      *      mydbitmask() : irc::dynamicbitmask()\r    *      {\r       *        freebits = new unsigned char[this->bits_size];\r        *        memset(freebits, 0, this->bits_size);\r         *      }\r       *\r      *      ~mydbitmask()\r   *      {\r       *        delete[] freebits;\r    *      }\r       *\r      *      unsigned char* GetFreeBits()\r    *      {\r       *        return freebits;\r      *      }\r       *\r      *      void SetFreeBits(unsigned char* freebt)\r         *      {\r       *        freebits = freebt;\r    *      }\r       * };\r   * \endcode\r     */\r    class CoreExport dynamicbitmask : public classbase\r     {\r       private:\r              /** Data bits. We start with four of these,\r             * and we grow the bitfield as we allocate\r              * more than 32 entries with Allocate().\r                */\r            unsigned char* bits;\r    protected:\r            /** Current set size (size of freebits and bits).\r               * Both freebits and bits will ALWAYS be the\r            * same length.\r                 */\r            unsigned char bits_size;\r        public:\r               /** Allocate the initial memory for bits and\r            * freebits and zero the memory.\r                */\r            dynamicbitmask();\r\r             /** Free the memory used by bits and freebits\r           */\r            virtual ~dynamicbitmask();\r\r            /** Allocate an irc::bitfield.\r          * @return An irc::bitfield which can be used\r           * with Get, Deallocate and Toggle methods.\r             * @throw Can throw std::bad_alloc if there is\r          * no ram left to grow the bitmask.\r             */\r            bitfield Allocate();\r\r          /** Deallocate an irc::bitfield.\r                * @param An irc::bitfield to deallocate.\r               * @return True if the bitfield could be\r                * deallocated, false if it could not.\r          */\r            bool Deallocate(bitfield &pos);\r\r               /** Toggle the value of a bitfield.\r             * @param pos A bitfield to allocate, previously\r                * allocated by dyamicbitmask::Allocate().\r              * @param state The state to set the field to.\r          */\r            void Toggle(bitfield &pos, bool state);\r\r               /** Get the value of a bitfield.\r                * @param pos A bitfield to retrieve, previously\r                * allocated by dyamicbitmask::Allocate().\r              * @return The value of the bitfield.\r           * @throw Will throw ModuleException if the bitfield\r            * you provide is outside of the range\r          * 0 >= bitfield.first < size_bits.\r             */\r            bool Get(bitfield &pos);\r\r              /** Return the size in bytes allocated to the bits\r              * array.\r               * Note that the actual allocation is twice this,\r               * as there are an equal number of bytes allocated\r              * for the freebits array.\r              */\r            unsigned char GetSize();\r\r              /** Get free bits mask\r          */\r            virtual unsigned char* GetFreeBits() { return NULL; }\r\r         /** Set free bits mask\r          */\r            virtual void SetFreeBits(unsigned char* freebits) { }\r  };\r\r    /** Turn _ characters in a string into spaces\r   * @param n String to translate\r         * @return The new value with _ translated to space.\r    */\r    CoreExport const char* Spacify(const char* n);\r}\r\r/* Define operators for using >> and << with irc::string to an ostream on an istream. */\r/* This was endless fun. No. Really. */\r/* It was also the first core change Ommeh made, if anyone cares */\r\r/** Operator << for irc::string\r */\rinline std::ostream& operator<<(std::ostream &os, const irc::string &str) { return os << str.c_str(); }\r\r/** Operator >> for irc::string\r */\rinline std::istream& operator>>(std::istream &is, irc::string &str)\r{\r std::string tmp;\r       is >> tmp;\r     str = tmp.c_str();\r     return is;\r}\r\r/* Define operators for + and == with irc::string to std::string for easy assignment\r * and comparison\r *\r * Operator +\r */\rinline std::string operator+ (std::string& leftval, irc::string& rightval)\r{\r return leftval + std::string(rightval.c_str());\r}\r\r/* Define operators for + and == with irc::string to std::string for easy assignment\r * and comparison\r *\r * Operator +\r */\rinline irc::string operator+ (irc::string& leftval, std::string& rightval)\r{\r    return leftval + irc::string(rightval.c_str());\r}\r\r/* Define operators for + and == with irc::string to std::string for easy assignment\r * and comparison\r *\r * Operator ==\r */\rinline bool operator== (const std::string& leftval, const irc::string& rightval)\r{\r     return (leftval.c_str() == rightval);\r}\r\r/* Define operators for + and == with irc::string to std::string for easy assignment\r * and comparison\r *\r * Operator ==\r */\rinline bool operator== (const irc::string& leftval, const std::string& rightval)\r{\r       return (leftval == rightval.c_str());\r}\r\r/** Assign an irc::string to a std::string.\r */\rinline std::string assign(const irc::string &other) { return other.c_str(); }\r\r/** Assign a std::string to an irc::string.\r */\rinline irc::string assign(const std::string &other) { return other.c_str(); }\r\r/** Trim the leading and trailing spaces from a std::string.\r */\rinline std::string& trim(std::string &str)\r{\r   std::string::size_type start = str.find_first_not_of(" ");\r     std::string::size_type end = str.find_last_not_of(" ");\r        if (start == std::string::npos || end == std::string::npos)\r            str = "";\r      else\r           str = str.substr(start, end-start+1);\r\r return str;\r}\r\r/** Hashing stuff is totally different on vc++'s hash_map implementation, so to save a buttload of\r * #ifdefs we'll just do it all at once\r */\rnamespace nspace\r{\r       /** Hashing function to hash irc::string\r        */\r#ifdef WINDOWS\r     template<> class CoreExport hash_compare<irc::string, std::less<irc::string> >\r {\r      public:\r                enum { bucket_size = 4, min_buckets = 8 }; /* Got these numbers from the CRT source, if anyone wants to change them feel free. */\r\r             /** Compare two irc::string values for hashing in hash_map\r              */\r            bool operator()(const irc::string & s1, const irc::string & s2) const\r          {\r                      if(s1.length() != s2.length()) return true;\r                    return (irc::irc_char_traits::compare(s1.c_str(), s2.c_str(), s1.length()) < 0);\r               }\r              \r               /** Hash an irc::string value for hash_map\r              */\r            size_t operator()(const irc::string & s) const;\r        };\r\r    template<> class CoreExport hash_compare<std::string, std::less<std::string> >\r {\r      public:\r                enum { bucket_size = 4, min_buckets = 8 }; /* Again, from the CRT source */\r\r           /** Compare two std::string values for hashing in hash_map\r              */\r            bool operator()(const std::string & s1, const std::string & s2) const\r          {\r                      if(s1.length() != s2.length()) return true;\r                    return (irc::irc_char_traits::compare(s1.c_str(), s2.c_str(), s1.length()) < 0);\r               }\r              \r               /** Hash a std::string using RFC1459 case sensitivity rules\r            * @param s A string to hash\r            * @return The hash value\r               */\r             size_t operator()(const std::string & s) const;\r        };\r#else\r       template<> struct hash<irc::string>\r    {\r              /** Hash an irc::string using RFC1459 case sensitivity rules\r            * @param s A string to hash\r            * @return The hash value\r               */\r            size_t operator()(const irc::string &s) const;\r };\r\r    template<> struct hash<std::string>\r    {\r              /** Hash a std::string using RFC1459 case sensitivity rules\r            * @param s A string to hash\r            * @return The hash value\r               */\r             size_t operator()(const string &s) const;\r      };\r#endif\r\r     /** Convert a string to lower case respecting RFC1459\r  * @param n A string to lowercase\r       */\r     void strlower(char *n);\r}\r\r#endif\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *         the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef _HASHCOMP_H_
+#define _HASHCOMP_H_
+
+#include "inspircd_config.h"
+#include "socket.h"
+#include "hash_map.h"
+
+/*******************************************************
+ * This file contains classes and templates that deal
+ * with the comparison and hashing of 'irc strings'.
+ * An 'irc string' is a string which compares in a
+ * case insensitive manner, and as per RFC 1459 will
+ * treat [ identical to {, ] identical to }, and \
+ * as identical to |.
+ *
+ * Our hashing functions are designed  to accept
+ * std::string and compare/hash them as type irc::string
+ * by converting them internally. This makes them
+ * backwards compatible with other code which is not
+ * aware of irc::string.
+ *******************************************************/
+
+/** Required namespaces and symbols */
+using namespace std;
+
+/** aton() */
+using irc::sockets::insp_aton;
+
+/** nota() */
+using irc::sockets::insp_ntoa;
+
+#ifndef LOWERMAP
+#define LOWERMAP
+/** A mapping of uppercase to lowercase, including scandinavian
+ * 'oddities' as specified by RFC1459, e.g. { -> [, and | -> \
+ */
+unsigned const char lowermap[256] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,                            /* 0-19 */
+                               20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,                         /* 20-39 */
+                               40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,                         /* 40-59 */
+                               60, 61, 62, 63, 64, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,             /* 60-79 */
+                               112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 94, 95, 96, 97, 98, 99,           /* 80-99 */
+                               100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,     /* 100-119 */
+                               120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139,     /* 120-139 */
+                               140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,     /* 140-159 */
+                               160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179,     /* 160-179 */
+                               180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199,     /* 180-199 */
+                               200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219,     /* 200-219 */
+                               220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,     /* 220-239 */
+                               240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255                          /* 240-255 */
+};
+#endif
+
+/** The irc namespace contains a number of helper classes.
+ */
+namespace irc
+{
+
+       /** This class returns true if two strings match.
+        * Case sensitivity is ignored, and the RFC 'character set'
+        * is adhered to
+        */
+       struct StrHashComp
+       {
+               /** The operator () does the actual comparison in hash_map
+                */
+               bool operator()(const std::string& s1, const std::string& s2) const;
+       };
+
+       /** The irc_char_traits class is used for RFC-style comparison of strings.
+        * This class is used to implement irc::string, a case-insensitive, RFC-
+        * comparing string class.
+        */
+       struct irc_char_traits : std::char_traits<char> {
+
+               /** Check if two chars match.
+                * @param c1st First character
+                * @param c2nd Second character
+                * @return true if the characters are equal
+                */
+               static bool eq(char c1st, char c2nd);
+
+               /** Check if two chars do NOT match.
+                * @param c1st First character
+                * @param c2nd Second character
+                * @return true if the characters are unequal
+                */
+               static bool ne(char c1st, char c2nd);
+
+               /** Check if one char is less than another.
+                * @param c1st First character
+                * @param c2nd Second character
+                * @return true if c1st is less than c2nd
+                */
+               static bool lt(char c1st, char c2nd);
+
+               /** Compare two strings of size n.
+                * @param str1 First string
+                * @param str2 Second string
+                * @param n Length to compare to
+                * @return similar to strcmp, zero for equal, less than zero for str1
+                * being less and greater than zero for str1 being greater than str2.
+                */
+               static CoreExport int compare(const char* str1, const char* str2, size_t n);
+
+               /** Find a char within a string up to position n.
+                * @param s1 String to find in
+                * @param n Position to search up to
+                * @param c Character to search for
+                * @return Pointer to the first occurance of c in s1
+                */
+               static CoreExport const char* find(const char* s1, int  n, char c);
+       };
+
+       /** Compose a hex string from raw data.
+        * @param raw The raw data to compose hex from
+        * @pram rawsz The size of the raw data buffer
+        * @return The hex string.
+        */
+       CoreExport std::string hex(const unsigned char *raw, size_t rawsz);
+
+       /** This typedef declares irc::string based upon irc_char_traits.
+        */
+       typedef basic_string<char, irc_char_traits, allocator<char> > string;
+
+       /** irc::stringjoiner joins string lists into a string, using
+        * the given seperator string.
+        * This class can join a vector of std::string, a deque of
+        * std::string, or a const char** array, using overloaded
+        * constructors.
+        */
+       class CoreExport stringjoiner
+       {
+        private:
+               /** Output string
+                */
+               std::string joined;
+        public:
+               /** Join elements of a vector, between (and including) begin and end
+                * @param seperator The string to seperate values with
+                * @param sequence One or more items to seperate
+                * @param begin The starting element in the sequence to be joined
+                * @param end The ending element in the sequence to be joined
+                */
+               stringjoiner(const std::string &seperator, const std::vector<std::string> &sequence, int begin, int end);
+               /** Join elements of a deque, between (and including) begin and end
+                * @param seperator The string to seperate values with
+                * @param sequence One or more items to seperate
+                * @param begin The starting element in the sequence to be joined
+                * @param end The ending element in the sequence to be joined
+                */
+               stringjoiner(const std::string &seperator, const std::deque<std::string> &sequence, int begin, int end);
+               /** Join elements of an array of char arrays, between (and including) begin and end
+                * @param seperator The string to seperate values with
+                * @param sequence One or more items to seperate
+                * @param begin The starting element in the sequence to be joined
+                * @param end The ending element in the sequence to be joined
+                */
+               stringjoiner(const std::string &seperator, const char** sequence, int begin, int end);
+
+               /** Get the joined sequence
+                * @return A reference to the joined string
+                */
+               std::string& GetJoined();
+       };
+
+       /** irc::modestacker stacks mode sequences into a list.
+        * It can then reproduce this list, clamped to a maximum of MAXMODES
+        * values per line.
+        */
+       class CoreExport modestacker
+       {
+        private:
+               /** The mode sequence and its parameters
+                */
+               std::deque<std::string> sequence;
+               /** True if the mode sequence is initially adding
+                * characters, false if it is initially removing
+                * them
+                */
+               bool adding;
+        public:
+               /** Construct a new modestacker.
+                * @param add True if the stack is adding modes,
+                * false if it is removing them
+                */
+               modestacker(bool add);
+               /** Push a modeletter and its parameter onto the stack.
+                * No checking is performed as to if this mode actually
+                * requires a parameter. If you stack invalid mode
+                * sequences, they will be tidied if and when they are
+                * passed to a mode parser.
+                * @param modeletter The mode letter to insert
+                * @param parameter The parameter for the mode
+                */
+               void Push(char modeletter, const std::string &parameter);
+               /** Push a modeletter without parameter onto the stack.
+                * No checking is performed as to if this mode actually
+                * requires a parameter. If you stack invalid mode
+                * sequences, they will be tidied if and when they are
+                * passed to a mode parser.
+                * @param modeletter The mode letter to insert
+                */
+               void Push(char modeletter);
+               /** Push a '+' symbol onto the stack.
+                */
+               void PushPlus();
+               /** Push a '-' symbol onto the stack.
+                */
+               void PushMinus();
+               /** Return zero or more elements which form the
+                * mode line. This will be clamped to a max of
+                * MAXMODES items (MAXMODES-1 mode parameters and
+                * one mode sequence string), and max_line_size
+                * characters. As specified below, this function
+                * should be called in a loop until it returns zero,
+                * indicating there are no more modes to return.
+                * @param result The deque to populate. This will
+                * be cleared before it is used.
+                * @param max_line_size The maximum size of the line
+                * to build, in characters, seperate to MAXMODES.
+                * @return The number of elements in the deque.
+                * The function should be called repeatedly until it
+                * returns 0, in case there are multiple lines of
+                * mode changes to be obtained.
+                */
+               int GetStackedLine(std::deque<std::string> &result, int max_line_size = 360);
+       };
+
+       /** irc::tokenstream reads a string formatted as per RFC1459 and RFC2812.
+        * It will split the string into 'tokens' each containing one parameter
+        * from the string.
+        * For instance, if it is instantiated with the string:
+        * "PRIVMSG #test :foo bar baz qux"
+        * then each successive call to tokenstream::GetToken() will return
+        * "PRIVMSG", "#test", "foo bar baz qux", "".
+        * Note that if the whole string starts with a colon this is not taken
+        * to mean the string is all one parameter, and the first item in the
+        * list will be ":item". This is to allow for parsing 'source' fields
+        * from data.
+        */
+       class CoreExport tokenstream
+       {
+        private:
+               /** Original string
+                */
+               std::string tokens;
+               /** Last position of a seperator token
+                */
+               std::string::iterator last_starting_position;
+               /** Current string position
+                */
+               std::string::iterator n;
+               /** True if the last value was an ending value
+                */
+               bool last_pushed;
+        public:
+               /** Create a tokenstream and fill it with the provided data
+                */
+               tokenstream(const std::string &source);
+               ~tokenstream();
+
+               /** Fetch the next token from the stream as a std::string
+                * @param token The next token available, or an empty string if none remain
+                * @return True if tokens are left to be read, false if the last token was just retrieved.
+                */
+               bool GetToken(std::string &token);
+
+               /** Fetch the next token from the stream as an irc::string
+                * @param token The next token available, or an empty string if none remain
+                * @return True if tokens are left to be read, false if the last token was just retrieved.
+                */
+               bool GetToken(irc::string &token);
+
+               /** Fetch the next token from the stream as an integer
+                * @param token The next token available, or undefined if none remain
+                * @return True if tokens are left to be read, false if the last token was just retrieved.
+                */
+               bool GetToken(int &token);
+
+               /** Fetch the next token from the stream as a long integer
+                * @param token The next token available, or undefined if none remain
+                * @return True if tokens are left to be read, false if the last token was just retrieved.
+                */
+               bool GetToken(long &token);
+       };
+
+       /** irc::sepstream allows for splitting token seperated lists.
+        * Each successive call to sepstream::GetToken() returns
+        * the next token, until none remain, at which point the method returns
+        * an empty string.
+        */
+       class CoreExport sepstream : public classbase
+       {
+        private:
+               /** Original string.
+                */
+               std::string tokens;
+               /** Last position of a seperator token
+                */
+               std::string::iterator last_starting_position;
+               /** Current string position
+                */
+               std::string::iterator n;
+               /** Seperator value
+                */
+               char sep;
+        public:
+               /** Create a sepstream and fill it with the provided data
+                */
+               sepstream(const std::string &source, char seperator);
+               virtual ~sepstream();
+
+               /** Fetch the next token from the stream
+                * @return The next token is returned, or an empty string if none remain
+                */
+               virtual const std::string GetToken();
+               
+               /** Fetch the entire remaining stream, without tokenizing
+                * @return The remaining part of the stream
+                */
+               virtual const std::string GetRemaining();
+               
+               /** Returns true if the end of the stream has been reached
+                * @return True if the end of the stream has been reached, otherwise false
+                */
+               virtual bool StreamEnd();
+       };
+
+       /** A derived form of sepstream, which seperates on commas
+        */
+       class CoreExport commasepstream : public sepstream
+       {
+        public:
+               /** Initialize with comma seperator
+                */
+               commasepstream(const std::string &source) : sepstream(source, ',')
+               {
+               }
+       };
+
+       /** A derived form of sepstream, which seperates on spaces
+        */
+       class CoreExport spacesepstream : public sepstream
+       {
+        public:
+               /** Initialize with space seperator
+                */
+               spacesepstream(const std::string &source) : sepstream(source, ' ')
+               {
+               }
+       };
+
+       /** The portparser class seperates out a port range into integers.
+        * A port range may be specified in the input string in the form
+        * "6660,6661,6662-6669,7020". The end of the stream is indicated by
+        * a return value of 0 from portparser::GetToken(). If you attempt
+        * to specify an illegal range (e.g. one where start >= end, or
+        * start or end < 0) then GetToken() will return the first element
+        * of the pair of numbers.
+        */
+       class CoreExport portparser : public classbase
+       {
+        private:
+               /** Used to split on commas
+                */
+               commasepstream* sep;
+               /** Current position in a range of ports
+                */
+               long in_range;
+               /** Starting port in a range of ports
+                */
+               long range_begin;
+               /** Ending port in a range of ports
+                */
+               long range_end;
+               /** Allow overlapped port ranges
+                */
+               bool overlapped;
+               /** Used to determine overlapping of ports
+                * without O(n) algorithm being used
+                */
+               std::map<long, bool> overlap_set;
+               /** Returns true if val overlaps an existing range
+                */
+               bool Overlaps(long val);
+        public:
+               /** Create a portparser and fill it with the provided data
+                * @param source The source text to parse from
+                * @param allow_overlapped Allow overlapped ranges
+                */
+               portparser(const std::string &source, bool allow_overlapped = true);
+               /** Frees the internal commasepstream object
+                */
+               ~portparser();
+               /** Fetch the next token from the stream
+                * @return The next port number is returned, or 0 if none remain
+                */
+               long GetToken();
+       };
+
+       /** Used to hold a bitfield definition in dynamicbitmask.
+        * You must be allocated one of these by dynamicbitmask::Allocate(),
+        * you should not fill the values yourself!
+        */
+       typedef std::pair<size_t, unsigned char> bitfield;
+
+       /** The irc::dynamicbitmask class is used to maintain a bitmap of
+        * boolean values, which can grow to any reasonable size no matter
+        * how many bitfields are in it.
+        *
+        * It starts off at 32 bits in size, large enough to hold 32 boolean
+        * values, with a memory allocation of 8 bytes. If you allocate more
+        * than 32 bits, the class will grow the bitmap by 8 bytes at a time
+        * for each set of 8 bitfields you allocate with the Allocate()
+        * method.
+        *
+        * This method is designed so that multiple modules can be allocated
+        * bit values in a bitmap dynamically, rather than having to define
+        * costs in a fixed size unsigned integer and having the possibility
+        * of collisions of values in different third party modules.
+        *
+        * IMPORTANT NOTE:
+        *
+        * To use this class, you must derive from it.
+        * This is because each derived instance has its own freebits array
+        * which can determine what bitfields are allocated on a TYPE BY TYPE
+        * basis, e.g. an irc::dynamicbitmask type for userrecs, and one for
+        * chanrecs, etc. You should inheret it in a very simple way as follows.
+        * The base class will resize and maintain freebits as required, you are
+        * just required to make the pointer static and specific to this class
+        * type.
+        *
+        * \code
+        * class mydbitmask : public irc::dynamicbitmask
+        * {
+        *  private:
+        *
+        *      static unsigned char* freebits;
+        *
+        *  public:
+        *
+        *      mydbitmask() : irc::dynamicbitmask()
+        *      {
+        *        freebits = new unsigned char[this->bits_size];
+        *        memset(freebits, 0, this->bits_size);
+        *      }
+        *
+        *      ~mydbitmask()
+        *      {
+        *        delete[] freebits;
+        *      }
+        *
+        *      unsigned char* GetFreeBits()
+        *      {
+        *        return freebits;
+        *      }
+        *
+        *      void SetFreeBits(unsigned char* freebt)
+        *      {
+        *        freebits = freebt;
+        *      }
+        * };
+        * \endcode
+        */
+       class CoreExport dynamicbitmask : public classbase
+       {
+        private:
+               /** Data bits. We start with four of these,
+                * and we grow the bitfield as we allocate
+                * more than 32 entries with Allocate().
+                */
+               unsigned char* bits;
+        protected:
+               /** Current set size (size of freebits and bits).
+                * Both freebits and bits will ALWAYS be the
+                * same length.
+                */
+               unsigned char bits_size;
+        public:
+               /** Allocate the initial memory for bits and
+                * freebits and zero the memory.
+                */
+               dynamicbitmask();
+
+               /** Free the memory used by bits and freebits
+                */
+               virtual ~dynamicbitmask();
+
+               /** Allocate an irc::bitfield.
+                * @return An irc::bitfield which can be used
+                * with Get, Deallocate and Toggle methods.
+                * @throw Can throw std::bad_alloc if there is
+                * no ram left to grow the bitmask.
+                */
+               bitfield Allocate();
+
+               /** Deallocate an irc::bitfield.
+                * @param An irc::bitfield to deallocate.
+                * @return True if the bitfield could be
+                * deallocated, false if it could not.
+                */
+               bool Deallocate(bitfield &pos);
+
+               /** Toggle the value of a bitfield.
+                * @param pos A bitfield to allocate, previously
+                * allocated by dyamicbitmask::Allocate().
+                * @param state The state to set the field to.
+                */
+               void Toggle(bitfield &pos, bool state);
+
+               /** Get the value of a bitfield.
+                * @param pos A bitfield to retrieve, previously
+                * allocated by dyamicbitmask::Allocate().
+                * @return The value of the bitfield.
+                * @throw Will throw ModuleException if the bitfield
+                * you provide is outside of the range
+                * 0 >= bitfield.first < size_bits.
+                */
+               bool Get(bitfield &pos);
+
+               /** Return the size in bytes allocated to the bits
+                * array.
+                * Note that the actual allocation is twice this,
+                * as there are an equal number of bytes allocated
+                * for the freebits array.
+                */
+               unsigned char GetSize();
+
+               /** Get free bits mask
+                */
+               virtual unsigned char* GetFreeBits() { return NULL; }
+
+               /** Set free bits mask
+                */
+               virtual void SetFreeBits(unsigned char* freebits) { }
+       };
+
+       /** Turn _ characters in a string into spaces
+        * @param n String to translate
+        * @return The new value with _ translated to space.
+        */
+       CoreExport const char* Spacify(const char* n);
+}
+
+/* Define operators for using >> and << with irc::string to an ostream on an istream. */
+/* This was endless fun. No. Really. */
+/* It was also the first core change Ommeh made, if anyone cares */
+
+/** Operator << for irc::string
+ */
+inline std::ostream& operator<<(std::ostream &os, const irc::string &str) { return os << str.c_str(); }
+
+/** Operator >> for irc::string
+ */
+inline std::istream& operator>>(std::istream &is, irc::string &str)
+{
+       std::string tmp;
+       is >> tmp;
+       str = tmp.c_str();
+       return is;
+}
+
+/* Define operators for + and == with irc::string to std::string for easy assignment
+ * and comparison
+ *
+ * Operator +
+ */
+inline std::string operator+ (std::string& leftval, irc::string& rightval)
+{
+       return leftval + std::string(rightval.c_str());
+}
+
+/* Define operators for + and == with irc::string to std::string for easy assignment
+ * and comparison
+ *
+ * Operator +
+ */
+inline irc::string operator+ (irc::string& leftval, std::string& rightval)
+{
+       return leftval + irc::string(rightval.c_str());
+}
+
+/* Define operators for + and == with irc::string to std::string for easy assignment
+ * and comparison
+ *
+ * Operator ==
+ */
+inline bool operator== (const std::string& leftval, const irc::string& rightval)
+{
+       return (leftval.c_str() == rightval);
+}
+
+/* Define operators for + and == with irc::string to std::string for easy assignment
+ * and comparison
+ *
+ * Operator ==
+ */
+inline bool operator== (const irc::string& leftval, const std::string& rightval)
+{
+       return (leftval == rightval.c_str());
+}
+
+/** Assign an irc::string to a std::string.
+ */
+inline std::string assign(const irc::string &other) { return other.c_str(); }
+
+/** Assign a std::string to an irc::string.
+ */
+inline irc::string assign(const std::string &other) { return other.c_str(); }
+
+/** Trim the leading and trailing spaces from a std::string.
+ */
+inline std::string& trim(std::string &str)
+{
+       std::string::size_type start = str.find_first_not_of(" ");
+       std::string::size_type end = str.find_last_not_of(" ");
+       if (start == std::string::npos || end == std::string::npos)
+               str = "";
+       else
+               str = str.substr(start, end-start+1);
+
+       return str;
+}
+
+/** Hashing stuff is totally different on vc++'s hash_map implementation, so to save a buttload of
+ * #ifdefs we'll just do it all at once
+ */
+namespace nspace
+{
+       /** Hashing function to hash irc::string
+        */
+#ifdef WINDOWS
+       template<> class CoreExport hash_compare<irc::string, std::less<irc::string> >
+       {
+       public:
+               enum { bucket_size = 4, min_buckets = 8 }; /* Got these numbers from the CRT source, if anyone wants to change them feel free. */
+
+               /** Compare two irc::string values for hashing in hash_map
+                */
+               bool operator()(const irc::string & s1, const irc::string & s2) const
+               {
+                       if(s1.length() != s2.length()) return true;
+                       return (irc::irc_char_traits::compare(s1.c_str(), s2.c_str(), s1.length()) < 0);
+               }
+               
+               /** Hash an irc::string value for hash_map
+                */
+               size_t operator()(const irc::string & s) const;
+       };
+
+       template<> class CoreExport hash_compare<std::string, std::less<std::string> >
+       {
+       public:
+               enum { bucket_size = 4, min_buckets = 8 }; /* Again, from the CRT source */
+
+               /** Compare two std::string values for hashing in hash_map
+                */
+               bool operator()(const std::string & s1, const std::string & s2) const
+               {
+                       if(s1.length() != s2.length()) return true;
+                       return (irc::irc_char_traits::compare(s1.c_str(), s2.c_str(), s1.length()) < 0);
+               }
+               
+               /** Hash a std::string using RFC1459 case sensitivity rules
+               * @param s A string to hash
+               * @return The hash value
+               */
+               size_t operator()(const std::string & s) const;
+       };
+#else
+       template<> struct hash<irc::string>
+       {
+               /** Hash an irc::string using RFC1459 case sensitivity rules
+                * @param s A string to hash
+                * @return The hash value
+                */
+               size_t operator()(const irc::string &s) const;
+       };
+
+       template<> struct hash<std::string>
+       {
+               /** Hash a std::string using RFC1459 case sensitivity rules
+               * @param s A string to hash
+               * @return The hash value
+               */
+               size_t operator()(const string &s) const;
+       };
+#endif
+
+       /** Convert a string to lower case respecting RFC1459
+       * @param n A string to lowercase
+       */
+       void strlower(char *n);
+}
+
+#endif
+
index 378ca4ec1c964904d69fe8cb2efd4b81029c457d..c3f8ed328321c3be9fa40c35779b3a240a6a7b0e 100644 (file)
@@ -1 +1,1279 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *        the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __INSPIRCD_H__\r#define __INSPIRCD_H__\r\r#ifndef WIN32\r#define DllExport \r#define CoreExport \r#define printf_c printf\r#else\r#include "inspircd_win32wrapper.h"\r/** Windows defines these already */\r#undef DELETE\r#undef ERROR\r#endif\r\r#include <time.h>\r#include <string>\r#include <sstream>\r#include "inspircd_config.h"\r#include "users.h"\r#include "channels.h"\r#include "socket.h"\r#include "mode.h"\r#include "socketengine.h"\r#include "command_parse.h"\r#include "snomasks.h"\r#include "cull_list.h"\r\r/** Returned by some functions to indicate failure.\r */\r#define ERROR -1\r\r/** Support for librodent -\r * see http://www.chatspike.net/index.php?z=64\r */\r#define ETIREDHAMSTERS EAGAIN\r\r/** Debug levels for use with InspIRCd::Log()\r */\renum DebugLevel\r{\r        DEBUG           =       10,\r    VERBOSE         =       20,\r    DEFAULT         =       30,\r    SPARSE          =       40,\r    NONE            =       50\r};\r\r/**\r * This define is used in place of strcmp when we\r * want to check if a char* string contains only one\r * letter. Pretty fast, its just two compares and an\r * addition.\r */\r#define IS_SINGLE(x,y) ( (*x == y) && (*(x+1) == 0) )\r\r/** Delete a pointer, and NULL its value\r */\rtemplate<typename T> inline void DELETE(T* x)\r{\r    delete x;\r      x = NULL;\r}\r\r/** Template function to convert any input type to std::string\r */\rtemplate<typename T> inline std::string ConvNumeric(const T &in)\r{\r     if (in == 0) return "0";\r       char res[MAXBUF];\r      char* out = res;\r       T quotient = in;\r       while (quotient) {\r             *out = "0123456789"[ std::abs( (long)quotient % 10 ) ];\r                ++out;\r         quotient /= 10;\r        }\r      if ( in < 0)\r           *out++ = '-';\r  *out = 0;\r      std::reverse(res,out);\r return res;\r}\r\r/** Template function to convert any input type to std::string\r */\rinline std::string ConvToStr(const int in)\r{\r return ConvNumeric(in);\r}\r\r/** Template function to convert any input type to std::string\r */\rinline std::string ConvToStr(const long in)\r{\r    return ConvNumeric(in);\r}\r\r/** Template function to convert any input type to std::string\r */\rinline std::string ConvToStr(const unsigned long in)\r{\r   return ConvNumeric(in);\r}\r\r/** Template function to convert any input type to std::string\r */\rinline std::string ConvToStr(const char* in)\r{\r   return in;\r}\r\r/** Template function to convert any input type to std::string\r */\rinline std::string ConvToStr(const bool in)\r{\r return (in ? "1" : "0");\r}\r\r/** Template function to convert any input type to std::string\r */\rinline std::string ConvToStr(char in)\r{\r return std::string(in,1);\r}\r\r/** Template function to convert any input type to std::string\r */\rtemplate <class T> inline std::string ConvToStr(const T &in)\r{\r std::stringstream tmp;\r if (!(tmp << in)) return std::string();\r        return tmp.str();\r}\r\r/** Template function to convert any input type to any other type\r * (usually an integer or numeric type)\r */\rtemplate<typename T> inline long ConvToInt(const T &in)\r{\r   std::stringstream tmp;\r if (!(tmp << in)) return 0;\r    return atoi(tmp.str().c_str());\r}\r\r/** Template function to convert integer to char, storing result in *res and\r * also returning the pointer to res. Based on Stuart Lowe's C/C++ Pages.\r * @param T input value\r * @param V result value\r * @param R base to convert to\r */\rtemplate<typename T, typename V, typename R> inline char* itoa(const T &in, V *res, R base)\r{\r    if (base < 2 || base > 16) { *res = 0; return res; }\r   char* out = res;\r       int quotient = in;\r     while (quotient) {\r             *out = "0123456789abcdef"[ std::abs( quotient % base ) ];\r              ++out;\r         quotient /= base;\r      }\r      if ( in < 0 && base == 10) *out++ = '-';\r       std::reverse( res, out );\r      *out = 0;\r      return res;\r}\r\r/** This class contains various STATS counters\r * It is used by the InspIRCd class, which internally\r * has an instance of it.\r */\rclass serverstats : public classbase\r{\r  public:\r     /** Number of accepted connections\r      */\r    unsigned long statsAccept;\r     /** Number of failed accepts\r    */\r    unsigned long statsRefused;\r    /** Number of unknown commands seen\r     */\r    unsigned long statsUnknown;\r    /** Number of nickname collisions handled\r       */\r    unsigned long statsCollisions;\r /** Number of DNS queries sent out\r      */\r    unsigned long statsDns;\r        /** Number of good DNS replies received\r         * NOTE: This may not tally to the number sent out,\r     * due to timeouts and other latency issues.\r    */\r    unsigned long statsDnsGood;\r    /** Number of bad (negative) DNS replies received\r       * NOTE: This may not tally to the number sent out,\r     * due to timeouts and other latency issues.\r    */\r    unsigned long statsDnsBad;\r     /** Number of inbound connections seen\r  */\r    unsigned long statsConnects;\r   /** Total bytes of data transmitted\r     */\r    double statsSent;\r      /** Total bytes of data received\r        */\r    double statsRecv;\r      /** Cpu usage at last sample\r    */\r    timeval LastCPU;\r       /** Time last sample was read\r   */\r    timeval LastSampled;\r   /** The constructor initializes all the counts to zero\r  */\r    serverstats()\r          : statsAccept(0), statsRefused(0), statsUnknown(0), statsCollisions(0), statsDns(0),\r           statsDnsGood(0), statsDnsBad(0), statsConnects(0), statsSent(0.0), statsRecv(0.0)\r      {\r      }\r};\r\r/* Forward declaration -- required */\rclass InspIRCd;\r\r/** This class implements a nonblocking log-writer.\r * Most people writing an ircd give little thought to their disk\r * i/o. On a congested system, disk writes can block for long\r * periods of time (e.g. if the system is busy and/or swapping\r * a lot). If we just use a blocking fprintf() call, this could\r * block for undesirable amounts of time (half of a second through\r * to whole seconds). We DO NOT want this, so we make our logfile\r * nonblocking and hook it into the SocketEngine.\r * NB: If the operating system does not support nonblocking file\r * I/O (linux seems to, as does freebsd) this will default to\r * blocking behaviour.\r */\rclass CoreExport FileLogger : public EventHandler\r{\r protected:\r        /** The creator/owner of this object\r    */\r    InspIRCd* ServerInstance;\r      /** The log file (fd is inside this somewhere,\r  * we get it out with fileno())\r         */\r    FILE* log;\r     /** Buffer of pending log lines to be written\r   */\r    std::string buffer;\r    /** Number of write operations that have occured\r        */\r    int writeops;\r public:\r /** The constructor takes an already opened logfile.\r    */\r    FileLogger(InspIRCd* Instance, FILE* logfile);\r /** This returns false, logfiles are writeable.\r         */\r    virtual bool Readable();\r       /** Handle pending write events.\r        * This will flush any waiting data to disk.\r    * If any data remains after the fprintf call,\r  * another write event is scheduled to write\r    * the rest of the data when possible.\r  */\r    virtual void HandleEvent(EventType et, int errornum = 0);\r      /** Write one or more preformatted log lines.\r   * If the data cannot be written immediately,\r   * this class will insert itself into the\r       * SocketEngine, and register a write event,\r    * and when the write event occurs it will\r      * attempt again to write the data.\r     */\r    void WriteLogLine(const std::string &line);\r    /** Close the log file and cancel any events.\r   */\r    virtual void Close();\r  /** Close the log file and cancel any events.\r   * (indirectly call Close()\r     */\r    virtual ~FileLogger();\r};\r\r/** A list of failed port bindings, used for informational purposes on startup */\rtypedef std::vector<std::pair<std::string, long> > FailedPortList;\r\r/** A list of ip addresses cross referenced against clone counts */\rtypedef std::map<irc::string, unsigned int> clonemap;\r\r/* Forward declaration - required */\rclass XLineManager;\r\r/** The main class of the irc server.\r * This class contains instances of all the other classes\r * in this software, with the exception of the base class,\r * classbase. Amongst other things, it contains a ModeParser,\r * a DNS object, a CommandParser object, and a list of active\r * Module objects, and facilities for Module objects to\r * interact with the core system it implements. You should\r * NEVER attempt to instantiate a class of type InspIRCd\r * yourself. If you do, this is equivalent to spawning a second\r * IRC server, and could have catastrophic consequences for the\r * program in terms of ram usage (basically, you could create\r * an obese forkbomb built from recursively spawning irc servers!)\r */\rclass CoreExport InspIRCd : public classbase\r{\r private:\r /** Holds a string describing the last module error to occur\r    */\r    char MODERR[MAXBUF];\r\r  /** Remove a ModuleFactory pointer\r      * @param j Index number of the ModuleFactory to remove\r         */\r    void EraseFactory(int j);\r\r     /** Remove a Module pointer\r     * @param j Index number of the Module to remove\r        */\r    void EraseModule(int j);\r\r      /** Move a given module to a specific slot in the list\r  * @param modulename The module name to relocate\r        * @param slot The slot to move the module into\r         */\r    void MoveTo(std::string modulename,int slot);\r\r /** Display the startup banner\r  */\r    void Start();\r\r /** Set up the signal handlers\r  */\r    void SetSignals();\r\r    /** Daemonize the ircd and close standard input/output streams\r  * @return True if the program daemonized succesfully\r   */\r    bool DaemonSeed();\r\r    /** Moves the given module to the last slot in the list\r         * @param modulename The module name to relocate\r        */\r    void MoveToLast(std::string modulename);\r\r      /** Moves the given module to the first slot in the list\r        * @param modulename The module name to relocate\r        */\r    void MoveToFirst(std::string modulename);\r\r     /** Moves one module to be placed after another in the list\r     * @param modulename The module name to relocate\r        * @param after The module name to place the module after\r       */\r    void MoveAfter(std::string modulename, std::string after);\r\r    /** Moves one module to be placed before another in the list\r    * @param modulename The module name to relocate\r        * @param after The module name to place the module before\r      */\r    void MoveBefore(std::string modulename, std::string before);\r\r  /** Iterate the list of InspSocket objects, removing ones which have timed out\r  * @param TIME the current time\r         */\r    void DoSocketTimeouts(time_t TIME);\r\r   /** Perform background user events such as PING checks\r  * @param TIME the current time\r         */\r    void DoBackgroundUserStuff(time_t TIME);\r\r      /** Returns true when all modules have done pre-registration checks on a user\r   * @param user The user to verify\r       * @return True if all modules have finished checking this user\r         */\r    bool AllModulesReportReady(userrec* user);\r\r    /** Total number of modules loaded into the ircd, minus one\r     */\r    int ModCount;\r\r /** Logfile pathname specified on the commandline, or empty string\r      */\r    char LogFileName[MAXBUF];\r\r     /** The feature names published by various modules\r      */\r    featurelist Features;\r\r /** The interface names published by various modules\r    */\r    interfacelist Interfaces;\r\r     /** The current time, updated in the mainloop\r   */\r    time_t TIME;\r\r  /** The time that was recorded last time around the mainloop\r    */\r    time_t OLDTIME;\r\r       /** A 64k buffer used to read client lines into\r         */\r    char ReadBuffer[65535];\r\r       /** Used when connecting clients\r        */\r    insp_sockaddr client, server;\r\r /** Used when connecting clients\r        */\r    socklen_t length;\r\r     /** Nonblocking file writer\r     */\r    FileLogger* Logger;\r\r   /** Time offset in seconds\r      * This offset is added to all calls to Time(). Use SetTimeDelta() to update\r    */\r    int time_delta;\r\r public:\r\r     /** InspSocket classes pending deletion after being closed.\r     * We don't delete these immediately as this may cause a segmentation fault.\r    */\r    std::map<InspSocket*,InspSocket*> SocketCull;\r\r /** Build the ISUPPORT string by triggering all modules On005Numeric events\r     */\r    void BuildISupport();\r\r /** Number of unregistered users online right now.\r      * (Unregistered means before USER/NICK/dns)\r    */\r    int unregistered_count;\r\r       /** List of server names we've seen.\r    */\r    servernamelist servernames;\r\r   /** Time this ircd was booted\r   */\r    time_t startup_time;\r\r  /** Config file pathname specified on the commandline or via ./configure\r        */\r    char ConfigFileName[MAXBUF];\r\r  /** Mode handler, handles mode setting and removal\r      */\r    ModeParser* Modes;\r\r    /** Command parser, handles client to server commands\r   */\r    CommandParser* Parser;\r\r        /** Socket engine, handles socket activity events\r       */\r    SocketEngine* SE;\r\r     /** Stats class, holds miscellaneous stats counters\r     */\r    serverstats* stats;\r\r   /**  Server Config class, holds configuration file data\r         */\r    ServerConfig* Config;\r\r /** Snomask manager - handles routing of snomask messages\r       * to opers.\r    */\r    SnomaskManager* SNO;\r\r  /** Client list, a hash_map containing all clients, local and remote\r    */\r    user_hash* clientlist;\r\r        /** Channel list, a hash_map containing all channels\r    */\r    chan_hash* chanlist;\r\r  /** Local client list, a vector containing only local clients\r   */\r    std::vector<userrec*> local_users;\r\r    /** Oper list, a vector containing all local and remote opered users\r    */\r    std::vector<userrec*> all_opers;\r\r      /** Map of local ip addresses for clone counting\r        */\r    clonemap local_clones;\r\r        /** Map of global ip addresses for clone counting\r       */\r    clonemap global_clones;\r\r       /** DNS class, provides resolver facilities to the core and modules\r     */\r    DNS* Res;\r\r     /** Timer manager class, triggers InspTimer timer events\r        */\r    TimerManager* Timers;\r\r /** X-Line manager. Handles G/K/Q/E line setting, removal and matching\r  */\r    XLineManager* XLines;\r\r /** A list of Module* module classes\r    * Note that this list is always exactly 255 in size.\r   * The actual number of loaded modules is available from GetModuleCount()\r       */\r    ModuleList modules;\r\r   /** A list of ModuleFactory* module factories\r   * Note that this list is always exactly 255 in size.\r   * The actual number of loaded modules is available from GetModuleCount()\r       */\r    FactoryList factory;\r\r  /** The time we next call our ping timeout and reg timeout checks\r       */\r    time_t next_call;\r\r     /** Global cull list, will be processed on next iteration\r       */\r    CullList GlobalCulls;\r\r /** Get the current time\r        * Because this only calls time() once every time around the mainloop,\r  * it is much faster than calling time() directly.\r      * @param delta True to use the delta as an offset, false otherwise\r     * @return The current time as an epoch value (time_t)\r  */\r    time_t Time(bool delta = false);\r\r      /** Set the time offset in seconds\r      * This offset is added to Time() to offset the system time by the specified\r    * number of seconds.\r   * @param delta The number of seconds to offset\r         * @return The old time delta\r   */\r    int SetTimeDelta(int delta);\r\r  /** Add a user to the local clone map\r   * @param user The user to add\r  */\r    void AddLocalClone(userrec* user);\r\r    /** Add a user to the global clone map\r  * @param user The user to add\r  */\r    void AddGlobalClone(userrec* user);\r\r   /** Number of users with a certain mode set on them\r     */\r    int ModeCount(const char mode);\r\r       /** Get the time offset in seconds\r      * @return The current time delta (in seconds)\r  */\r    int GetTimeDelta();\r\r   /** Process a user whos socket has been flagged as active\r       * @param cu The user to process\r        * @return There is no actual return value, however upon exit, the user 'cu' may have been\r      * marked for deletion in the global CullList.\r  */\r    void ProcessUser(userrec* cu);\r\r        /** Get the total number of currently loaded modules\r    * @return The number of loaded modules\r         */\r    int GetModuleCount();\r\r /** Find a module by name, and return a Module* to it.\r  * This is preferred over iterating the module lists yourself.\r  * @param name The module name to look up\r       * @return A pointer to the module, or NULL if the module cannot be found\r       */\r    Module* FindModule(const std::string &name);\r\r  /** Bind all ports specified in the configuration file.\r         * @param bail True if the function should bail back to the shell on failure\r    * @param found_ports The actual number of ports found in the config, as opposed to the number actually bound\r   * @return The number of ports actually bound without error\r     */\r    int BindPorts(bool bail, int &found_ports, FailedPortList &failed_ports);\r\r     /** Binds a socket on an already open file descriptor\r   * @param sockfd A valid file descriptor of an open socket\r      * @param port The port number to bind to\r       * @param addr The address to bind to (IP only)\r         * @return True if the port was bound successfully\r      */\r    bool BindSocket(int sockfd, int port, char* addr, bool dolisten = true);\r\r      /** Adds a server name to the list of servers we've seen\r        * @param The servername to add\r         */\r    void AddServerName(const std::string &servername);\r\r    /** Finds a cached char* pointer of a server name,\r      * This is used to optimize userrec by storing only the pointer to the name\r     * @param The servername to find\r        * @return A pointer to this name, gauranteed to never become invalid\r   */\r    const char* FindServerNamePtr(const std::string &servername);\r\r /** Returns true if we've seen the given server name before\r     * @param The servername to find\r        * @return True if we've seen this server name before\r   */\r    bool FindServerName(const std::string &servername);\r\r   /** Gets the GECOS (description) field of the given server.\r     * If the servername is not that of the local server, the name\r  * is passed to handling modules which will attempt to determine\r        * the GECOS that bleongs to the given servername.\r      * @param servername The servername to find the description of\r  * @return The description of this server, or of the local server\r       */\r    std::string GetServerDescription(const char* servername);\r\r     /** Write text to all opers connected to this server\r    * @param text The text format string\r   * @param ... Format args\r       */\r    void WriteOpers(const char* text, ...);\r\r       /** Write text to all opers connected to this server\r    * @param text The text to send\r         */\r    void WriteOpers(const std::string &text);\r\r     /** Find a nickname in the nick hash\r    * @param nick The nickname to find\r     * @return A pointer to the user, or NULL if the user does not exist\r    */\r    userrec* FindNick(const std::string &nick);\r\r   /** Find a nickname in the nick hash\r    * @param nick The nickname to find\r     * @return A pointer to the user, or NULL if the user does not exist\r    */\r    userrec* FindNick(const char* nick);\r\r  /** Find a channel in the channels hash\r         * @param chan The channel to find\r      * @return A pointer to the channel, or NULL if the channel does not exist\r      */\r    chanrec* FindChan(const std::string &chan);\r\r   /** Find a channel in the channels hash\r         * @param chan The channel to find\r      * @return A pointer to the channel, or NULL if the channel does not exist\r      */\r    chanrec* FindChan(const char* chan);\r\r  /** Called by the constructor to load all modules from the config file.\r         */\r    void LoadAllModules();\r\r        /** Check for a 'die' tag in the config file, and abort if found\r        * @return Depending on the configuration, this function may never return\r       */\r    void CheckDie();\r\r      /** Check we aren't running as root, and exit if we are\r         * @return Depending on the configuration, this function may never return\r       */\r    void CheckRoot();\r\r     /** Determine the right path for, and open, the logfile\r         * @param argv The argv passed to main() initially, used to calculate program path\r      * @param argc The argc passed to main() initially, used to calculate program path\r      */\r    void OpenLog(char** argv, int argc);\r\r  /** Close the currently open log file\r   */\r    void CloseLog();\r\r      /** Send a server notice to all local users\r     * @param text The text format string to send\r   * @param ... The format arguments\r      */\r    void ServerNoticeAll(char* text, ...);\r\r        /** Send a server message (PRIVMSG) to all local users\r  * @param text The text format string to send\r   * @param ... The format arguments\r      */\r    void ServerPrivmsgAll(char* text, ...);\r\r       /** Send text to all users with a specific set of modes\r         * @param modes The modes to check against, without a +, e.g. 'og'\r      * @param flags one of WM_OR or WM_AND. If you specify WM_OR, any one of the\r    * mode characters in the first parameter causes receipt of the message, and\r    * if you specify WM_OR, all the modes must be present.\r         * @param text The text format string to send\r   * @param ... The format arguments\r      */\r    void WriteMode(const char* modes, int flags, const char* text, ...);\r\r  /** Return true if a channel name is valid\r      * @param chname A channel name to verify\r       * @return True if the name is valid\r    */\r    bool IsChannel(const char *chname);\r\r   /** Rehash the local server\r     * @param status This value is unused, and required for signal handler functions\r        */\r    static void Rehash(int status);\r\r       /** Causes the server to exit after unloading modules and\r       * closing all open file descriptors.\r   *\r      * @param The exit code to give to the operating system\r         * (See the ExitStatus enum for valid values)\r   */\r    static void Exit(int status);\r\r /** Causes the server to exit immediately with exit code 0.\r     * The status code is required for signal handlers, and ignored.\r        */\r    static void QuickExit(int status);\r\r    /** Return a count of users, unknown and known connections\r      * @return The number of users\r  */\r    int UserCount();\r\r      /** Return a count of fully registered connections only\r         * @return The number of registered users\r       */\r    int RegisteredUserCount();\r\r    /** Return a count of invisible (umode +i) users only\r   * @return The number of invisible users\r        */\r    int InvisibleUserCount();\r\r     /** Return a count of opered (umode +o) users only\r      * @return The number of opers\r  */\r    int OperCount();\r\r      /** Return a count of unregistered (before NICK/USER) users only\r        * @return The number of unregistered (unknown) connections\r     */\r    int UnregisteredUserCount();\r\r  /** Return a count of channels on the network\r   * @return The number of channels\r       */\r    long ChannelCount();\r\r  /** Return a count of local users on this server only\r   * @return The number of local users\r    */\r    long LocalUserCount();\r\r        /** Send an error notice to all local users, opered and unopered\r        * @param s The error string to send\r    */\r    void SendError(const std::string &s);\r\r /** For use with Module::Prioritize().\r  * When the return value of this function is returned from\r      * Module::Prioritize(), this specifies that the module wishes\r  * to be ordered exactly BEFORE 'modulename'. For more information\r      * please see Module::Prioritize().\r     * @param modulename The module your module wants to be before in the call list\r         * @returns a priority ID which the core uses to relocate the module in the list\r        */\r    long PriorityBefore(const std::string &modulename);\r\r   /** For use with Module::Prioritize().\r  * When the return value of this function is returned from\r      * Module::Prioritize(), this specifies that the module wishes\r  * to be ordered exactly AFTER 'modulename'. For more information please\r        * see Module::Prioritize().\r    * @param modulename The module your module wants to be after in the call list\r  * @returns a priority ID which the core uses to relocate the module in the list\r        */\r    long PriorityAfter(const std::string &modulename);\r\r    /** Publish a 'feature'.\r        * There are two ways for a module to find another module it depends on.\r        * Either by name, using InspIRCd::FindModule, or by feature, using this\r        * function. A feature is an arbitary string which identifies something this\r    * module can do. For example, if your module provides SSL support, but other\r   * modules provide SSL support too, all the modules supporting SSL should\r       * publish an identical 'SSL' feature. This way, any module requiring use\r       * of SSL functions can just look up the 'SSL' feature using FindFeature,\r       * then use the module pointer they are given.\r  * @param FeatureName The case sensitive feature name to make available\r         * @param Mod a pointer to your module class\r    * @returns True on success, false if the feature is already published by\r       * another module.\r      */\r    bool PublishFeature(const std::string &FeatureName, Module* Mod);\r\r     /** Publish a module to an 'interface'.\r         * Modules which implement the same interface (the same way of communicating\r    * with other modules) can publish themselves to an interface, using this\r       * method. When they do so, they become part of a list of related or\r    * compatible modules, and a third module may then query for that list\r  * and know that all modules within that list offer the same API.\r       * A prime example of this is the hashing modules, which all accept the\r         * same types of Request class. Consider this to be similar to PublishFeature,\r  * except for that multiple modules may publish the same 'feature'.\r     * @param InterfaceName The case sensitive interface name to make available\r     * @param Mod a pointer to your module class\r    * @returns True on success, false on failure (there are currently no failure\r   * cases)\r       */\r    bool PublishInterface(const std::string &InterfaceName, Module* Mod);\r\r /** Return a pair saying how many other modules are currently using the\r         * interfaces provided by module m.\r     * @param m The module to count usage for\r       * @return A pair, where the first value is the number of uses of the interface,\r        * and the second value is the interface name being used.\r       */\r    std::pair<int,std::string> GetInterfaceInstanceCount(Module* m);\r\r      /** Mark your module as using an interface.\r     * If you mark your module as using an interface, then that interface\r   * module may not unload until your module has unloaded first.\r  * This can be used to prevent crashes by ensuring code you depend on\r   * is always in memory while your module is active.\r     * @param InterfaceName The interface to use\r    */\r    void UseInterface(const std::string &InterfaceName);\r\r  /** Mark your module as finished with an interface.\r     * If you used UseInterface() above, you should use this method when\r    * your module is finished with the interface (usually in its destructor)\r       * to allow the modules which implement the given interface to be unloaded.\r     * @param InterfaceName The interface you are finished with using.\r      */\r    void DoneWithInterface(const std::string &InterfaceName);\r\r     /** Unpublish a 'feature'.\r      * When your module exits, it must call this method for every feature it\r        * is providing so that the feature table is cleaned up.\r        * @param FeatureName the feature to remove\r     */\r    bool UnpublishFeature(const std::string &FeatureName);\r\r        /** Unpublish your module from an interface\r     * When your module exits, it must call this method for every interface\r         * it is part of so that the interfaces table is cleaned up. Only when\r  * the last item is deleted from an interface does the interface get\r    * removed.\r     * @param InterfaceName the interface to be removed from\r        * @param Mod The module to remove from the interface list\r      */\r    bool UnpublishInterface(const std::string &InterfaceName, Module* Mod);\r\r       /** Find a 'feature'.\r   * There are two ways for a module to find another module it depends on.\r        * Either by name, using InspIRCd::FindModule, or by feature, using the\r         * InspIRCd::PublishFeature method. A feature is an arbitary string which\r       * identifies something this module can do. For example, if your module\r         * provides SSL support, but other modules provide SSL support too, all\r         * the modules supporting SSL should publish an identical 'SSL' feature.\r        * To find a module capable of providing the feature you want, simply\r   * call this method with the feature name you are looking for.\r  * @param FeatureName The feature name you wish to obtain the module for\r        * @returns A pointer to a valid module class on success, NULL on failure.\r      */\r    Module* FindFeature(const std::string &FeatureName);\r\r  /** Find an 'interface'.\r        * An interface is a list of modules which all implement the same API.\r  * @param InterfaceName The Interface you wish to obtain the module\r     * list of.\r     * @return A pointer to a deque of Module*, or NULL if the interface\r    * does not exist.\r      */\r    modulelist* FindInterface(const std::string &InterfaceName);\r\r  /** Given a pointer to a Module, return its filename\r    * @param m The module pointer to identify\r      * @return The module name or an empty string\r   */\r    const std::string& GetModuleName(Module* m);\r\r  /** Return true if a nickname is valid\r  * @param n A nickname to verify\r        * @return True if the nick is valid\r    */\r    bool IsNick(const char* n);\r\r   /** Return true if an ident is valid\r    * @param An ident to verify\r    * @return True if the ident is valid\r   */\r    bool IsIdent(const char* n);\r\r  /** Find a username by their file descriptor.\r   * It is preferred to use this over directly accessing the fd_ref_table array.\r  * @param socket The file descriptor of a user\r  * @return A pointer to the user if the user exists locally on this descriptor\r  */\r    userrec* FindDescriptor(int socket);\r\r  /** Add a new mode to this server's mode parser\r         * @param mh The modehandler to add\r     * @param modechar The mode character this modehandler handles\r  * @return True if the mode handler was added\r   */\r    bool AddMode(ModeHandler* mh, const unsigned char modechar);\r\r  /** Add a new mode watcher to this server's mode parser\r         * @param mw The modewatcher to add\r     * @return True if the modewatcher was added\r    */\r    bool AddModeWatcher(ModeWatcher* mw);\r\r /** Delete a mode watcher from this server's mode parser\r        * @param mw The modewatcher to delete\r  * @return True if the modewatcher was deleted\r  */\r    bool DelModeWatcher(ModeWatcher* mw);\r\r /** Add a dns Resolver class to this server's active set\r        * @param r The resolver to add\r         * @param cached If this value is true, then the cache will\r     * be searched for the DNS result, immediately. If the value is\r         * false, then a request will be sent to the nameserver, and the\r        * result will not be immediately available. You should usually\r         * use the boolean value which you passed to the Resolver\r       * constructor, which Resolver will set appropriately depending\r         * on if cached results are available and haven't expired. It is\r        * however safe to force this value to false, forcing a remote DNS\r      * lookup, but not an update of the cache.\r      * @return True if the operation completed successfully. Note that\r      * if this method returns true, you should not attempt to access\r        * the resolver class you pass it after this call, as depending upon\r    * the request given, the object may be deleted!\r        */\r    bool AddResolver(Resolver* r, bool cached);\r\r   /** Add a command to this server's command parser\r       * @param f A command_t command handler object to add\r   * @throw ModuleException Will throw ModuleExcption if the command already exists\r       */\r    void AddCommand(command_t *f);\r\r        /** Send a modechange.\r  * The parameters provided are identical to that sent to the\r    * handler for class cmd_mode.\r  * @param parameters The mode parameters\r        * @param pcnt The number of items you have given in the first parameter\r        * @param user The user to send error messages to\r       */\r    void SendMode(const char **parameters, int pcnt, userrec *user);\r\r      /** Match two strings using pattern matching.\r   * This operates identically to the global function match(),\r    * except for that it takes std::string arguments rather than\r   * const char* ones.\r    * @param sliteral The literal string to match against\r  * @param spattern The pattern to match against. CIDR and globs are supported.\r  */\r    bool MatchText(const std::string &sliteral, const std::string &spattern);\r\r     /** Call the handler for a given command.\r       * @param commandname The command whos handler you wish to call\r         * @param parameters The mode parameters\r        * @param pcnt The number of items you have given in the first parameter\r        * @param user The user to execute the command as\r       * @return True if the command handler was called successfully\r  */\r    CmdResult CallCommandHandler(const std::string &commandname, const char** parameters, int pcnt, userrec* user);\r\r       /** Return true if the command is a module-implemented command and the given parameters are valid for it\r        * @param parameters The mode parameters\r        * @param pcnt The number of items you have given in the first parameter\r        * @param user The user to test-execute the command as\r  * @return True if the command handler is a module command, and there are enough parameters and the user has permission to the command\r  */\r    bool IsValidModuleCommand(const std::string &commandname, int pcnt, userrec* user);\r\r   /** Add a gline and apply it\r    * @param duration How long the line should last\r        * @param source Who set the line\r       * @param reason The reason for the line\r        * @param hostmask The hostmask to set the line against\r         */\r    void AddGLine(long duration, const std::string &source, const std::string &reason, const std::string &hostmask);\r\r      /** Add a qline and apply it\r    * @param duration How long the line should last\r        * @param source Who set the line\r       * @param reason The reason for the line\r        * @param nickname The nickmask to set the line against\r         */\r    void AddQLine(long duration, const std::string &source, const std::string &reason, const std::string &nickname);\r\r      /** Add a zline and apply it\r    * @param duration How long the line should last\r        * @param source Who set the line\r       * @param reason The reason for the line\r        * @param ipaddr The ip-mask to set the line against\r    */\r    void AddZLine(long duration, const std::string &source, const std::string &reason, const std::string &ipaddr);\r\r        /** Add a kline and apply it\r    * @param duration How long the line should last\r        * @param source Who set the line\r       * @param reason The reason for the line\r        * @param hostmask The hostmask to set the line against\r         */\r    void AddKLine(long duration, const std::string &source, const std::string &reason, const std::string &hostmask);\r\r      /** Add an eline\r        * @param duration How long the line should last\r        * @param source Who set the line\r       * @param reason The reason for the line\r        * @param hostmask The hostmask to set the line against\r         */\r    void AddELine(long duration, const std::string &source, const std::string &reason, const std::string &hostmask);\r\r      /** Delete a gline\r      * @param hostmask The gline to delete\r  * @return True if the item was removed\r         */\r    bool DelGLine(const std::string &hostmask);\r\r   /** Delete a qline\r      * @param nickname The qline to delete\r  * @return True if the item was removed\r         */\r    bool DelQLine(const std::string &nickname);\r\r   /** Delete a zline\r      * @param ipaddr The zline to delete\r    * @return True if the item was removed\r         */\r    bool DelZLine(const std::string &ipaddr);\r\r     /** Delete a kline\r      * @param hostmask The kline to delete\r  * @return True if the item was removed\r         */\r    bool DelKLine(const std::string &hostmask);\r\r   /** Delete an eline\r     * @param hostmask The kline to delete\r  * @return True if the item was removed\r         */\r    bool DelELine(const std::string &hostmask);\r\r   /** Return true if the given parameter is a valid nick!user\@host mask\r  * @param mask A nick!user\@host masak to match against\r         * @return True i the mask is valid\r     */\r    bool IsValidMask(const std::string &mask);\r\r    /** Rehash the local server\r     */\r    void RehashServer();\r\r  /** Return the channel whos index number matches that provided\r  * @param The index number of the channel to fetch\r      * @return A channel record, or NUll if index < 0 or index >= InspIRCd::ChannelCount()\r  */\r    chanrec* GetChannelIndex(long index);\r\r /** Dump text to a user target, splitting it appropriately to fit\r       * @param User the user to dump the text to\r     * @param LinePrefix text to prefix each complete line with\r     * @param TextStream the text to send to the user\r       */\r    void DumpText(userrec* User, const std::string &LinePrefix, stringstream &TextStream);\r\r        /** Check if the given nickmask matches too many users, send errors to the given user\r   * @param nick A nickmask to match against\r      * @param user A user to send error text to\r     * @return True if the nick matches too many users\r      */\r    bool NickMatchesEveryone(const std::string &nick, userrec* user);\r\r     /** Check if the given IP mask matches too many users, send errors to the given user\r    * @param ip An ipmask to match against\r         * @param user A user to send error text to\r     * @return True if the ip matches too many users\r        */\r    bool IPMatchesEveryone(const std::string &ip, userrec* user);\r\r /** Check if the given hostmask matches too many users, send errors to the given user\r   * @param mask A hostmask to match against\r      * @param user A user to send error text to\r     * @return True if the host matches too many users\r      */\r    bool HostMatchesEveryone(const std::string &mask, userrec* user);\r\r     /** Calculate a duration in seconds from a string in the form 1y2w3d4h6m5s\r      * @param str A string containing a time in the form 1y2w3d4h6m5s\r       * (one year, two weeks, three days, four hours, six minutes and five seconds)\r  * @return The total number of seconds\r  */\r    long Duration(const std::string &str);\r\r        /** Attempt to compare an oper password to a string from the config file.\r       * This will be passed to handling modules which will compare the data\r  * against possible hashed equivalents in the input string.\r     * @param data The data from the config file\r    * @param input The data input by the oper\r      * @param tagnum the tag number of the oper's tag in the config file\r    * @return 0 if the strings match, 1 or -1 if they do not\r       */\r    int OperPassCompare(const char* data,const char* input, int tagnum);\r\r  /** Check if a given server is a uline.\r         * An empty string returns true, this is by design.\r     * @param server The server to check for uline status\r   * @return True if the server is a uline OR the string is empty\r         */\r    bool ULine(const char* server);\r\r       /** Returns true if the uline is 'silent' (doesnt generate\r      * remote connect notices etc).\r         */\r    bool SilentULine(const char* server);\r\r /** Returns the subversion revision ID of this ircd\r     * @return The revision ID or an empty string\r   */\r    std::string GetRevision();\r\r    /** Returns the full version string of this ircd\r        * @return The version string\r   */\r    std::string GetVersionString();\r\r       /** Attempt to write the process id to a given file\r     * @param filename The PID file to attempt to write to\r  * @return This function may bail if the file cannot be written\r         */\r    void WritePID(const std::string &filename);\r\r   /** Returns text describing the last module error\r       * @return The last error message to occur\r      */\r    char* ModuleError();\r\r  /** Load a given module file\r    * @param filename The file to load\r     * @return True if the module was found and loaded\r      */\r    bool LoadModule(const char* filename);\r\r        /** Unload a given module file\r  * @param filename The file to unload\r   * @return True if the module was unloaded\r      */\r    bool UnloadModule(const char* filename);\r\r      /** This constructor initialises all the subsystems and reads the config file.\r  * @param argc The argument count passed to main()\r      * @param argv The argument list passed to main()\r       * @throw <anything> If anything is thrown from here and makes it to\r    * you, you should probably just give up and go home. Yes, really.\r      * It's that bad. Higher level classes should catch any non-fatal exceptions.\r   */\r    InspIRCd(int argc, char** argv);\r\r      /** Do one iteration of the mainloop\r    * @param process_module_sockets True if module sockets are to be processed\r     * this time around the event loop. The is the default.\r         */\r    void DoOneIteration(bool process_module_sockets = true);\r\r      /** Output a log message to the ircd.log file\r   * The text will only be output if the current loglevel\r         * is less than or equal to the level you provide\r       * @param level A log level from the DebugLevel enum\r    * @param text Format string of to write to the log\r     * @param ... Format arguments of text to write to the log\r      */\r    void Log(int level, const char* text, ...);\r\r   /** Output a log message to the ircd.log file\r   * The text will only be output if the current loglevel\r         * is less than or equal to the level you provide\r       * @param level A log level from the DebugLevel enum\r    * @param text Text to write to the log\r         */\r    void Log(int level, const std::string &text);\r\r /** Send a line of WHOIS data to a user.\r        * @param user user to send the line to\r         * @param dest user being WHOISed\r       * @param numeric Numeric to send\r       * @param text Text of the numeric\r      */\r    void SendWhoisLine(userrec* user, userrec* dest, int numeric, const std::string &text);\r\r       /** Send a line of WHOIS data to a user.\r        * @param user user to send the line to\r         * @param dest user being WHOISed\r       * @param numeric Numeric to send\r       * @param format Format string for the numeric\r  * @param ... Parameters for the format string\r  */\r    void SendWhoisLine(userrec* user, userrec* dest, int numeric, const char* format, ...);\r\r       /** Quit a user for excess flood, and if they are not\r   * fully registered yet, temporarily zline their IP.\r    * @param current user to quit\r  */\r    void FloodQuitUser(userrec* current);\r\r /** Restart the server.\r         * This function will not return. If an error occurs,\r   * it will throw an instance of CoreException.\r  * @param reason The restart reason to show to all clients\r      * @throw CoreException An instance of CoreException indicating the error from execv().\r         */\r    void Restart(const std::string &reason);\r\r      /** Prepare the ircd for restart or shutdown.\r   * This function unloads all modules which can be unloaded,\r     * closes all open sockets, and closes the logfile.\r     */\r    void Cleanup();\r\r       /** This copies the user and channel hash_maps into new hash maps.\r      * This frees memory used by the hash_map allocator (which it neglects\r  * to free, most of the time, using tons of ram)\r        */\r    void RehashUsersAndChans();\r\r   /** Resets the cached max bans value on all channels.\r   * Called by rehash.\r    */\r    void ResetMaxBans();\r\r  /** Return a time_t as a human-readable string.\r         */\r    std::string TimeString(time_t curtime);\r\r       /** Begin execution of the server.\r      * NOTE: this function NEVER returns. Internally,\r       * after performing some initialisation routines,\r       * it will repeatedly call DoOneIteration in a loop.\r    * @return The return value for this function is undefined.\r     */\r    int Run();\r};\r\r#endif\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *         the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __INSPIRCD_H__
+#define __INSPIRCD_H__
+
+#ifndef WIN32
+#define DllExport 
+#define CoreExport 
+#define printf_c printf
+#else
+#include "inspircd_win32wrapper.h"
+/** Windows defines these already */
+#undef DELETE
+#undef ERROR
+#endif
+
+#include <time.h>
+#include <string>
+#include <sstream>
+#include "inspircd_config.h"
+#include "users.h"
+#include "channels.h"
+#include "socket.h"
+#include "mode.h"
+#include "socketengine.h"
+#include "command_parse.h"
+#include "snomasks.h"
+#include "cull_list.h"
+
+/** Returned by some functions to indicate failure.
+ */
+#define ERROR -1
+
+/** Support for librodent -
+ * see http://www.chatspike.net/index.php?z=64
+ */
+#define ETIREDHAMSTERS EAGAIN
+
+/** Debug levels for use with InspIRCd::Log()
+ */
+enum DebugLevel
+{
+       DEBUG           =       10,
+       VERBOSE         =       20,
+       DEFAULT         =       30,
+       SPARSE          =       40,
+       NONE            =       50
+};
+
+/**
+ * This define is used in place of strcmp when we
+ * want to check if a char* string contains only one
+ * letter. Pretty fast, its just two compares and an
+ * addition.
+ */
+#define IS_SINGLE(x,y) ( (*x == y) && (*(x+1) == 0) )
+
+/** Delete a pointer, and NULL its value
+ */
+template<typename T> inline void DELETE(T* x)
+{
+       delete x;
+       x = NULL;
+}
+
+/** Template function to convert any input type to std::string
+ */
+template<typename T> inline std::string ConvNumeric(const T &in)
+{
+       if (in == 0) return "0";
+       char res[MAXBUF];
+       char* out = res;
+       T quotient = in;
+       while (quotient) {
+               *out = "0123456789"[ std::abs( (long)quotient % 10 ) ];
+               ++out;
+               quotient /= 10;
+       }
+       if ( in < 0)
+               *out++ = '-';
+       *out = 0;
+       std::reverse(res,out);
+       return res;
+}
+
+/** Template function to convert any input type to std::string
+ */
+inline std::string ConvToStr(const int in)
+{
+       return ConvNumeric(in);
+}
+
+/** Template function to convert any input type to std::string
+ */
+inline std::string ConvToStr(const long in)
+{
+       return ConvNumeric(in);
+}
+
+/** Template function to convert any input type to std::string
+ */
+inline std::string ConvToStr(const unsigned long in)
+{
+       return ConvNumeric(in);
+}
+
+/** Template function to convert any input type to std::string
+ */
+inline std::string ConvToStr(const char* in)
+{
+       return in;
+}
+
+/** Template function to convert any input type to std::string
+ */
+inline std::string ConvToStr(const bool in)
+{
+       return (in ? "1" : "0");
+}
+
+/** Template function to convert any input type to std::string
+ */
+inline std::string ConvToStr(char in)
+{
+       return std::string(in,1);
+}
+
+/** Template function to convert any input type to std::string
+ */
+template <class T> inline std::string ConvToStr(const T &in)
+{
+       std::stringstream tmp;
+       if (!(tmp << in)) return std::string();
+       return tmp.str();
+}
+
+/** Template function to convert any input type to any other type
+ * (usually an integer or numeric type)
+ */
+template<typename T> inline long ConvToInt(const T &in)
+{
+       std::stringstream tmp;
+       if (!(tmp << in)) return 0;
+       return atoi(tmp.str().c_str());
+}
+
+/** Template function to convert integer to char, storing result in *res and
+ * also returning the pointer to res. Based on Stuart Lowe's C/C++ Pages.
+ * @param T input value
+ * @param V result value
+ * @param R base to convert to
+ */
+template<typename T, typename V, typename R> inline char* itoa(const T &in, V *res, R base)
+{
+       if (base < 2 || base > 16) { *res = 0; return res; }
+       char* out = res;
+       int quotient = in;
+       while (quotient) {
+               *out = "0123456789abcdef"[ std::abs( quotient % base ) ];
+               ++out;
+               quotient /= base;
+       }
+       if ( in < 0 && base == 10) *out++ = '-';
+       std::reverse( res, out );
+       *out = 0;
+       return res;
+}
+
+/** This class contains various STATS counters
+ * It is used by the InspIRCd class, which internally
+ * has an instance of it.
+ */
+class serverstats : public classbase
+{
+  public:
+       /** Number of accepted connections
+        */
+       unsigned long statsAccept;
+       /** Number of failed accepts
+        */
+       unsigned long statsRefused;
+       /** Number of unknown commands seen
+        */
+       unsigned long statsUnknown;
+       /** Number of nickname collisions handled
+        */
+       unsigned long statsCollisions;
+       /** Number of DNS queries sent out
+        */
+       unsigned long statsDns;
+       /** Number of good DNS replies received
+        * NOTE: This may not tally to the number sent out,
+        * due to timeouts and other latency issues.
+        */
+       unsigned long statsDnsGood;
+       /** Number of bad (negative) DNS replies received
+        * NOTE: This may not tally to the number sent out,
+        * due to timeouts and other latency issues.
+        */
+       unsigned long statsDnsBad;
+       /** Number of inbound connections seen
+        */
+       unsigned long statsConnects;
+       /** Total bytes of data transmitted
+        */
+       double statsSent;
+       /** Total bytes of data received
+        */
+       double statsRecv;
+       /** Cpu usage at last sample
+        */
+       timeval LastCPU;
+       /** Time last sample was read
+        */
+       timeval LastSampled;
+       /** The constructor initializes all the counts to zero
+        */
+       serverstats()
+               : statsAccept(0), statsRefused(0), statsUnknown(0), statsCollisions(0), statsDns(0),
+               statsDnsGood(0), statsDnsBad(0), statsConnects(0), statsSent(0.0), statsRecv(0.0)
+       {
+       }
+};
+
+/* Forward declaration -- required */
+class InspIRCd;
+
+/** This class implements a nonblocking log-writer.
+ * Most people writing an ircd give little thought to their disk
+ * i/o. On a congested system, disk writes can block for long
+ * periods of time (e.g. if the system is busy and/or swapping
+ * a lot). If we just use a blocking fprintf() call, this could
+ * block for undesirable amounts of time (half of a second through
+ * to whole seconds). We DO NOT want this, so we make our logfile
+ * nonblocking and hook it into the SocketEngine.
+ * NB: If the operating system does not support nonblocking file
+ * I/O (linux seems to, as does freebsd) this will default to
+ * blocking behaviour.
+ */
+class CoreExport FileLogger : public EventHandler
+{
+ protected:
+       /** The creator/owner of this object
+        */
+       InspIRCd* ServerInstance;
+       /** The log file (fd is inside this somewhere,
+        * we get it out with fileno())
+        */
+       FILE* log;
+       /** Buffer of pending log lines to be written
+        */
+       std::string buffer;
+       /** Number of write operations that have occured
+        */
+       int writeops;
+ public:
+       /** The constructor takes an already opened logfile.
+        */
+       FileLogger(InspIRCd* Instance, FILE* logfile);
+       /** This returns false, logfiles are writeable.
+        */
+       virtual bool Readable();
+       /** Handle pending write events.
+        * This will flush any waiting data to disk.
+        * If any data remains after the fprintf call,
+        * another write event is scheduled to write
+        * the rest of the data when possible.
+        */
+       virtual void HandleEvent(EventType et, int errornum = 0);
+       /** Write one or more preformatted log lines.
+        * If the data cannot be written immediately,
+        * this class will insert itself into the
+        * SocketEngine, and register a write event,
+        * and when the write event occurs it will
+        * attempt again to write the data.
+        */
+       void WriteLogLine(const std::string &line);
+       /** Close the log file and cancel any events.
+        */
+       virtual void Close();
+       /** Close the log file and cancel any events.
+        * (indirectly call Close()
+        */
+       virtual ~FileLogger();
+};
+
+/** A list of failed port bindings, used for informational purposes on startup */
+typedef std::vector<std::pair<std::string, long> > FailedPortList;
+
+/** A list of ip addresses cross referenced against clone counts */
+typedef std::map<irc::string, unsigned int> clonemap;
+
+/* Forward declaration - required */
+class XLineManager;
+
+/** The main class of the irc server.
+ * This class contains instances of all the other classes
+ * in this software, with the exception of the base class,
+ * classbase. Amongst other things, it contains a ModeParser,
+ * a DNS object, a CommandParser object, and a list of active
+ * Module objects, and facilities for Module objects to
+ * interact with the core system it implements. You should
+ * NEVER attempt to instantiate a class of type InspIRCd
+ * yourself. If you do, this is equivalent to spawning a second
+ * IRC server, and could have catastrophic consequences for the
+ * program in terms of ram usage (basically, you could create
+ * an obese forkbomb built from recursively spawning irc servers!)
+ */
+class CoreExport InspIRCd : public classbase
+{
+ private:
+       /** Holds a string describing the last module error to occur
+        */
+       char MODERR[MAXBUF];
+
+       /** Remove a ModuleFactory pointer
+        * @param j Index number of the ModuleFactory to remove
+        */
+       void EraseFactory(int j);
+
+       /** Remove a Module pointer
+        * @param j Index number of the Module to remove
+        */
+       void EraseModule(int j);
+
+       /** Move a given module to a specific slot in the list
+        * @param modulename The module name to relocate
+        * @param slot The slot to move the module into
+        */
+       void MoveTo(std::string modulename,int slot);
+
+       /** Display the startup banner
+        */
+       void Start();
+
+       /** Set up the signal handlers
+        */
+       void SetSignals();
+
+       /** Daemonize the ircd and close standard input/output streams
+        * @return True if the program daemonized succesfully
+        */
+       bool DaemonSeed();
+
+       /** Moves the given module to the last slot in the list
+        * @param modulename The module name to relocate
+        */
+       void MoveToLast(std::string modulename);
+
+       /** Moves the given module to the first slot in the list
+        * @param modulename The module name to relocate
+        */
+       void MoveToFirst(std::string modulename);
+
+       /** Moves one module to be placed after another in the list
+        * @param modulename The module name to relocate
+        * @param after The module name to place the module after
+        */
+       void MoveAfter(std::string modulename, std::string after);
+
+       /** Moves one module to be placed before another in the list
+        * @param modulename The module name to relocate
+        * @param after The module name to place the module before
+        */
+       void MoveBefore(std::string modulename, std::string before);
+
+       /** Iterate the list of InspSocket objects, removing ones which have timed out
+        * @param TIME the current time
+        */
+       void DoSocketTimeouts(time_t TIME);
+
+       /** Perform background user events such as PING checks
+        * @param TIME the current time
+        */
+       void DoBackgroundUserStuff(time_t TIME);
+
+       /** Returns true when all modules have done pre-registration checks on a user
+        * @param user The user to verify
+        * @return True if all modules have finished checking this user
+        */
+       bool AllModulesReportReady(userrec* user);
+
+       /** Total number of modules loaded into the ircd, minus one
+        */
+       int ModCount;
+
+       /** Logfile pathname specified on the commandline, or empty string
+        */
+       char LogFileName[MAXBUF];
+
+       /** The feature names published by various modules
+        */
+       featurelist Features;
+
+       /** The interface names published by various modules
+        */
+       interfacelist Interfaces;
+
+       /** The current time, updated in the mainloop
+        */
+       time_t TIME;
+
+       /** The time that was recorded last time around the mainloop
+        */
+       time_t OLDTIME;
+
+       /** A 64k buffer used to read client lines into
+        */
+       char ReadBuffer[65535];
+
+       /** Used when connecting clients
+        */
+       insp_sockaddr client, server;
+
+       /** Used when connecting clients
+        */
+       socklen_t length;
+
+       /** Nonblocking file writer
+        */
+       FileLogger* Logger;
+
+       /** Time offset in seconds
+        * This offset is added to all calls to Time(). Use SetTimeDelta() to update
+        */
+       int time_delta;
+
+ public:
+
+       /** InspSocket classes pending deletion after being closed.
+        * We don't delete these immediately as this may cause a segmentation fault.
+        */
+       std::map<InspSocket*,InspSocket*> SocketCull;
+
+       /** Build the ISUPPORT string by triggering all modules On005Numeric events
+        */
+       void BuildISupport();
+
+       /** Number of unregistered users online right now.
+        * (Unregistered means before USER/NICK/dns)
+        */
+       int unregistered_count;
+
+       /** List of server names we've seen.
+        */
+       servernamelist servernames;
+
+       /** Time this ircd was booted
+        */
+       time_t startup_time;
+
+       /** Config file pathname specified on the commandline or via ./configure
+        */
+       char ConfigFileName[MAXBUF];
+
+       /** Mode handler, handles mode setting and removal
+        */
+       ModeParser* Modes;
+
+       /** Command parser, handles client to server commands
+        */
+       CommandParser* Parser;
+
+       /** Socket engine, handles socket activity events
+        */
+       SocketEngine* SE;
+
+       /** Stats class, holds miscellaneous stats counters
+        */
+       serverstats* stats;
+
+       /**  Server Config class, holds configuration file data
+        */
+       ServerConfig* Config;
+
+       /** Snomask manager - handles routing of snomask messages
+        * to opers.
+        */
+       SnomaskManager* SNO;
+
+       /** Client list, a hash_map containing all clients, local and remote
+        */
+       user_hash* clientlist;
+
+       /** Channel list, a hash_map containing all channels
+        */
+       chan_hash* chanlist;
+
+       /** Local client list, a vector containing only local clients
+        */
+       std::vector<userrec*> local_users;
+
+       /** Oper list, a vector containing all local and remote opered users
+        */
+       std::vector<userrec*> all_opers;
+
+       /** Map of local ip addresses for clone counting
+        */
+       clonemap local_clones;
+
+       /** Map of global ip addresses for clone counting
+        */
+       clonemap global_clones;
+
+       /** DNS class, provides resolver facilities to the core and modules
+        */
+       DNS* Res;
+
+       /** Timer manager class, triggers InspTimer timer events
+        */
+       TimerManager* Timers;
+
+       /** X-Line manager. Handles G/K/Q/E line setting, removal and matching
+        */
+       XLineManager* XLines;
+
+       /** A list of Module* module classes
+        * Note that this list is always exactly 255 in size.
+        * The actual number of loaded modules is available from GetModuleCount()
+        */
+       ModuleList modules;
+
+       /** A list of ModuleFactory* module factories
+        * Note that this list is always exactly 255 in size.
+        * The actual number of loaded modules is available from GetModuleCount()
+        */
+       FactoryList factory;
+
+       /** The time we next call our ping timeout and reg timeout checks
+        */
+       time_t next_call;
+
+       /** Global cull list, will be processed on next iteration
+        */
+       CullList GlobalCulls;
+
+       /** Get the current time
+        * Because this only calls time() once every time around the mainloop,
+        * it is much faster than calling time() directly.
+        * @param delta True to use the delta as an offset, false otherwise
+        * @return The current time as an epoch value (time_t)
+        */
+       time_t Time(bool delta = false);
+
+       /** Set the time offset in seconds
+        * This offset is added to Time() to offset the system time by the specified
+        * number of seconds.
+        * @param delta The number of seconds to offset
+        * @return The old time delta
+        */
+       int SetTimeDelta(int delta);
+
+       /** Add a user to the local clone map
+        * @param user The user to add
+        */
+       void AddLocalClone(userrec* user);
+
+       /** Add a user to the global clone map
+        * @param user The user to add
+        */
+       void AddGlobalClone(userrec* user);
+
+       /** Number of users with a certain mode set on them
+        */
+       int ModeCount(const char mode);
+
+       /** Get the time offset in seconds
+        * @return The current time delta (in seconds)
+        */
+       int GetTimeDelta();
+
+       /** Process a user whos socket has been flagged as active
+        * @param cu The user to process
+        * @return There is no actual return value, however upon exit, the user 'cu' may have been
+        * marked for deletion in the global CullList.
+        */
+       void ProcessUser(userrec* cu);
+
+       /** Get the total number of currently loaded modules
+        * @return The number of loaded modules
+        */
+       int GetModuleCount();
+
+       /** Find a module by name, and return a Module* to it.
+        * This is preferred over iterating the module lists yourself.
+        * @param name The module name to look up
+        * @return A pointer to the module, or NULL if the module cannot be found
+        */
+       Module* FindModule(const std::string &name);
+
+       /** Bind all ports specified in the configuration file.
+        * @param bail True if the function should bail back to the shell on failure
+        * @param found_ports The actual number of ports found in the config, as opposed to the number actually bound
+        * @return The number of ports actually bound without error
+        */
+       int BindPorts(bool bail, int &found_ports, FailedPortList &failed_ports);
+
+       /** Binds a socket on an already open file descriptor
+        * @param sockfd A valid file descriptor of an open socket
+        * @param port The port number to bind to
+        * @param addr The address to bind to (IP only)
+        * @return True if the port was bound successfully
+        */
+       bool BindSocket(int sockfd, int port, char* addr, bool dolisten = true);
+
+       /** Adds a server name to the list of servers we've seen
+        * @param The servername to add
+        */
+       void AddServerName(const std::string &servername);
+
+       /** Finds a cached char* pointer of a server name,
+        * This is used to optimize userrec by storing only the pointer to the name
+        * @param The servername to find
+        * @return A pointer to this name, gauranteed to never become invalid
+        */
+       const char* FindServerNamePtr(const std::string &servername);
+
+       /** Returns true if we've seen the given server name before
+        * @param The servername to find
+        * @return True if we've seen this server name before
+        */
+       bool FindServerName(const std::string &servername);
+
+       /** Gets the GECOS (description) field of the given server.
+        * If the servername is not that of the local server, the name
+        * is passed to handling modules which will attempt to determine
+        * the GECOS that bleongs to the given servername.
+        * @param servername The servername to find the description of
+        * @return The description of this server, or of the local server
+        */
+       std::string GetServerDescription(const char* servername);
+
+       /** Write text to all opers connected to this server
+        * @param text The text format string
+        * @param ... Format args
+        */
+       void WriteOpers(const char* text, ...);
+
+       /** Write text to all opers connected to this server
+        * @param text The text to send
+        */
+       void WriteOpers(const std::string &text);
+
+       /** Find a nickname in the nick hash
+        * @param nick The nickname to find
+        * @return A pointer to the user, or NULL if the user does not exist
+        */
+       userrec* FindNick(const std::string &nick);
+
+       /** Find a nickname in the nick hash
+        * @param nick The nickname to find
+        * @return A pointer to the user, or NULL if the user does not exist
+        */
+       userrec* FindNick(const char* nick);
+
+       /** Find a channel in the channels hash
+        * @param chan The channel to find
+        * @return A pointer to the channel, or NULL if the channel does not exist
+        */
+       chanrec* FindChan(const std::string &chan);
+
+       /** Find a channel in the channels hash
+        * @param chan The channel to find
+        * @return A pointer to the channel, or NULL if the channel does not exist
+        */
+       chanrec* FindChan(const char* chan);
+
+       /** Called by the constructor to load all modules from the config file.
+        */
+       void LoadAllModules();
+
+       /** Check for a 'die' tag in the config file, and abort if found
+        * @return Depending on the configuration, this function may never return
+        */
+       void CheckDie();
+
+       /** Check we aren't running as root, and exit if we are
+        * @return Depending on the configuration, this function may never return
+        */
+       void CheckRoot();
+
+       /** Determine the right path for, and open, the logfile
+        * @param argv The argv passed to main() initially, used to calculate program path
+        * @param argc The argc passed to main() initially, used to calculate program path
+        */
+       void OpenLog(char** argv, int argc);
+
+       /** Close the currently open log file
+        */
+       void CloseLog();
+
+       /** Send a server notice to all local users
+        * @param text The text format string to send
+        * @param ... The format arguments
+        */
+       void ServerNoticeAll(char* text, ...);
+
+       /** Send a server message (PRIVMSG) to all local users
+        * @param text The text format string to send
+        * @param ... The format arguments
+        */
+       void ServerPrivmsgAll(char* text, ...);
+
+       /** Send text to all users with a specific set of modes
+        * @param modes The modes to check against, without a +, e.g. 'og'
+        * @param flags one of WM_OR or WM_AND. If you specify WM_OR, any one of the
+        * mode characters in the first parameter causes receipt of the message, and
+        * if you specify WM_OR, all the modes must be present.
+        * @param text The text format string to send
+        * @param ... The format arguments
+        */
+       void WriteMode(const char* modes, int flags, const char* text, ...);
+
+       /** Return true if a channel name is valid
+        * @param chname A channel name to verify
+        * @return True if the name is valid
+        */
+       bool IsChannel(const char *chname);
+
+       /** Rehash the local server
+        * @param status This value is unused, and required for signal handler functions
+        */
+       static void Rehash(int status);
+
+       /** Causes the server to exit after unloading modules and
+        * closing all open file descriptors.
+        *
+        * @param The exit code to give to the operating system
+        * (See the ExitStatus enum for valid values)
+        */
+       static void Exit(int status);
+
+       /** Causes the server to exit immediately with exit code 0.
+        * The status code is required for signal handlers, and ignored.
+        */
+       static void QuickExit(int status);
+
+       /** Return a count of users, unknown and known connections
+        * @return The number of users
+        */
+       int UserCount();
+
+       /** Return a count of fully registered connections only
+        * @return The number of registered users
+        */
+       int RegisteredUserCount();
+
+       /** Return a count of invisible (umode +i) users only
+        * @return The number of invisible users
+        */
+       int InvisibleUserCount();
+
+       /** Return a count of opered (umode +o) users only
+        * @return The number of opers
+        */
+       int OperCount();
+
+       /** Return a count of unregistered (before NICK/USER) users only
+        * @return The number of unregistered (unknown) connections
+        */
+       int UnregisteredUserCount();
+
+       /** Return a count of channels on the network
+        * @return The number of channels
+        */
+       long ChannelCount();
+
+       /** Return a count of local users on this server only
+        * @return The number of local users
+        */
+       long LocalUserCount();
+
+       /** Send an error notice to all local users, opered and unopered
+        * @param s The error string to send
+        */
+       void SendError(const std::string &s);
+
+       /** For use with Module::Prioritize().
+        * When the return value of this function is returned from
+        * Module::Prioritize(), this specifies that the module wishes
+        * to be ordered exactly BEFORE 'modulename'. For more information
+        * please see Module::Prioritize().
+        * @param modulename The module your module wants to be before in the call list
+        * @returns a priority ID which the core uses to relocate the module in the list
+        */
+       long PriorityBefore(const std::string &modulename);
+
+       /** For use with Module::Prioritize().
+        * When the return value of this function is returned from
+        * Module::Prioritize(), this specifies that the module wishes
+        * to be ordered exactly AFTER 'modulename'. For more information please
+        * see Module::Prioritize().
+        * @param modulename The module your module wants to be after in the call list
+        * @returns a priority ID which the core uses to relocate the module in the list
+        */
+       long PriorityAfter(const std::string &modulename);
+
+       /** Publish a 'feature'.
+        * There are two ways for a module to find another module it depends on.
+        * Either by name, using InspIRCd::FindModule, or by feature, using this
+        * function. A feature is an arbitary string which identifies something this
+        * module can do. For example, if your module provides SSL support, but other
+        * modules provide SSL support too, all the modules supporting SSL should
+        * publish an identical 'SSL' feature. This way, any module requiring use
+        * of SSL functions can just look up the 'SSL' feature using FindFeature,
+        * then use the module pointer they are given.
+        * @param FeatureName The case sensitive feature name to make available
+        * @param Mod a pointer to your module class
+        * @returns True on success, false if the feature is already published by
+        * another module.
+        */
+       bool PublishFeature(const std::string &FeatureName, Module* Mod);
+
+       /** Publish a module to an 'interface'.
+        * Modules which implement the same interface (the same way of communicating
+        * with other modules) can publish themselves to an interface, using this
+        * method. When they do so, they become part of a list of related or
+        * compatible modules, and a third module may then query for that list
+        * and know that all modules within that list offer the same API.
+        * A prime example of this is the hashing modules, which all accept the
+        * same types of Request class. Consider this to be similar to PublishFeature,
+        * except for that multiple modules may publish the same 'feature'.
+        * @param InterfaceName The case sensitive interface name to make available
+        * @param Mod a pointer to your module class
+        * @returns True on success, false on failure (there are currently no failure
+        * cases)
+        */
+       bool PublishInterface(const std::string &InterfaceName, Module* Mod);
+
+       /** Return a pair saying how many other modules are currently using the
+        * interfaces provided by module m.
+        * @param m The module to count usage for
+        * @return A pair, where the first value is the number of uses of the interface,
+        * and the second value is the interface name being used.
+        */
+       std::pair<int,std::string> GetInterfaceInstanceCount(Module* m);
+
+       /** Mark your module as using an interface.
+        * If you mark your module as using an interface, then that interface
+        * module may not unload until your module has unloaded first.
+        * This can be used to prevent crashes by ensuring code you depend on
+        * is always in memory while your module is active.
+        * @param InterfaceName The interface to use
+        */
+       void UseInterface(const std::string &InterfaceName);
+
+       /** Mark your module as finished with an interface.
+        * If you used UseInterface() above, you should use this method when
+        * your module is finished with the interface (usually in its destructor)
+        * to allow the modules which implement the given interface to be unloaded.
+        * @param InterfaceName The interface you are finished with using.
+        */
+       void DoneWithInterface(const std::string &InterfaceName);
+
+       /** Unpublish a 'feature'.
+        * When your module exits, it must call this method for every feature it
+        * is providing so that the feature table is cleaned up.
+        * @param FeatureName the feature to remove
+        */
+       bool UnpublishFeature(const std::string &FeatureName);
+
+       /** Unpublish your module from an interface
+        * When your module exits, it must call this method for every interface
+        * it is part of so that the interfaces table is cleaned up. Only when
+        * the last item is deleted from an interface does the interface get
+        * removed.
+        * @param InterfaceName the interface to be removed from
+        * @param Mod The module to remove from the interface list
+        */
+       bool UnpublishInterface(const std::string &InterfaceName, Module* Mod);
+
+       /** Find a 'feature'.
+        * There are two ways for a module to find another module it depends on.
+        * Either by name, using InspIRCd::FindModule, or by feature, using the
+        * InspIRCd::PublishFeature method. A feature is an arbitary string which
+        * identifies something this module can do. For example, if your module
+        * provides SSL support, but other modules provide SSL support too, all
+        * the modules supporting SSL should publish an identical 'SSL' feature.
+        * To find a module capable of providing the feature you want, simply
+        * call this method with the feature name you are looking for.
+        * @param FeatureName The feature name you wish to obtain the module for
+        * @returns A pointer to a valid module class on success, NULL on failure.
+        */
+       Module* FindFeature(const std::string &FeatureName);
+
+       /** Find an 'interface'.
+        * An interface is a list of modules which all implement the same API.
+        * @param InterfaceName The Interface you wish to obtain the module
+        * list of.
+        * @return A pointer to a deque of Module*, or NULL if the interface
+        * does not exist.
+        */
+       modulelist* FindInterface(const std::string &InterfaceName);
+
+       /** Given a pointer to a Module, return its filename
+        * @param m The module pointer to identify
+        * @return The module name or an empty string
+        */
+       const std::string& GetModuleName(Module* m);
+
+       /** Return true if a nickname is valid
+        * @param n A nickname to verify
+        * @return True if the nick is valid
+        */
+       bool IsNick(const char* n);
+
+       /** Return true if an ident is valid
+        * @param An ident to verify
+        * @return True if the ident is valid
+        */
+       bool IsIdent(const char* n);
+
+       /** Find a username by their file descriptor.
+        * It is preferred to use this over directly accessing the fd_ref_table array.
+        * @param socket The file descriptor of a user
+        * @return A pointer to the user if the user exists locally on this descriptor
+        */
+       userrec* FindDescriptor(int socket);
+
+       /** Add a new mode to this server's mode parser
+        * @param mh The modehandler to add
+        * @param modechar The mode character this modehandler handles
+        * @return True if the mode handler was added
+        */
+       bool AddMode(ModeHandler* mh, const unsigned char modechar);
+
+       /** Add a new mode watcher to this server's mode parser
+        * @param mw The modewatcher to add
+        * @return True if the modewatcher was added
+        */
+       bool AddModeWatcher(ModeWatcher* mw);
+
+       /** Delete a mode watcher from this server's mode parser
+        * @param mw The modewatcher to delete
+        * @return True if the modewatcher was deleted
+        */
+       bool DelModeWatcher(ModeWatcher* mw);
+
+       /** Add a dns Resolver class to this server's active set
+        * @param r The resolver to add
+        * @param cached If this value is true, then the cache will
+        * be searched for the DNS result, immediately. If the value is
+        * false, then a request will be sent to the nameserver, and the
+        * result will not be immediately available. You should usually
+        * use the boolean value which you passed to the Resolver
+        * constructor, which Resolver will set appropriately depending
+        * on if cached results are available and haven't expired. It is
+        * however safe to force this value to false, forcing a remote DNS
+        * lookup, but not an update of the cache.
+        * @return True if the operation completed successfully. Note that
+        * if this method returns true, you should not attempt to access
+        * the resolver class you pass it after this call, as depending upon
+        * the request given, the object may be deleted!
+        */
+       bool AddResolver(Resolver* r, bool cached);
+
+       /** Add a command to this server's command parser
+        * @param f A command_t command handler object to add
+        * @throw ModuleException Will throw ModuleExcption if the command already exists
+        */
+       void AddCommand(command_t *f);
+
+       /** Send a modechange.
+        * The parameters provided are identical to that sent to the
+        * handler for class cmd_mode.
+        * @param parameters The mode parameters
+        * @param pcnt The number of items you have given in the first parameter
+        * @param user The user to send error messages to
+        */
+       void SendMode(const char **parameters, int pcnt, userrec *user);
+
+       /** Match two strings using pattern matching.
+        * This operates identically to the global function match(),
+        * except for that it takes std::string arguments rather than
+        * const char* ones.
+        * @param sliteral The literal string to match against
+        * @param spattern The pattern to match against. CIDR and globs are supported.
+        */
+       bool MatchText(const std::string &sliteral, const std::string &spattern);
+
+       /** Call the handler for a given command.
+        * @param commandname The command whos handler you wish to call
+        * @param parameters The mode parameters
+        * @param pcnt The number of items you have given in the first parameter
+        * @param user The user to execute the command as
+        * @return True if the command handler was called successfully
+        */
+       CmdResult CallCommandHandler(const std::string &commandname, const char** parameters, int pcnt, userrec* user);
+
+       /** Return true if the command is a module-implemented command and the given parameters are valid for it
+        * @param parameters The mode parameters
+        * @param pcnt The number of items you have given in the first parameter
+        * @param user The user to test-execute the command as
+        * @return True if the command handler is a module command, and there are enough parameters and the user has permission to the command
+        */
+       bool IsValidModuleCommand(const std::string &commandname, int pcnt, userrec* user);
+
+       /** Add a gline and apply it
+        * @param duration How long the line should last
+        * @param source Who set the line
+        * @param reason The reason for the line
+        * @param hostmask The hostmask to set the line against
+        */
+       void AddGLine(long duration, const std::string &source, const std::string &reason, const std::string &hostmask);
+
+       /** Add a qline and apply it
+        * @param duration How long the line should last
+        * @param source Who set the line
+        * @param reason The reason for the line
+        * @param nickname The nickmask to set the line against
+        */
+       void AddQLine(long duration, const std::string &source, const std::string &reason, const std::string &nickname);
+
+       /** Add a zline and apply it
+        * @param duration How long the line should last
+        * @param source Who set the line
+        * @param reason The reason for the line
+        * @param ipaddr The ip-mask to set the line against
+        */
+       void AddZLine(long duration, const std::string &source, const std::string &reason, const std::string &ipaddr);
+
+       /** Add a kline and apply it
+        * @param duration How long the line should last
+        * @param source Who set the line
+        * @param reason The reason for the line
+        * @param hostmask The hostmask to set the line against
+        */
+       void AddKLine(long duration, const std::string &source, const std::string &reason, const std::string &hostmask);
+
+       /** Add an eline
+        * @param duration How long the line should last
+        * @param source Who set the line
+        * @param reason The reason for the line
+        * @param hostmask The hostmask to set the line against
+        */
+       void AddELine(long duration, const std::string &source, const std::string &reason, const std::string &hostmask);
+
+       /** Delete a gline
+        * @param hostmask The gline to delete
+        * @return True if the item was removed
+        */
+       bool DelGLine(const std::string &hostmask);
+
+       /** Delete a qline
+        * @param nickname The qline to delete
+        * @return True if the item was removed
+        */
+       bool DelQLine(const std::string &nickname);
+
+       /** Delete a zline
+        * @param ipaddr The zline to delete
+        * @return True if the item was removed
+        */
+       bool DelZLine(const std::string &ipaddr);
+
+       /** Delete a kline
+        * @param hostmask The kline to delete
+        * @return True if the item was removed
+        */
+       bool DelKLine(const std::string &hostmask);
+
+       /** Delete an eline
+        * @param hostmask The kline to delete
+        * @return True if the item was removed
+        */
+       bool DelELine(const std::string &hostmask);
+
+       /** Return true if the given parameter is a valid nick!user\@host mask
+        * @param mask A nick!user\@host masak to match against
+        * @return True i the mask is valid
+        */
+       bool IsValidMask(const std::string &mask);
+
+       /** Rehash the local server
+        */
+       void RehashServer();
+
+       /** Return the channel whos index number matches that provided
+        * @param The index number of the channel to fetch
+        * @return A channel record, or NUll if index < 0 or index >= InspIRCd::ChannelCount()
+        */
+       chanrec* GetChannelIndex(long index);
+
+       /** Dump text to a user target, splitting it appropriately to fit
+        * @param User the user to dump the text to
+        * @param LinePrefix text to prefix each complete line with
+        * @param TextStream the text to send to the user
+        */
+       void DumpText(userrec* User, const std::string &LinePrefix, stringstream &TextStream);
+
+       /** Check if the given nickmask matches too many users, send errors to the given user
+        * @param nick A nickmask to match against
+        * @param user A user to send error text to
+        * @return True if the nick matches too many users
+        */
+       bool NickMatchesEveryone(const std::string &nick, userrec* user);
+
+       /** Check if the given IP mask matches too many users, send errors to the given user
+        * @param ip An ipmask to match against
+        * @param user A user to send error text to
+        * @return True if the ip matches too many users
+        */
+       bool IPMatchesEveryone(const std::string &ip, userrec* user);
+
+       /** Check if the given hostmask matches too many users, send errors to the given user
+        * @param mask A hostmask to match against
+        * @param user A user to send error text to
+        * @return True if the host matches too many users
+        */
+       bool HostMatchesEveryone(const std::string &mask, userrec* user);
+
+       /** Calculate a duration in seconds from a string in the form 1y2w3d4h6m5s
+        * @param str A string containing a time in the form 1y2w3d4h6m5s
+        * (one year, two weeks, three days, four hours, six minutes and five seconds)
+        * @return The total number of seconds
+        */
+       long Duration(const std::string &str);
+
+       /** Attempt to compare an oper password to a string from the config file.
+        * This will be passed to handling modules which will compare the data
+        * against possible hashed equivalents in the input string.
+        * @param data The data from the config file
+        * @param input The data input by the oper
+        * @param tagnum the tag number of the oper's tag in the config file
+        * @return 0 if the strings match, 1 or -1 if they do not
+        */
+       int OperPassCompare(const char* data,const char* input, int tagnum);
+
+       /** Check if a given server is a uline.
+        * An empty string returns true, this is by design.
+        * @param server The server to check for uline status
+        * @return True if the server is a uline OR the string is empty
+        */
+       bool ULine(const char* server);
+
+       /** Returns true if the uline is 'silent' (doesnt generate
+        * remote connect notices etc).
+        */
+       bool SilentULine(const char* server);
+
+       /** Returns the subversion revision ID of this ircd
+        * @return The revision ID or an empty string
+        */
+       std::string GetRevision();
+
+       /** Returns the full version string of this ircd
+        * @return The version string
+        */
+       std::string GetVersionString();
+
+       /** Attempt to write the process id to a given file
+        * @param filename The PID file to attempt to write to
+        * @return This function may bail if the file cannot be written
+        */
+       void WritePID(const std::string &filename);
+
+       /** Returns text describing the last module error
+        * @return The last error message to occur
+        */
+       char* ModuleError();
+
+       /** Load a given module file
+        * @param filename The file to load
+        * @return True if the module was found and loaded
+        */
+       bool LoadModule(const char* filename);
+
+       /** Unload a given module file
+        * @param filename The file to unload
+        * @return True if the module was unloaded
+        */
+       bool UnloadModule(const char* filename);
+
+       /** This constructor initialises all the subsystems and reads the config file.
+        * @param argc The argument count passed to main()
+        * @param argv The argument list passed to main()
+        * @throw <anything> If anything is thrown from here and makes it to
+        * you, you should probably just give up and go home. Yes, really.
+        * It's that bad. Higher level classes should catch any non-fatal exceptions.
+        */
+       InspIRCd(int argc, char** argv);
+
+       /** Do one iteration of the mainloop
+        * @param process_module_sockets True if module sockets are to be processed
+        * this time around the event loop. The is the default.
+        */
+       void DoOneIteration(bool process_module_sockets = true);
+
+       /** Output a log message to the ircd.log file
+        * The text will only be output if the current loglevel
+        * is less than or equal to the level you provide
+        * @param level A log level from the DebugLevel enum
+        * @param text Format string of to write to the log
+        * @param ... Format arguments of text to write to the log
+        */
+       void Log(int level, const char* text, ...);
+
+       /** Output a log message to the ircd.log file
+        * The text will only be output if the current loglevel
+        * is less than or equal to the level you provide
+        * @param level A log level from the DebugLevel enum
+        * @param text Text to write to the log
+        */
+       void Log(int level, const std::string &text);
+
+       /** Send a line of WHOIS data to a user.
+        * @param user user to send the line to
+        * @param dest user being WHOISed
+        * @param numeric Numeric to send
+        * @param text Text of the numeric
+        */
+       void SendWhoisLine(userrec* user, userrec* dest, int numeric, const std::string &text);
+
+       /** Send a line of WHOIS data to a user.
+        * @param user user to send the line to
+        * @param dest user being WHOISed
+        * @param numeric Numeric to send
+        * @param format Format string for the numeric
+        * @param ... Parameters for the format string
+        */
+       void SendWhoisLine(userrec* user, userrec* dest, int numeric, const char* format, ...);
+
+       /** Quit a user for excess flood, and if they are not
+        * fully registered yet, temporarily zline their IP.
+        * @param current user to quit
+        */
+       void FloodQuitUser(userrec* current);
+
+       /** Restart the server.
+        * This function will not return. If an error occurs,
+        * it will throw an instance of CoreException.
+        * @param reason The restart reason to show to all clients
+        * @throw CoreException An instance of CoreException indicating the error from execv().
+        */
+       void Restart(const std::string &reason);
+
+       /** Prepare the ircd for restart or shutdown.
+        * This function unloads all modules which can be unloaded,
+        * closes all open sockets, and closes the logfile.
+        */
+       void Cleanup();
+
+       /** This copies the user and channel hash_maps into new hash maps.
+        * This frees memory used by the hash_map allocator (which it neglects
+        * to free, most of the time, using tons of ram)
+        */
+       void RehashUsersAndChans();
+
+       /** Resets the cached max bans value on all channels.
+        * Called by rehash.
+        */
+       void ResetMaxBans();
+
+       /** Return a time_t as a human-readable string.
+        */
+       std::string TimeString(time_t curtime);
+
+       /** Begin execution of the server.
+        * NOTE: this function NEVER returns. Internally,
+        * after performing some initialisation routines,
+        * it will repeatedly call DoOneIteration in a loop.
+        * @return The return value for this function is undefined.
+        */
+       int Run();
+};
+
+#endif
+
index 98fbc018f95a445cc4eae2e7ce31581c44dca948..d165d64f2429285a449a20ec1cf68a13fa7daaeb 100644 (file)
@@ -1 +1,437 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *        the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __INSP_SOCKET_H__\r#define __INSP_SOCKET_H__\r\r#include <sstream>\r#include <string>\r#include <deque>\r#include "dns.h"\r#include "inspircd_config.h"\r#include "socket.h"\r#include "inspsocket.h"\r#include "timer.h"\r\r/**\r * States which a socket may be in\r */\renum InspSocketState\r{\r    /** Socket disconnected */\r     I_DISCONNECTED,\r        /** Socket connecting */\r       I_CONNECTING,\r  /** Socket fully connected */\r  I_CONNECTED,\r   /** Socket listening for connections */\r        I_LISTENING,\r   /** Socket has an error */\r     I_ERROR\r};\r\r/**\r * Error types which a socket may exhibit\r */\renum InspSocketError\r{\r   /** Socket connect timed out */\r        I_ERR_TIMEOUT,\r /** Socket could not be created */\r     I_ERR_SOCKET,\r  /** Socket could not connect (refused) */\r      I_ERR_CONNECT,\r /** Socket could not bind to local port/ip */\r  I_ERR_BIND,\r    /** Socket could not reslve host (depreciated) */\r      I_ERR_RESOLVE,\r /** Socket could not write data */\r     I_ERR_WRITE,\r   /** No more file descriptors left to create socket! */\r I_ERR_NOMOREFDS\r};\r\r/* Required forward declarations */\rclass InspSocket;\rclass InspIRCd;\r\rusing irc::sockets::insp_sockaddr;\rusing irc::sockets::insp_inaddr;\rusing irc::sockets::insp_ntoa;\rusing irc::sockets::insp_aton;\r\r/** Used to time out socket connections\r */\rclass CoreExport SocketTimeout : public InspTimer\r{\r private:\r        /** InspSocket the class is attached to\r         */\r    InspSocket* sock;\r      /** Server instance creating the timeout class\r  */\r    InspIRCd* ServerInstance;\r      /** File descriptor of class this is attached to\r        */\r    int sfd;\r public:\r      /** Create a socket timeout class\r       * @param fd File descriptor of InspSocket\r      * @pram Instance server instance to attach to\r  * @param thesock InspSocket to attach to\r       * @param secs_from_now Seconds from now to time out\r    * @param now The current time\r  */\r    SocketTimeout(int fd, InspIRCd* Instance, InspSocket* thesock, long secs_from_now, time_t now) : InspTimer(secs_from_now, now), sock(thesock), ServerInstance(Instance), sfd(fd) { };\r  /** Handle tick event\r   */\r    virtual void Tick(time_t now);\r};\r\r/**\r * InspSocket is an extendable socket class which modules\r * can use for TCP socket support. It is fully integrated\r * into InspIRCds socket loop and attaches its sockets to\r * the core's instance of the SocketEngine class, meaning\r * that any sockets you create have the same power and\r * abilities as a socket created by the core itself.\r * To use InspSocket, you must inherit a class from it,\r * and use the InspSocket constructors to establish connections\r * and bindings.\r */\rclass CoreExport InspSocket : public EventHandler\r{\r public:\r\r  /** \r    * Bind IP\r      */\r    std::string cbindip;\r\r  /** \r    * Is hooked by a module for low level IO\r       */\r    bool IsIOHooked;\r\r      /** \r    * Instance we were created by\r  */\r    InspIRCd* Instance;\r\r   /** \r    * Timeout class or NULL\r        */\r    SocketTimeout* Timeout;\r\r       /** \r    * Timeout length\r       */\r    unsigned long timeout_val;\r\r    /** \r    * Socket output buffer (binary safe)\r   */\r    std::deque<std::string> outbuffer;\r\r    /**\r     * The hostname connected to\r    */\r    char host[MAXBUF];\r\r    /**\r     * The port connected to, or the port\r   * this socket is listening on\r  */\r    int port;\r\r     /**\r     * The state for this socket, either\r    * listening, connecting, connected\r     * or error.\r    */\r    InspSocketState state;\r\r        /**\r     * This value is true if the\r    * socket has timed out.\r        */\r    bool timeout;\r  \r       /**\r     * Socket input buffer, used by read(). The class which\r         * extends InspSocket is expected to implement an extendable\r    * buffer which can grow much larger than 64k,\r  * this buffer is just designed to be temporary storage.\r        * space.\r       */\r    char ibuf[65535];\r\r     /**\r     * The IP address being connected\r       * to stored in string form for\r         * easy retrieval by accessors.\r         */\r    char IP[MAXBUF];\r\r      /**\r     * Used by accept() to indicate the\r     * sizes of the sockaddr_in structures\r  */\r    socklen_t length;\r\r     /** Flushes the write buffer\r    */\r    bool FlushWriteBuffer();\r\r      /** Set the queue sizes\r         * This private method sets the operating system queue\r  * sizes for this socket to 65535 so that it can queue\r  * more information without application-level queueing\r  * which was required in older software.\r        */\r    void SetQueues(int nfd);\r\r      /** When the socket has been marked as closing, this flag\r       * will be set to true, then the next time the socket is\r        * examined, the socket is deleted and closed.\r  */\r    bool ClosePending;\r\r    /** Set to true when we're waiting for a write event.\r   * If this is true and a write event comes in, we\r       * call the write instead of the read method.\r   */\r    bool WaitingForWriteEvent;\r\r    /**\r     * Bind to an address\r   * @param ip IP to bind to\r      * @return True is the binding succeeded\r        */\r    bool BindAddr(const std::string &ip);\r\r /**\r     * The default constructor does nothing\r         * and should not be used.\r      */\r    InspSocket(InspIRCd* SI);\r\r     /**\r     * This constructor is used to associate\r        * an existing connecting with an InspSocket\r    * class. The given file descriptor must be\r     * valid, and when initialized, the InspSocket\r  * will be set with the given IP address\r        * and placed in CONNECTED state.\r       */\r    InspSocket(InspIRCd* SI, int newfd, const char* ip);\r\r  /**\r     * This constructor is used to create a new\r     * socket, either listening for connections, or an outbound connection to another host.\r         * Note that if you specify a hostname in the 'ipaddr' parameter, this class will not\r   * connect. You must resolve your hostnames before passing them to InspSocket. To do so,\r        * you should use the nonblocking class 'Resolver'.\r     * @param ipaddr The IP to connect to, or bind to\r       * @param port The port number to connect to, or bind to\r        * @param listening true to listen on the given host:port pair, or false to connect to them\r     * @param maxtime Number of seconds to wait, if connecting, before the connection times out and an OnTimeout() event is generated\r       * @param connectbindip When creating an outbound connection, the IP to bind the connection to. If not defined, the port is not bound.\r  * @return On exit, GetState() returns I_ERROR if an error occured, and errno can be used to read the socket error.\r     */\r    InspSocket(InspIRCd* SI, const std::string &ipaddr, int port, bool listening, unsigned long maxtime, const std::string &connectbindip = "");\r\r  /**\r     * This method is called when an outbound\r       * connection on your socket is completed.\r      * @return false to abort the connection, true to continue\r      */\r    virtual bool OnConnected();\r\r   /**\r     * This method is called when an error occurs.\r  * A closed socket in itself is not an error,\r   * however errors also generate close events.\r   * @param e The error type which occured\r        */\r    virtual void OnError(InspSocketError e);\r\r      /**\r     * When an established connection is terminated,\r        * the OnDisconnect method is triggered.\r        */\r    virtual int OnDisconnect();\r\r   /**\r     * When there is data waiting to be read on a\r   * socket, the OnDataReady() method is called.\r  * Within this method, you *MUST* call the Read()\r       * method to read any pending data. At its lowest\r       * level, this event is signalled by the core via\r       * the socket engine. If you return false from this\r     * function, the core removes your socket from its\r      * list and erases it from the socket engine, then\r      * calls InspSocket::Close() and deletes it.\r    * @return false to close the socket\r    */\r    virtual bool OnDataReady();\r\r   /**\r     * When it is ok to write to the socket, and a \r         * write event was requested, this method is\r    * triggered. Within this method you should call\r        * write() or send() etc, to send data to the\r   * other end of the socket. Further write events\r        * will not be triggered unless you call WantWrite().\r   * @return false to close the socket\r    */\r    virtual bool OnWriteReady();\r\r  /**\r     * When an outbound connection fails, and the\r   * attempt times out, you will receive this event.\r      * The method will trigger once maxtime seconds are\r     * reached (as given in the constructor) just\r   * before the socket's descriptor is closed.\r    * A failed DNS lookup may cause this event if\r  * the DNS server is not responding, as well as\r         * a failed connect() call, because DNS lookups are\r     * nonblocking as implemented by this class.\r    */\r    virtual void OnTimeout();\r\r     /**\r     * Whenever close() is called, OnClose() will be\r        * called first. Please note that this means\r    * OnClose will be called alongside OnError(),\r  * OnTimeout(), and Close(), and also when\r      * cancelling a listening socket by calling\r     * the destructor indirectly.\r   */\r    virtual void OnClose();\r\r       /**\r     * Reads all pending bytes from the socket\r      * into a char* array which can be up to\r        * 16 kilobytes in length.\r      */\r    virtual char* Read();\r\r /**\r     * Returns the IP address associated with\r       * this connection, or an empty string if\r       * no IP address exists.\r        */\r    std::string GetIP();\r\r  /**\r     * Writes a std::string to the socket. No carriage\r      * returns or linefeeds are appended to the string.\r     * @param data The data to send\r         */\r    virtual int Write(const std::string &data);\r\r   /**\r     * If your socket is a listening socket, when a new\r     * connection comes in on the socket this method will\r   * be called. Given the new file descriptor in the\r      * parameters, and the IP, it is recommended you copy\r   * them to a new instance of your socket class,\r         * e.g.:\r        *\r      * MySocket* newsocket = new MySocket(newfd,ip);\r        *\r      * Once you have done this, you can then associate the\r  * new socket with the core using Server::AddSocket().\r  */\r    virtual int OnIncomingConnection(int newfd, char* ip);\r\r        /**\r     * Changes the socket's state. The core uses this\r       * to change socket states, and you should not call\r     * it directly.\r         */\r    void SetState(InspSocketState s);\r\r     /**\r     * Call this to receive the next write event\r    * that comes along for this fd to the OnWriteReady\r     * method.\r      */\r    void WantWrite();\r\r     /**\r     * Returns the current socket state.\r    */\r    InspSocketState GetState();\r\r   /**\r     * Only the core should call this function.\r     * When called, it is assumed the socket is ready\r       * to read data, and the method call routes the\r         * event to the various methods of InspSocket\r   * for you to handle. This can also cause the\r   * socket's state to change.\r    */\r    bool Poll();\r\r  /**\r     * This method returns the socket's file descriptor\r     * as assigned by the operating system, or -1\r   * if no descriptor has been assigned.\r  */\r    int GetFd();\r\r  /**\r     * This method causes the socket to close, and may\r      * also be triggered by other methods such as OnTimeout\r         * and OnError.\r         */\r    virtual void Close();\r\r /**\r     * The destructor may implicitly call OnClose(), and\r    * will close() and shutdown() the file descriptor\r      * used for this socket.\r        */\r    virtual ~InspSocket();\r\r        /**\r     * This method attempts to connect to a hostname.\r       * This only occurs on a non-listening socket. This\r     * method is asyncronous.\r       */\r    virtual bool DoConnect();\r\r     /**\r     * This method marks the socket closed.\r         * The next time the core examines a socket marked\r      * as closed, the socket will be closed and the \r        * memory reclaimed.\r    *\r      * NOTE: This method is DEPRECIATED and will be\r         * ignored if called!\r   */\r    void MarkAsClosed();\r\r  /** Handle event from EventHandler parent class\r         */\r    void HandleEvent(EventType et, int errornum = 0);\r\r     /** Returns true if this socket is readable\r     */\r    bool Readable();\r};\r\r#endif\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *         the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __INSP_SOCKET_H__
+#define __INSP_SOCKET_H__
+
+#include <sstream>
+#include <string>
+#include <deque>
+#include "dns.h"
+#include "inspircd_config.h"
+#include "socket.h"
+#include "inspsocket.h"
+#include "timer.h"
+
+/**
+ * States which a socket may be in
+ */
+enum InspSocketState
+{
+       /** Socket disconnected */
+       I_DISCONNECTED,
+       /** Socket connecting */
+       I_CONNECTING,
+       /** Socket fully connected */
+       I_CONNECTED,
+       /** Socket listening for connections */
+       I_LISTENING,
+       /** Socket has an error */
+       I_ERROR
+};
+
+/**
+ * Error types which a socket may exhibit
+ */
+enum InspSocketError
+{
+       /** Socket connect timed out */
+       I_ERR_TIMEOUT,
+       /** Socket could not be created */
+       I_ERR_SOCKET,
+       /** Socket could not connect (refused) */
+       I_ERR_CONNECT,
+       /** Socket could not bind to local port/ip */
+       I_ERR_BIND,
+       /** Socket could not reslve host (depreciated) */
+       I_ERR_RESOLVE,
+       /** Socket could not write data */
+       I_ERR_WRITE,
+       /** No more file descriptors left to create socket! */
+       I_ERR_NOMOREFDS
+};
+
+/* Required forward declarations */
+class InspSocket;
+class InspIRCd;
+
+using irc::sockets::insp_sockaddr;
+using irc::sockets::insp_inaddr;
+using irc::sockets::insp_ntoa;
+using irc::sockets::insp_aton;
+
+/** Used to time out socket connections
+ */
+class CoreExport SocketTimeout : public InspTimer
+{
+ private:
+       /** InspSocket the class is attached to
+        */
+       InspSocket* sock;
+       /** Server instance creating the timeout class
+        */
+       InspIRCd* ServerInstance;
+       /** File descriptor of class this is attached to
+        */
+       int sfd;
+ public:
+       /** Create a socket timeout class
+        * @param fd File descriptor of InspSocket
+        * @pram Instance server instance to attach to
+        * @param thesock InspSocket to attach to
+        * @param secs_from_now Seconds from now to time out
+        * @param now The current time
+        */
+       SocketTimeout(int fd, InspIRCd* Instance, InspSocket* thesock, long secs_from_now, time_t now) : InspTimer(secs_from_now, now), sock(thesock), ServerInstance(Instance), sfd(fd) { };
+       /** Handle tick event
+        */
+       virtual void Tick(time_t now);
+};
+
+/**
+ * InspSocket is an extendable socket class which modules
+ * can use for TCP socket support. It is fully integrated
+ * into InspIRCds socket loop and attaches its sockets to
+ * the core's instance of the SocketEngine class, meaning
+ * that any sockets you create have the same power and
+ * abilities as a socket created by the core itself.
+ * To use InspSocket, you must inherit a class from it,
+ * and use the InspSocket constructors to establish connections
+ * and bindings.
+ */
+class CoreExport InspSocket : public EventHandler
+{
+ public:
+
+       /** 
+        * Bind IP
+        */
+       std::string cbindip;
+
+       /** 
+        * Is hooked by a module for low level IO
+        */
+       bool IsIOHooked;
+
+       /** 
+        * Instance we were created by
+        */
+       InspIRCd* Instance;
+
+       /** 
+        * Timeout class or NULL
+        */
+       SocketTimeout* Timeout;
+
+       /** 
+        * Timeout length
+        */
+       unsigned long timeout_val;
+
+       /** 
+        * Socket output buffer (binary safe)
+        */
+       std::deque<std::string> outbuffer;
+
+       /**
+        * The hostname connected to
+        */
+       char host[MAXBUF];
+
+       /**
+        * The port connected to, or the port
+        * this socket is listening on
+        */
+       int port;
+
+       /**
+        * The state for this socket, either
+        * listening, connecting, connected
+        * or error.
+        */
+       InspSocketState state;
+
+       /**
+        * This value is true if the
+        * socket has timed out.
+        */
+       bool timeout;
+       
+       /**
+        * Socket input buffer, used by read(). The class which
+        * extends InspSocket is expected to implement an extendable
+        * buffer which can grow much larger than 64k,
+        * this buffer is just designed to be temporary storage.
+        * space.
+        */
+       char ibuf[65535];
+
+       /**
+        * The IP address being connected
+        * to stored in string form for
+        * easy retrieval by accessors.
+        */
+       char IP[MAXBUF];
+
+       /**
+        * Used by accept() to indicate the
+        * sizes of the sockaddr_in structures
+        */
+       socklen_t length;
+
+       /** Flushes the write buffer
+        */
+       bool FlushWriteBuffer();
+
+       /** Set the queue sizes
+        * This private method sets the operating system queue
+        * sizes for this socket to 65535 so that it can queue
+        * more information without application-level queueing
+        * which was required in older software.
+        */
+       void SetQueues(int nfd);
+
+       /** When the socket has been marked as closing, this flag
+        * will be set to true, then the next time the socket is
+        * examined, the socket is deleted and closed.
+        */
+       bool ClosePending;
+
+       /** Set to true when we're waiting for a write event.
+        * If this is true and a write event comes in, we
+        * call the write instead of the read method.
+        */
+       bool WaitingForWriteEvent;
+
+       /**
+        * Bind to an address
+        * @param ip IP to bind to
+        * @return True is the binding succeeded
+        */
+       bool BindAddr(const std::string &ip);
+
+       /**
+        * The default constructor does nothing
+        * and should not be used.
+        */
+       InspSocket(InspIRCd* SI);
+
+       /**
+        * This constructor is used to associate
+        * an existing connecting with an InspSocket
+        * class. The given file descriptor must be
+        * valid, and when initialized, the InspSocket
+        * will be set with the given IP address
+        * and placed in CONNECTED state.
+        */
+       InspSocket(InspIRCd* SI, int newfd, const char* ip);
+
+       /**
+        * This constructor is used to create a new
+        * socket, either listening for connections, or an outbound connection to another host.
+        * Note that if you specify a hostname in the 'ipaddr' parameter, this class will not
+        * connect. You must resolve your hostnames before passing them to InspSocket. To do so,
+        * you should use the nonblocking class 'Resolver'.
+        * @param ipaddr The IP to connect to, or bind to
+        * @param port The port number to connect to, or bind to
+        * @param listening true to listen on the given host:port pair, or false to connect to them
+        * @param maxtime Number of seconds to wait, if connecting, before the connection times out and an OnTimeout() event is generated
+        * @param connectbindip When creating an outbound connection, the IP to bind the connection to. If not defined, the port is not bound.
+        * @return On exit, GetState() returns I_ERROR if an error occured, and errno can be used to read the socket error.
+        */
+       InspSocket(InspIRCd* SI, const std::string &ipaddr, int port, bool listening, unsigned long maxtime, const std::string &connectbindip = "");
+
+       /**
+        * This method is called when an outbound
+        * connection on your socket is completed.
+        * @return false to abort the connection, true to continue
+        */
+       virtual bool OnConnected();
+
+       /**
+        * This method is called when an error occurs.
+        * A closed socket in itself is not an error,
+        * however errors also generate close events.
+        * @param e The error type which occured
+        */
+       virtual void OnError(InspSocketError e);
+
+       /**
+        * When an established connection is terminated,
+        * the OnDisconnect method is triggered.
+        */
+       virtual int OnDisconnect();
+
+       /**
+        * When there is data waiting to be read on a
+        * socket, the OnDataReady() method is called.
+        * Within this method, you *MUST* call the Read()
+        * method to read any pending data. At its lowest
+        * level, this event is signalled by the core via
+        * the socket engine. If you return false from this
+        * function, the core removes your socket from its
+        * list and erases it from the socket engine, then
+        * calls InspSocket::Close() and deletes it.
+        * @return false to close the socket
+        */
+       virtual bool OnDataReady();
+
+       /**
+        * When it is ok to write to the socket, and a 
+        * write event was requested, this method is
+        * triggered. Within this method you should call
+        * write() or send() etc, to send data to the
+        * other end of the socket. Further write events
+        * will not be triggered unless you call WantWrite().
+        * @return false to close the socket
+        */
+       virtual bool OnWriteReady();
+
+       /**
+        * When an outbound connection fails, and the
+        * attempt times out, you will receive this event.
+        * The method will trigger once maxtime seconds are
+        * reached (as given in the constructor) just
+        * before the socket's descriptor is closed.
+        * A failed DNS lookup may cause this event if
+        * the DNS server is not responding, as well as
+        * a failed connect() call, because DNS lookups are
+        * nonblocking as implemented by this class.
+        */
+       virtual void OnTimeout();
+
+       /**
+        * Whenever close() is called, OnClose() will be
+        * called first. Please note that this means
+        * OnClose will be called alongside OnError(),
+        * OnTimeout(), and Close(), and also when
+        * cancelling a listening socket by calling
+        * the destructor indirectly.
+        */
+       virtual void OnClose();
+
+       /**
+        * Reads all pending bytes from the socket
+        * into a char* array which can be up to
+        * 16 kilobytes in length.
+        */
+       virtual char* Read();
+
+       /**
+        * Returns the IP address associated with
+        * this connection, or an empty string if
+        * no IP address exists.
+        */
+       std::string GetIP();
+
+       /**
+        * Writes a std::string to the socket. No carriage
+        * returns or linefeeds are appended to the string.
+        * @param data The data to send
+        */
+       virtual int Write(const std::string &data);
+
+       /**
+        * If your socket is a listening socket, when a new
+        * connection comes in on the socket this method will
+        * be called. Given the new file descriptor in the
+        * parameters, and the IP, it is recommended you copy
+        * them to a new instance of your socket class,
+        * e.g.:
+        *
+        * MySocket* newsocket = new MySocket(newfd,ip);
+        *
+        * Once you have done this, you can then associate the
+        * new socket with the core using Server::AddSocket().
+        */
+       virtual int OnIncomingConnection(int newfd, char* ip);
+
+       /**
+        * Changes the socket's state. The core uses this
+        * to change socket states, and you should not call
+        * it directly.
+        */
+       void SetState(InspSocketState s);
+
+       /**
+        * Call this to receive the next write event
+        * that comes along for this fd to the OnWriteReady
+        * method.
+        */
+       void WantWrite();
+
+       /**
+        * Returns the current socket state.
+        */
+       InspSocketState GetState();
+
+       /**
+        * Only the core should call this function.
+        * When called, it is assumed the socket is ready
+        * to read data, and the method call routes the
+        * event to the various methods of InspSocket
+        * for you to handle. This can also cause the
+        * socket's state to change.
+        */
+       bool Poll();
+
+       /**
+        * This method returns the socket's file descriptor
+        * as assigned by the operating system, or -1
+        * if no descriptor has been assigned.
+        */
+       int GetFd();
+
+       /**
+        * This method causes the socket to close, and may
+        * also be triggered by other methods such as OnTimeout
+        * and OnError.
+        */
+       virtual void Close();
+
+       /**
+        * The destructor may implicitly call OnClose(), and
+        * will close() and shutdown() the file descriptor
+        * used for this socket.
+        */
+       virtual ~InspSocket();
+
+       /**
+        * This method attempts to connect to a hostname.
+        * This only occurs on a non-listening socket. This
+        * method is asyncronous.
+        */
+       virtual bool DoConnect();
+
+       /**
+        * This method marks the socket closed.
+        * The next time the core examines a socket marked
+        * as closed, the socket will be closed and the 
+        * memory reclaimed.
+        *
+        * NOTE: This method is DEPRECIATED and will be
+        * ignored if called!
+        */
+       void MarkAsClosed();
+
+       /** Handle event from EventHandler parent class
+        */
+       void HandleEvent(EventType et, int errornum = 0);
+
+       /** Returns true if this socket is readable
+        */
+       bool Readable();
+};
+
+#endif
+
index 89abed94f4a8433498c2422fdb94810a97c3c5da..87024a9f8354abdc026602535263bd5c92c6efa1 100644 (file)
@@ -1 +1,56 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __IN_INSPSTRING_H\r#define __IN_INSPSTRING_H\r\r#include "inspircd_config.h"\r#include <string.h>\r#include <cstddef>\r\r#ifndef HAS_STRLCPY\r/** strlcpy() implementation for systems that don't have it (linux) */\rCoreExport size_t strlcpy(char *dst, const char *src, size_t siz);\r/** strlcat() implementation for systems that don't have it (linux) */\rCoreExport size_t strlcat(char *dst, const char *src, size_t siz);\r#endif\r\r/** charlcat() will append one character to a string using the same\r * safety scemantics as strlcat().\r * @param x The string to operate on\r * @param y the character to append to the end of x\r * @param z The maximum allowed length for z including null terminator\r */\rCoreExport int charlcat(char* x,char y,int z);\r/** charremove() will remove all instances of a character from a string\r * @param mp The string to operate on\r * @param remove The character to remove\r */\rCoreExport bool charremove(char* mp, char remove);\r\r/** strnewdup() is an implemenetation of strdup() which calls operator new\r * rather than malloc to allocate the new string, therefore allowing it to\r * be hooked into the C++ memory manager, and freed with operator delete.\r * This is required for windows, where we override operators new and delete\r * to allow for global allocation between modules and the core.\r */\rinline char * strnewdup(const char * s1)\r{\r     size_t len = strlen(s1) + 1;\r   char * p = new char[len];\r      memcpy(p, s1, len);\r    return p;\r}\r\r#endif\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __IN_INSPSTRING_H
+#define __IN_INSPSTRING_H
+
+#include "inspircd_config.h"
+#include <string.h>
+#include <cstddef>
+
+#ifndef HAS_STRLCPY
+/** strlcpy() implementation for systems that don't have it (linux) */
+CoreExport size_t strlcpy(char *dst, const char *src, size_t siz);
+/** strlcat() implementation for systems that don't have it (linux) */
+CoreExport size_t strlcat(char *dst, const char *src, size_t siz);
+#endif
+
+/** charlcat() will append one character to a string using the same
+ * safety scemantics as strlcat().
+ * @param x The string to operate on
+ * @param y the character to append to the end of x
+ * @param z The maximum allowed length for z including null terminator
+ */
+CoreExport int charlcat(char* x,char y,int z);
+/** charremove() will remove all instances of a character from a string
+ * @param mp The string to operate on
+ * @param remove The character to remove
+ */
+CoreExport bool charremove(char* mp, char remove);
+
+/** strnewdup() is an implemenetation of strdup() which calls operator new
+ * rather than malloc to allocate the new string, therefore allowing it to
+ * be hooked into the C++ memory manager, and freed with operator delete.
+ * This is required for windows, where we override operators new and delete
+ * to allow for global allocation between modules and the core.
+ */
+inline char * strnewdup(const char * s1)
+{
+       size_t len = strlen(s1) + 1;
+       char * p = new char[len];
+       memcpy(p, s1, len);
+       return p;
+}
+
+#endif
+
index 5f083552347b6a4633518c83cb1e487bf79873b0..6d91de1a89b0ea329bba1bb64beb0702f396be3a 100644 (file)
@@ -1 +1,519 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __MODE_H\r#define __MODE_H\r\r/* include the common header files */\r#include <string>\r#include <deque>\r#include <vector>\r#include "users.h"\r#include "channels.h"\r#include "ctables.h"\r\rclass InspIRCd;\r\r/**\r * Holds the values for different type of modes\r * that can exist, USER or CHANNEL type.\r */\renum ModeType\r{\r    /** User mode */\r       MODETYPE_USER = 0,\r     /** Channel mode */\r    MODETYPE_CHANNEL = 1\r};\r\r/**\r * Holds mode actions - modes can be allowed or denied.\r */\renum ModeAction\r{\r     MODEACTION_DENY = 0, /* Drop the mode change, AND a parameter if its a parameterized mode */\r   MODEACTION_ALLOW = 1 /* Allow the mode */\r};\r\r/**\r * Used to mask off the mode types in the mode handler\r * array. Used in a simple two instruction hashing function\r * "(modeletter - 65) OR mask"\r */\renum ModeMasks\r{\r       MASK_USER = 128,        /* A user mode */\r      MASK_CHANNEL = 0        /* A channel mode */\r};\r\r/**\r * These fixed values can be used to proportionally compare module-defined prefixes to known values.\r * For example, if your module queries a chanrec, and is told that user 'joebloggs' has the prefix\r * '$', and you dont know what $ means, then you can compare it to these three values to determine\r * its worth against them. For example if '$' had a value of 15000, you would know it is of higher\r * status than voice, but lower status than halfop.\r * No two modes should have equal prefix values.\r */\renum PrefixModeValue\r{\r     /* +v */\r       VOICE_VALUE     =       10000,\r /* +h */\r       HALFOP_VALUE    =       20000,\r /* +o */\r       OP_VALUE        =       30000\r};\r\r/**\r * Used by ModeHandler::ModeSet() to return the state of a mode upon a channel or user.\r * The pair contains an activity flag, true if the mode is set with the given parameter,\r * and the parameter of the mode (or the parameter provided) in the std::string.\r */\rtypedef std::pair<bool,std::string> ModePair;\r\r/** Each mode is implemented by ONE ModeHandler class.\r * You must derive ModeHandler and add the child class to\r * the list of modes handled by the ircd, using\r * ModeParser::AddMode. When the mode you implement is\r * set by a user, the virtual function OnModeChange is\r * called. If you specify a value greater than 0 for\r * parameters_on or parameters_off, then when the mode is\r * set or unset respectively, std::string &parameter will\r * contain the parameter given by the user, else it will\r * contain an empty string. You may alter this parameter\r * string, and if you alter it to an empty string, and your\r * mode is expected to have a parameter, then this is\r * equivalent to returning MODEACTION_DENY.\r */\rclass CoreExport ModeHandler : public Extensible\r{\r protected:\r  /**\r     * Creator/owner pointer\r        */\r    InspIRCd* ServerInstance;\r      /**\r     * The mode letter you're implementing.\r         */\r    char mode;\r     /**\r     * Number of parameters when being set\r  */\r    int n_params_on;\r       /**\r     * Number of parameters when being unset\r        */\r    int n_params_off;\r      /**\r     * Mode is a 'list' mode. The behaviour\r         * of your mode is now set entirely within\r      * the class as of the 1.1 api, rather than\r     * inside the mode parser as in the 1.0 api,\r    * so the only use of this value (along with\r    * IsListMode()) is for the core to determine\r   * wether your module can produce 'lists' or not\r        * (e.g. banlists, etc)\r         */\r    bool list;\r     /**\r     * The mode type, either MODETYPE_USER or\r       * MODETYPE_CHANNEL.\r    */\r    ModeType m_type;\r       /**\r     * True if the mode requires oper status\r        * to set.\r      */\r    bool oper;\r\r    /** Mode prefix, or 0\r   */\r    char prefix;\r\r  /** Number of items with this mode set on them\r  */\r    unsigned int count;\r\r public:\r  /**\r     * The constructor for ModeHandler initalizes the mode handler.\r         * The constructor of any class you derive from ModeHandler should\r      * probably call this constructor with the parameters set correctly.\r    * @param modeletter The mode letter you wish to handle\r         * @param parameters_on The number of parameters your mode takes when being set. Note that any nonzero value is treated as 1.\r   * @param parameters_off The number of parameters your mode takes when being unset. Note that any nonzero value is treated as 1.\r        * @param listmode Set to true if your mode is a listmode, e.g. it will respond to MODE #channel +modechar with a list of items\r         * @param ModeType Set this to MODETYPE_USER for a usermode, or MODETYPE_CHANNEL for a channelmode.\r     * @param operonly Set this to true if only opers should be allowed to set or unset the mode.\r   * @param mprefix For listmodes where parameters are NICKNAMES which are on the channel (for example, +ohv), you may define a prefix.\r   * When you define a prefix, it can be returned in NAMES, WHO etc if it has the highest value (as returned by GetPrefixRank())\r  * In the core, the only modes to implement prefixes are +ovh (ops, voice, halfop) which define the prefix characters @, % and +\r        * and the rank values OP_VALUE, HALFOP_VALUE and VOICE_VALUE respectively. Any prefixes you define should have unique values proportional\r      * to these three defaults or proportional to another mode in a module you depend on. See src/cmode_o.cpp as an example.\r        */\r    ModeHandler(InspIRCd* Instance, char modeletter, int parameters_on, int parameters_off, bool listmode, ModeType type, bool operonly, char mprefix = 0);\r        /**\r     * The default destructor does nothing\r  */\r    virtual ~ModeHandler();\r        /**\r     * Returns true if the mode is a list mode\r      */\r    bool IsListMode();\r     /**\r     * Mode prefix or 0. If this is defined, you should\r     * also implement GetPrefixRank() to return an integer\r  * value for this mode prefix.\r  */\r    char GetPrefix();\r      /** Get number of items with this mode set on them\r      */\r    virtual unsigned int GetCount();\r       /** Adjust usage count returned by GetCount\r     */\r    virtual void ChangeCount(int modifier);\r        /**\r     * Get the 'value' of this modes prefix.\r        * determines which to display when there are multiple.\r         * The mode with the highest value is ranked first. See the\r     * PrefixModeValue enum and chanrec::GetPrefixValue() for\r       * more information.\r    */\r    virtual unsigned int GetPrefixRank();\r  /**\r     * Returns the modes type\r       */\r    ModeType GetModeType();\r        /**\r     * Returns true if the mode can only be set/unset by an oper\r    */\r    bool NeedsOper();\r      /**\r     * Returns the number of parameters for the mode. Any non-zero\r  * value should be considered to be equivalent to one.\r  * @param adding If this is true, the number of parameters required to set the mode should be returned, otherwise the number of parameters required to unset the mode shall be returned.\r        * @return The number of parameters the mode expects\r    */\r    int GetNumParams(bool adding);\r /**\r     * Returns the mode character this handler handles.\r     * @return The mode character\r   */\r    char GetModeChar();\r\r   /**\r     * Called when a mode change for your mode occurs.\r      * @param source Contains the user setting the mode.\r    * @param dest For usermodes, contains the destination user the mode is being set on. For channelmodes, this is an undefined value.\r     * @param channel For channel modes, contains the destination channel the modes are being set on. For usermodes, this is an undefined value.\r    * @param parameter The parameter for your mode, if you indicated that your mode requires a parameter when being set or unset. Note that\r        * if you alter this value, the new value becomes the one displayed and send out to the network, also, if you set this to an empty string\r       * but you specified your mode REQUIRES a parameter, this is equivalent to returning MODEACTION_DENY and will prevent the mode from being\r       * displayed.\r   * @param adding This value is true when the mode is being set, or false when it is being unset.\r        * @return MODEACTION_ALLOW to allow the mode, or MODEACTION_DENY to prevent the mode, also see the description of 'parameter'.\r         */\r    virtual ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding); /* Can change the mode parameter as its a ref */\r       /**\r     * If your mode is a listmode, then this method will be called for displaying an item list, e.g. on MODE #channel +modechar\r     * without any parameter or other modes in the command.\r         * @param user The user issuing the command\r     * @parameter channel The channel they're requesting an item list of (e.g. a banlist, or an exception list etc)\r         */\r    virtual void DisplayList(userrec* user, chanrec* channel);\r     /**\r     * If your mode needs special action during a server sync to determine which side wins when comparing timestamps,\r       * override this function and use it to return true or false. The default implementation just returns true if\r   * theirs < ours. This will only be called for non-listmodes with parameters, when adding the mode and where\r    * theirs == ours (therefore the default implementation will always return false).\r      * @param theirs The timestamp of the remote side\r       * @param ours The timestamp of the local side\r  * @param their_param Their parameter if the mode has a parameter\r       * @param our_param Our parameter if the mode has a parameter\r   * @param channel The channel we are checking against\r   * @return True if the other side wins the merge, false if we win the merge for this mode.\r      */\r    virtual bool CheckTimeStamp(time_t theirs, time_t ours, const std::string &their_param, const std::string &our_param, chanrec* channel);\r\r      /**\r     * When a remote server needs to bounce a set of modes, it will call this method for every mode\r         * in the mode string to determine if the mode is set or not.\r   * @param source of the mode change, this will be NULL for a server mode\r        * @param dest Target user of the mode change, if this is a user mode\r   * @param channel Target channel of the mode change, if this is a channel mode\r  * @param parameter The parameter given for the mode change, or an empty string\r         * @returns The first value of the pair should be true if the mode is set with the given parameter.\r     * In the case of permissions modes such as channelmode +o, this should return true if the user given\r   * as the parameter has the given privilage on the given channel. The string value of the pair will hold\r        * the current setting for this mode set locally, when the bool is true, or, the parameter given.\r       * This allows the local server to enforce our locally set parameters back to a remote server.\r  */\r    virtual ModePair ModeSet(userrec* source, userrec* dest, chanrec* channel, const std::string &parameter);\r\r     /**\r     * When a MODETYPE_USER mode handler is being removed, the server will call this method for every user on the server.\r   * Your mode handler should remove its user mode from the user by sending the appropriate server modes using\r    * InspIRCd::SendMode(). The default implementation of this method can remove simple modes which have no parameters,\r    * and can be used when your mode is of this type, otherwise you must implement a more advanced version of it to remove\r         * your mode properly from each user.\r   * @param user The user which the server wants to remove your mode from\r         */\r    virtual void RemoveMode(userrec* user);\r\r       /**\r     * When a MODETYPE_CHANNEL mode handler is being removed, the server will call this method for every channel on the server.\r     * Your mode handler should remove its user mode from the channel by sending the appropriate server modes using\r         * InspIRCd::SendMode(). The default implementation of this method can remove simple modes which have no parameters,\r    * and can be used when your mode is of this type, otherwise you must implement a more advanced version of it to remove\r         * your mode properly from each channel. Note that in the case of listmodes, you should remove the entire list of items.\r        * @param channel The channel which the server wants to remove your mode from\r   */\r    virtual void RemoveMode(chanrec* channel);\r};\r\r/**\r * The ModeWatcher class can be used to alter the behaviour of a mode implemented\r * by the core or by another module. To use ModeWatcher, derive a class from it,\r * and attach it to the mode using Server::AddModeWatcher and Server::DelModeWatcher.\r * A ModeWatcher will be called both before and after the mode change.\r */\rclass CoreExport ModeWatcher : public Extensible\r{\r protected:\r  /**\r     * Creator/owner pointer\r        */\r    InspIRCd* ServerInstance;\r      /**\r     * The mode letter this class is watching\r       */\r    char mode;\r     /**\r     * The mode type being watched (user or  channel)\r       */\r    ModeType m_type;\r\r public:\r     /**\r     * The constructor initializes the mode and the mode type\r       */\r    ModeWatcher(InspIRCd* Instance, char modeletter, ModeType type);\r       /**\r     * The default destructor does nothing.\r         */\r    virtual ~ModeWatcher();\r\r       /**\r     * Get the mode character being watched\r         * @return The mode character being watched\r     */\r    char GetModeChar();\r    /**\r     * Get the mode type being watched\r      * @return The mode type being watched (user or channel)\r        */\r    ModeType GetModeType();\r\r       /**\r     * Before the mode character is processed by its handler, this method will be called.\r   * @param source The sender of the mode\r         * @param dest The target user for the mode, if you are watching a user mode\r    * @param channel The target channel for the mode, if you are watching a channel mode\r   * @param parameter The parameter of the mode, if the mode is supposed to have a parameter.\r     * If you alter the parameter you are given, the mode handler will see your atered version\r      * when it handles the mode.\r    * @param adding True if the mode is being added and false if it is being removed\r       * @type The mode type, either MODETYPE_USER or MODETYPE_CHANNEL\r        * @return True to allow the mode change to go ahead, false to abort it. If you abort the\r       * change, the mode handler (and ModeWatcher::AfterMode()) will never see the mode change.\r      */\r    virtual bool BeforeMode(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding, ModeType type);\r /**\r     * After the mode character has been processed by the ModeHandler, this method will be called.\r  * @param source The sender of the mode\r         * @param dest The target user for the mode, if you are watching a user mode\r    * @param channel The target channel for the mode, if you are watching a channel mode\r   * @param parameter The parameter of the mode, if the mode is supposed to have a parameter.\r     * You cannot alter the parameter here, as the mode handler has already processed it.\r   * @param adding True if the mode is being added and false if it is being removed\r       * @type The mode type, either MODETYPE_USER or MODETYPE_CHANNEL\r        */\r    virtual void AfterMode(userrec* source, userrec* dest, chanrec* channel, const std::string &parameter, bool adding, ModeType type);\r};\r\rtypedef std::vector<ModeWatcher*>::iterator ModeWatchIter;\r\r/** The mode parser handles routing of modes and handling of mode strings.\r * It marshalls, controls and maintains both ModeWatcher and ModeHandler classes,\r * parses client to server MODE strings for user and channel modes, and performs\r * processing for the 004 mode list numeric, amongst other things.\r */\rclass CoreExport ModeParser : public classbase\r{\r private:\r    /**\r     * Creator/owner pointer\r        */\r    InspIRCd* ServerInstance;\r      /** Mode handlers for each mode, to access a handler subtract\r   * 65 from the ascii value of the mode letter.\r  * The upper bit of the value indicates if its a usermode\r       * or a channel mode, so we have 256 of them not 64.\r    */\r    ModeHandler* modehandlers[256];\r        /** Mode watcher classes arranged in the same way as the\r        * mode handlers, except for instead of having 256 of them\r      * we have 256 lists of them.\r   */\r    std::vector<ModeWatcher*> modewatchers[256];\r   /** Displays the current modes of a channel or user.\r    * Used by ModeParser::Process.\r         */\r    void DisplayCurrentModes(userrec *user, userrec* targetuser, chanrec* targetchannel, const char* text);\r\r       /** The string representing the last set of modes to be parsed.\r         * Use GetLastParse() to get this value, to be used for  display purposes.\r      */\r    std::string LastParse;\r\r public:\r\r      /** The constructor initializes all the RFC basic modes by using ModeParserAddMode().\r   */\r    ModeParser(InspIRCd* Instance);\r\r       /** Used to check if user 'd' should be allowed to do operation 'MASK' on channel 'chan'.\r       * for example, should 'user A' be able to 'op' on 'channel B'.\r         */\r    userrec* SanityChecks(userrec *user,const char *dest,chanrec *chan,int status);\r        /** Grant a built in privilage (e.g. ops, halfops, voice) to a user on a channel\r        */\r    const char* Grant(userrec *d,chanrec *chan,int MASK);\r  /** Revoke a built in privilage (e.g. ops, halfops, voice) to a user on a channel\r       */\r    const char* Revoke(userrec *d,chanrec *chan,int MASK);\r /** Tidy a banmask. This makes a banmask 'acceptable' if fields are left out.\r   * E.g.\r         *\r      * nick -> nick!*@*\r     * \r     * nick!ident -> nick!ident@*\r   * \r     * host.name -> *!*@host.name\r   * \r     * ident@host.name -> *!ident@host.name\r         *\r      * This method can be used on both IPV4 and IPV6 user masks.\r    */\r    static void CleanMask(std::string &mask);\r      /** Get the last string to be processed, as it was sent to the user or channel. \r        * Use this to display a string you just sent to be parsed, as the actual output\r        * may be different to what you sent after it has been 'cleaned up' by the parser.\r      * @return Last parsed string, as seen by users.\r        */\r    const std::string& GetLastParse();\r     /** Add a mode to the mode parser. The modeletter parameter\r     * is purely to save on doing a lookup in the function, as\r      * strictly it could be obtained via ModeHandler::GetModeChar().\r        * @return True if the mode was successfully added.\r     */\r    bool AddMode(ModeHandler* mh, unsigned const char modeletter);\r /** Delete a mode from the mode parser.\r         * When a mode is deleted, the mode handler will be called\r      * for every user (if it is a user mode) or for every  channel\r  * (if it is a channel mode) to unset the mode on all objects.\r  * This prevents modes staying in the system which no longer exist.\r     * @param mh The mode handler to remove\r         * @return True if the mode was successfully removed.\r   */\r    bool DelMode(ModeHandler* mh);\r /** Add a mode watcher.\r         * A mode watcher is triggered before and after a mode handler is\r       * triggered. See the documentation of class ModeWatcher for more\r       * information.\r         * @param mw The ModeWatcher you want to add\r    * @return True if the ModeWatcher was added correctly\r  */\r    bool AddModeWatcher(ModeWatcher* mw);\r  /** Delete a mode watcher.\r      * A mode watcher is triggered before and after a mode handler is\r       * triggered. See the documentation of class ModeWatcher for more\r       * information.\r         * @param mw The ModeWatcher you want to delete\r         * @return True if the ModeWatcher was deleted correctly\r        */\r    bool DelModeWatcher(ModeWatcher* mw);\r  /** Process a set of mode changes from a server or user.\r        * @param parameters The parameters of the mode change, in the format\r   * they would be from a MODE command.\r   * @param pcnt The number of items in the parameters array\r      * @param user The user setting or removing the modes. When the modes are set\r   * by a server, an 'uninitialized' userrec is used, where *user::nick == NULL\r   * and *user->server == NULL.\r   * @param servermode True if a server is setting the mode.\r      */\r    void Process(const char** parameters, int pcnt, userrec *user, bool servermode);\r\r      /** Find the mode handler for a given mode and type.\r    * @param modeletter mode letter to search for\r  * @param type of mode to search for, user or channel\r   * @returns a pointer to a ModeHandler class, or NULL of there isnt a handler for the given mode\r        */\r    ModeHandler* FindMode(unsigned const char modeletter, ModeType mt);\r\r   /** Find a mode handler by its prefix.\r  * If there is no mode handler with the given prefix, NULL will be returned.\r    * @param pfxletter The prefix to find, e.g. '@'\r        * @return The mode handler which handles this prefix, or NULL if there is none.\r        */\r    ModeHandler* FindPrefix(unsigned const char pfxletter);\r\r       /** Returns a list of mode characters which are usermodes.\r      * This is used in the 004 numeric when users connect.\r  */\r    std::string UserModeList();\r\r   /** Returns a list of channel mode characters which are listmodes.\r      * This is used in the 004 numeric when users connect.\r  */\r    std::string ChannelModeList();\r\r        /** Returns a list of channel mode characters which take parameters.\r    * This is used in the 004 numeric when users connect.\r  */\r    std::string ParaModeList();\r\r   /** Generates the CHANMODES= 005 sequence\r       */\r    std::string ChanModes();\r       /** Used by this class internally during std::sort and 005 generation\r   */\r    static bool PrefixComparison(prefixtype one, prefixtype two);\r\r /** This returns the PREFIX=(ohv)@%+ section of the 005 numeric.\r        */\r    std::string BuildPrefixes();\r\r  /** This returns the privilages of a user upon a channel, in the format of a mode change.\r       * For example, if a user has privilages +avh, this will return the string "avh nick nick nick".\r        * This is used by the core when cycling a user to refresh their hostname. You may use it for\r   * similar purposes.\r    * @param user The username to look up\r  * @param channel The channel name to look up the privilages of the user for\r    * @return The mode string.\r     */\r    std::string ModeString(userrec* user, chanrec* channel);\r};\r\r#endif\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __MODE_H
+#define __MODE_H
+
+/* include the common header files */
+#include <string>
+#include <deque>
+#include <vector>
+#include "users.h"
+#include "channels.h"
+#include "ctables.h"
+
+class InspIRCd;
+
+/**
+ * Holds the values for different type of modes
+ * that can exist, USER or CHANNEL type.
+ */
+enum ModeType
+{
+       /** User mode */
+       MODETYPE_USER = 0,
+       /** Channel mode */
+       MODETYPE_CHANNEL = 1
+};
+
+/**
+ * Holds mode actions - modes can be allowed or denied.
+ */
+enum ModeAction
+{
+       MODEACTION_DENY = 0, /* Drop the mode change, AND a parameter if its a parameterized mode */
+       MODEACTION_ALLOW = 1 /* Allow the mode */
+};
+
+/**
+ * Used to mask off the mode types in the mode handler
+ * array. Used in a simple two instruction hashing function
+ * "(modeletter - 65) OR mask"
+ */
+enum ModeMasks
+{
+       MASK_USER = 128,        /* A user mode */
+       MASK_CHANNEL = 0        /* A channel mode */
+};
+
+/**
+ * These fixed values can be used to proportionally compare module-defined prefixes to known values.
+ * For example, if your module queries a chanrec, and is told that user 'joebloggs' has the prefix
+ * '$', and you dont know what $ means, then you can compare it to these three values to determine
+ * its worth against them. For example if '$' had a value of 15000, you would know it is of higher
+ * status than voice, but lower status than halfop.
+ * No two modes should have equal prefix values.
+ */
+enum PrefixModeValue
+{
+       /* +v */
+       VOICE_VALUE     =       10000,
+       /* +h */
+       HALFOP_VALUE    =       20000,
+       /* +o */
+       OP_VALUE        =       30000
+};
+
+/**
+ * Used by ModeHandler::ModeSet() to return the state of a mode upon a channel or user.
+ * The pair contains an activity flag, true if the mode is set with the given parameter,
+ * and the parameter of the mode (or the parameter provided) in the std::string.
+ */
+typedef std::pair<bool,std::string> ModePair;
+
+/** Each mode is implemented by ONE ModeHandler class.
+ * You must derive ModeHandler and add the child class to
+ * the list of modes handled by the ircd, using
+ * ModeParser::AddMode. When the mode you implement is
+ * set by a user, the virtual function OnModeChange is
+ * called. If you specify a value greater than 0 for
+ * parameters_on or parameters_off, then when the mode is
+ * set or unset respectively, std::string &parameter will
+ * contain the parameter given by the user, else it will
+ * contain an empty string. You may alter this parameter
+ * string, and if you alter it to an empty string, and your
+ * mode is expected to have a parameter, then this is
+ * equivalent to returning MODEACTION_DENY.
+ */
+class CoreExport ModeHandler : public Extensible
+{
+ protected:
+       /**
+        * Creator/owner pointer
+        */
+       InspIRCd* ServerInstance;
+       /**
+        * The mode letter you're implementing.
+        */
+       char mode;
+       /**
+        * Number of parameters when being set
+        */
+       int n_params_on;
+       /**
+        * Number of parameters when being unset
+        */
+       int n_params_off;
+       /**
+        * Mode is a 'list' mode. The behaviour
+        * of your mode is now set entirely within
+        * the class as of the 1.1 api, rather than
+        * inside the mode parser as in the 1.0 api,
+        * so the only use of this value (along with
+        * IsListMode()) is for the core to determine
+        * wether your module can produce 'lists' or not
+        * (e.g. banlists, etc)
+        */
+       bool list;
+       /**
+        * The mode type, either MODETYPE_USER or
+        * MODETYPE_CHANNEL.
+        */
+       ModeType m_type;
+       /**
+        * True if the mode requires oper status
+        * to set.
+        */
+       bool oper;
+
+       /** Mode prefix, or 0
+        */
+       char prefix;
+
+       /** Number of items with this mode set on them
+        */
+       unsigned int count;
+
+ public:
+       /**
+        * The constructor for ModeHandler initalizes the mode handler.
+        * The constructor of any class you derive from ModeHandler should
+        * probably call this constructor with the parameters set correctly.
+        * @param modeletter The mode letter you wish to handle
+        * @param parameters_on The number of parameters your mode takes when being set. Note that any nonzero value is treated as 1.
+        * @param parameters_off The number of parameters your mode takes when being unset. Note that any nonzero value is treated as 1.
+        * @param listmode Set to true if your mode is a listmode, e.g. it will respond to MODE #channel +modechar with a list of items
+        * @param ModeType Set this to MODETYPE_USER for a usermode, or MODETYPE_CHANNEL for a channelmode.
+        * @param operonly Set this to true if only opers should be allowed to set or unset the mode.
+        * @param mprefix For listmodes where parameters are NICKNAMES which are on the channel (for example, +ohv), you may define a prefix.
+        * When you define a prefix, it can be returned in NAMES, WHO etc if it has the highest value (as returned by GetPrefixRank())
+        * In the core, the only modes to implement prefixes are +ovh (ops, voice, halfop) which define the prefix characters @, % and +
+        * and the rank values OP_VALUE, HALFOP_VALUE and VOICE_VALUE respectively. Any prefixes you define should have unique values proportional
+        * to these three defaults or proportional to another mode in a module you depend on. See src/cmode_o.cpp as an example.
+        */
+       ModeHandler(InspIRCd* Instance, char modeletter, int parameters_on, int parameters_off, bool listmode, ModeType type, bool operonly, char mprefix = 0);
+       /**
+        * The default destructor does nothing
+        */
+       virtual ~ModeHandler();
+       /**
+        * Returns true if the mode is a list mode
+        */
+       bool IsListMode();
+       /**
+        * Mode prefix or 0. If this is defined, you should
+        * also implement GetPrefixRank() to return an integer
+        * value for this mode prefix.
+        */
+       char GetPrefix();
+       /** Get number of items with this mode set on them
+        */
+       virtual unsigned int GetCount();
+       /** Adjust usage count returned by GetCount
+        */
+       virtual void ChangeCount(int modifier);
+       /**
+        * Get the 'value' of this modes prefix.
+        * determines which to display when there are multiple.
+        * The mode with the highest value is ranked first. See the
+        * PrefixModeValue enum and chanrec::GetPrefixValue() for
+        * more information.
+        */
+       virtual unsigned int GetPrefixRank();
+       /**
+        * Returns the modes type
+        */
+       ModeType GetModeType();
+       /**
+        * Returns true if the mode can only be set/unset by an oper
+        */
+       bool NeedsOper();
+       /**
+        * Returns the number of parameters for the mode. Any non-zero
+        * value should be considered to be equivalent to one.
+        * @param adding If this is true, the number of parameters required to set the mode should be returned, otherwise the number of parameters required to unset the mode shall be returned.
+        * @return The number of parameters the mode expects
+        */
+       int GetNumParams(bool adding);
+       /**
+        * Returns the mode character this handler handles.
+        * @return The mode character
+        */
+       char GetModeChar();
+
+       /**
+        * Called when a mode change for your mode occurs.
+        * @param source Contains the user setting the mode.
+        * @param dest For usermodes, contains the destination user the mode is being set on. For channelmodes, this is an undefined value.
+        * @param channel For channel modes, contains the destination channel the modes are being set on. For usermodes, this is an undefined value.
+        * @param parameter The parameter for your mode, if you indicated that your mode requires a parameter when being set or unset. Note that
+        * if you alter this value, the new value becomes the one displayed and send out to the network, also, if you set this to an empty string
+        * but you specified your mode REQUIRES a parameter, this is equivalent to returning MODEACTION_DENY and will prevent the mode from being
+        * displayed.
+        * @param adding This value is true when the mode is being set, or false when it is being unset.
+        * @return MODEACTION_ALLOW to allow the mode, or MODEACTION_DENY to prevent the mode, also see the description of 'parameter'.
+        */
+       virtual ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding); /* Can change the mode parameter as its a ref */
+       /**
+        * If your mode is a listmode, then this method will be called for displaying an item list, e.g. on MODE #channel +modechar
+        * without any parameter or other modes in the command.
+        * @param user The user issuing the command
+        * @parameter channel The channel they're requesting an item list of (e.g. a banlist, or an exception list etc)
+        */
+       virtual void DisplayList(userrec* user, chanrec* channel);
+       /**
+        * If your mode needs special action during a server sync to determine which side wins when comparing timestamps,
+        * override this function and use it to return true or false. The default implementation just returns true if
+        * theirs < ours. This will only be called for non-listmodes with parameters, when adding the mode and where
+        * theirs == ours (therefore the default implementation will always return false).
+        * @param theirs The timestamp of the remote side
+        * @param ours The timestamp of the local side
+        * @param their_param Their parameter if the mode has a parameter
+        * @param our_param Our parameter if the mode has a parameter
+        * @param channel The channel we are checking against
+        * @return True if the other side wins the merge, false if we win the merge for this mode.
+        */
+       virtual bool CheckTimeStamp(time_t theirs, time_t ours, const std::string &their_param, const std::string &our_param, chanrec* channel);
+
+       /**
+        * When a remote server needs to bounce a set of modes, it will call this method for every mode
+        * in the mode string to determine if the mode is set or not.
+        * @param source of the mode change, this will be NULL for a server mode
+        * @param dest Target user of the mode change, if this is a user mode
+        * @param channel Target channel of the mode change, if this is a channel mode
+        * @param parameter The parameter given for the mode change, or an empty string
+        * @returns The first value of the pair should be true if the mode is set with the given parameter.
+        * In the case of permissions modes such as channelmode +o, this should return true if the user given
+        * as the parameter has the given privilage on the given channel. The string value of the pair will hold
+        * the current setting for this mode set locally, when the bool is true, or, the parameter given.
+        * This allows the local server to enforce our locally set parameters back to a remote server.
+        */
+       virtual ModePair ModeSet(userrec* source, userrec* dest, chanrec* channel, const std::string &parameter);
+
+       /**
+        * When a MODETYPE_USER mode handler is being removed, the server will call this method for every user on the server.
+        * Your mode handler should remove its user mode from the user by sending the appropriate server modes using
+        * InspIRCd::SendMode(). The default implementation of this method can remove simple modes which have no parameters,
+        * and can be used when your mode is of this type, otherwise you must implement a more advanced version of it to remove
+        * your mode properly from each user.
+        * @param user The user which the server wants to remove your mode from
+        */
+       virtual void RemoveMode(userrec* user);
+
+       /**
+        * When a MODETYPE_CHANNEL mode handler is being removed, the server will call this method for every channel on the server.
+        * Your mode handler should remove its user mode from the channel by sending the appropriate server modes using
+        * InspIRCd::SendMode(). The default implementation of this method can remove simple modes which have no parameters,
+        * and can be used when your mode is of this type, otherwise you must implement a more advanced version of it to remove
+        * your mode properly from each channel. Note that in the case of listmodes, you should remove the entire list of items.
+        * @param channel The channel which the server wants to remove your mode from
+        */
+       virtual void RemoveMode(chanrec* channel);
+};
+
+/**
+ * The ModeWatcher class can be used to alter the behaviour of a mode implemented
+ * by the core or by another module. To use ModeWatcher, derive a class from it,
+ * and attach it to the mode using Server::AddModeWatcher and Server::DelModeWatcher.
+ * A ModeWatcher will be called both before and after the mode change.
+ */
+class CoreExport ModeWatcher : public Extensible
+{
+ protected:
+       /**
+        * Creator/owner pointer
+        */
+       InspIRCd* ServerInstance;
+       /**
+        * The mode letter this class is watching
+        */
+       char mode;
+       /**
+        * The mode type being watched (user or  channel)
+        */
+       ModeType m_type;
+
+ public:
+       /**
+        * The constructor initializes the mode and the mode type
+        */
+       ModeWatcher(InspIRCd* Instance, char modeletter, ModeType type);
+       /**
+        * The default destructor does nothing.
+        */
+       virtual ~ModeWatcher();
+
+       /**
+        * Get the mode character being watched
+        * @return The mode character being watched
+        */
+       char GetModeChar();
+       /**
+        * Get the mode type being watched
+        * @return The mode type being watched (user or channel)
+        */
+       ModeType GetModeType();
+
+       /**
+        * Before the mode character is processed by its handler, this method will be called.
+        * @param source The sender of the mode
+        * @param dest The target user for the mode, if you are watching a user mode
+        * @param channel The target channel for the mode, if you are watching a channel mode
+        * @param parameter The parameter of the mode, if the mode is supposed to have a parameter.
+        * If you alter the parameter you are given, the mode handler will see your atered version
+        * when it handles the mode.
+        * @param adding True if the mode is being added and false if it is being removed
+        * @type The mode type, either MODETYPE_USER or MODETYPE_CHANNEL
+        * @return True to allow the mode change to go ahead, false to abort it. If you abort the
+        * change, the mode handler (and ModeWatcher::AfterMode()) will never see the mode change.
+        */
+       virtual bool BeforeMode(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding, ModeType type);
+       /**
+        * After the mode character has been processed by the ModeHandler, this method will be called.
+        * @param source The sender of the mode
+        * @param dest The target user for the mode, if you are watching a user mode
+        * @param channel The target channel for the mode, if you are watching a channel mode
+        * @param parameter The parameter of the mode, if the mode is supposed to have a parameter.
+        * You cannot alter the parameter here, as the mode handler has already processed it.
+        * @param adding True if the mode is being added and false if it is being removed
+        * @type The mode type, either MODETYPE_USER or MODETYPE_CHANNEL
+        */
+       virtual void AfterMode(userrec* source, userrec* dest, chanrec* channel, const std::string &parameter, bool adding, ModeType type);
+};
+
+typedef std::vector<ModeWatcher*>::iterator ModeWatchIter;
+
+/** The mode parser handles routing of modes and handling of mode strings.
+ * It marshalls, controls and maintains both ModeWatcher and ModeHandler classes,
+ * parses client to server MODE strings for user and channel modes, and performs
+ * processing for the 004 mode list numeric, amongst other things.
+ */
+class CoreExport ModeParser : public classbase
+{
+ private:
+       /**
+        * Creator/owner pointer
+        */
+       InspIRCd* ServerInstance;
+       /** Mode handlers for each mode, to access a handler subtract
+        * 65 from the ascii value of the mode letter.
+        * The upper bit of the value indicates if its a usermode
+        * or a channel mode, so we have 256 of them not 64.
+        */
+       ModeHandler* modehandlers[256];
+       /** Mode watcher classes arranged in the same way as the
+        * mode handlers, except for instead of having 256 of them
+        * we have 256 lists of them.
+        */
+       std::vector<ModeWatcher*> modewatchers[256];
+       /** Displays the current modes of a channel or user.
+        * Used by ModeParser::Process.
+        */
+       void DisplayCurrentModes(userrec *user, userrec* targetuser, chanrec* targetchannel, const char* text);
+
+       /** The string representing the last set of modes to be parsed.
+        * Use GetLastParse() to get this value, to be used for  display purposes.
+        */
+       std::string LastParse;
+
+ public:
+
+       /** The constructor initializes all the RFC basic modes by using ModeParserAddMode().
+        */
+       ModeParser(InspIRCd* Instance);
+
+       /** Used to check if user 'd' should be allowed to do operation 'MASK' on channel 'chan'.
+        * for example, should 'user A' be able to 'op' on 'channel B'.
+        */
+       userrec* SanityChecks(userrec *user,const char *dest,chanrec *chan,int status);
+       /** Grant a built in privilage (e.g. ops, halfops, voice) to a user on a channel
+        */
+       const char* Grant(userrec *d,chanrec *chan,int MASK);
+       /** Revoke a built in privilage (e.g. ops, halfops, voice) to a user on a channel
+        */
+       const char* Revoke(userrec *d,chanrec *chan,int MASK);
+       /** Tidy a banmask. This makes a banmask 'acceptable' if fields are left out.
+        * E.g.
+        *
+        * nick -> nick!*@*
+        * 
+        * nick!ident -> nick!ident@*
+        * 
+        * host.name -> *!*@host.name
+        * 
+        * ident@host.name -> *!ident@host.name
+        *
+        * This method can be used on both IPV4 and IPV6 user masks.
+        */
+       static void CleanMask(std::string &mask);
+       /** Get the last string to be processed, as it was sent to the user or channel. 
+        * Use this to display a string you just sent to be parsed, as the actual output
+        * may be different to what you sent after it has been 'cleaned up' by the parser.
+        * @return Last parsed string, as seen by users.
+        */
+       const std::string& GetLastParse();
+       /** Add a mode to the mode parser. The modeletter parameter
+        * is purely to save on doing a lookup in the function, as
+        * strictly it could be obtained via ModeHandler::GetModeChar().
+        * @return True if the mode was successfully added.
+        */
+       bool AddMode(ModeHandler* mh, unsigned const char modeletter);
+       /** Delete a mode from the mode parser.
+        * When a mode is deleted, the mode handler will be called
+        * for every user (if it is a user mode) or for every  channel
+        * (if it is a channel mode) to unset the mode on all objects.
+        * This prevents modes staying in the system which no longer exist.
+        * @param mh The mode handler to remove
+        * @return True if the mode was successfully removed.
+        */
+       bool DelMode(ModeHandler* mh);
+       /** Add a mode watcher.
+        * A mode watcher is triggered before and after a mode handler is
+        * triggered. See the documentation of class ModeWatcher for more
+        * information.
+        * @param mw The ModeWatcher you want to add
+        * @return True if the ModeWatcher was added correctly
+        */
+       bool AddModeWatcher(ModeWatcher* mw);
+       /** Delete a mode watcher.
+        * A mode watcher is triggered before and after a mode handler is
+        * triggered. See the documentation of class ModeWatcher for more
+        * information.
+        * @param mw The ModeWatcher you want to delete
+        * @return True if the ModeWatcher was deleted correctly
+        */
+       bool DelModeWatcher(ModeWatcher* mw);
+       /** Process a set of mode changes from a server or user.
+        * @param parameters The parameters of the mode change, in the format
+        * they would be from a MODE command.
+        * @param pcnt The number of items in the parameters array
+        * @param user The user setting or removing the modes. When the modes are set
+        * by a server, an 'uninitialized' userrec is used, where *user::nick == NULL
+        * and *user->server == NULL.
+        * @param servermode True if a server is setting the mode.
+        */
+       void Process(const char** parameters, int pcnt, userrec *user, bool servermode);
+
+       /** Find the mode handler for a given mode and type.
+        * @param modeletter mode letter to search for
+        * @param type of mode to search for, user or channel
+        * @returns a pointer to a ModeHandler class, or NULL of there isnt a handler for the given mode
+        */
+       ModeHandler* FindMode(unsigned const char modeletter, ModeType mt);
+
+       /** Find a mode handler by its prefix.
+        * If there is no mode handler with the given prefix, NULL will be returned.
+        * @param pfxletter The prefix to find, e.g. '@'
+        * @return The mode handler which handles this prefix, or NULL if there is none.
+        */
+       ModeHandler* FindPrefix(unsigned const char pfxletter);
+
+       /** Returns a list of mode characters which are usermodes.
+        * This is used in the 004 numeric when users connect.
+        */
+       std::string UserModeList();
+
+       /** Returns a list of channel mode characters which are listmodes.
+        * This is used in the 004 numeric when users connect.
+        */
+       std::string ChannelModeList();
+
+       /** Returns a list of channel mode characters which take parameters.
+        * This is used in the 004 numeric when users connect.
+        */
+       std::string ParaModeList();
+
+       /** Generates the CHANMODES= 005 sequence
+        */
+       std::string ChanModes();
+       /** Used by this class internally during std::sort and 005 generation
+        */
+       static bool PrefixComparison(prefixtype one, prefixtype two);
+
+       /** This returns the PREFIX=(ohv)@%+ section of the 005 numeric.
+        */
+       std::string BuildPrefixes();
+
+       /** This returns the privilages of a user upon a channel, in the format of a mode change.
+        * For example, if a user has privilages +avh, this will return the string "avh nick nick nick".
+        * This is used by the core when cycling a user to refresh their hostname. You may use it for
+        * similar purposes.
+        * @param user The username to look up
+        * @param channel The channel name to look up the privilages of the user for
+        * @return The mode string.
+        */
+       std::string ModeString(userrec* user, chanrec* channel);
+};
+
+#endif
+
index b9e403258b0a848df1fbc1cc8b58efc336b6a78c..2fe3de614f9515e0418aed1f6d8636d9ac660521 100644 (file)
@@ -1 +1,35 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "mode.h"\r#include "channels.h"\r\rclass InspIRCd;\r\r/** Channel mode +b\r */\rclass ModeChannelBan : public ModeHandler\r{\r private:\r   BanItem b;\r public:\r    ModeChannelBan(InspIRCd* Instance);\r    ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding);\r        std::string& AddBan(userrec *user,std::string& dest,chanrec *chan,int status);\r std::string& DelBan(userrec *user,std::string& dest,chanrec *chan,int status);\r void DisplayList(userrec* user, chanrec* channel);\r     ModePair ModeSet(userrec* source, userrec* dest, chanrec* channel, const std::string &parameter);\r      void RemoveMode(userrec* user);\r        void RemoveMode(chanrec* channel);\r};\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "mode.h"
+#include "channels.h"
+
+class InspIRCd;
+
+/** Channel mode +b
+ */
+class ModeChannelBan : public ModeHandler
+{
+ private:
+       BanItem b;
+ public:
+       ModeChannelBan(InspIRCd* Instance);
+       ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding);
+       std::string& AddBan(userrec *user,std::string& dest,chanrec *chan,int status);
+       std::string& DelBan(userrec *user,std::string& dest,chanrec *chan,int status);
+       void DisplayList(userrec* user, chanrec* channel);
+       ModePair ModeSet(userrec* source, userrec* dest, chanrec* channel, const std::string &parameter);
+       void RemoveMode(userrec* user);
+       void RemoveMode(chanrec* channel);
+};
+
index 9792fcb0058a14608de7e2f97165bd6b901d986a..77d1d57ae432a4c780c6ceb8e8c3772c5d9b8315 100644 (file)
@@ -1 +1,34 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "mode.h"\r#include "channels.h"\r\rclass InspIRCd;\r\r/** Channel mode +h\r */\rclass ModeChannelHalfOp : public ModeHandler\r{\r private:\r public:\r       ModeChannelHalfOp(InspIRCd* Instance);\r ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding);\r        std::string AddHalfOp(userrec *user,const char *dest,chanrec *chan,int status);\r        std::string DelHalfOp(userrec *user,const char *dest,chanrec *chan,int status);\r        ModePair ModeSet(userrec* source, userrec* dest, chanrec* channel, const std::string &parameter);\r      unsigned int GetPrefixRank();\r  void RemoveMode(chanrec* channel);\r     void RemoveMode(userrec* user);\r};\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "mode.h"
+#include "channels.h"
+
+class InspIRCd;
+
+/** Channel mode +h
+ */
+class ModeChannelHalfOp : public ModeHandler
+{
+ private:
+ public:
+       ModeChannelHalfOp(InspIRCd* Instance);
+       ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding);
+       std::string AddHalfOp(userrec *user,const char *dest,chanrec *chan,int status);
+       std::string DelHalfOp(userrec *user,const char *dest,chanrec *chan,int status);
+       ModePair ModeSet(userrec* source, userrec* dest, chanrec* channel, const std::string &parameter);
+       unsigned int GetPrefixRank();
+       void RemoveMode(chanrec* channel);
+       void RemoveMode(userrec* user);
+};
+
index 9df5314aa28716ff758051e8a008eec6c908f445..fb177dc0f85712aa6c1391b8c01e4cb04486f0e5 100644 (file)
@@ -1 +1,25 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "mode.h"\r\rclass InspIRCd;\r\r/** Channel mode +i\r */\rclass ModeChannelInviteOnly : public ModeHandler\r{\r public:\r   ModeChannelInviteOnly(InspIRCd* Instance);\r     ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding);\r};\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "mode.h"
+
+class InspIRCd;
+
+/** Channel mode +i
+ */
+class ModeChannelInviteOnly : public ModeHandler
+{
+ public:
+       ModeChannelInviteOnly(InspIRCd* Instance);
+       ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding);
+};
index 695518bf9ec5e59e5235569e04c33d6316932701..51e8ffcaa00fb6d92dff8c45689f6a594de388d9 100644 (file)
@@ -1 +1,29 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "mode.h"\r\rclass InspIRCd;\r\r/** Channel mode +k\r */\rclass ModeChannelKey : public ModeHandler\r{\r public:\r  ModeChannelKey(InspIRCd* Instance);\r    ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding);\r        ModePair ModeSet(userrec* source, userrec* dest, chanrec* channel, const std::string &parameter);\r      bool CheckTimeStamp(time_t theirs, time_t ours, const std::string &their_param, const std::string &our_param, chanrec* channel);\r       void RemoveMode(chanrec* channel);\r     void RemoveMode(userrec* user);\r};\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "mode.h"
+
+class InspIRCd;
+
+/** Channel mode +k
+ */
+class ModeChannelKey : public ModeHandler
+{
+ public:
+       ModeChannelKey(InspIRCd* Instance);
+       ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding);
+       ModePair ModeSet(userrec* source, userrec* dest, chanrec* channel, const std::string &parameter);
+       bool CheckTimeStamp(time_t theirs, time_t ours, const std::string &their_param, const std::string &our_param, chanrec* channel);
+       void RemoveMode(chanrec* channel);
+       void RemoveMode(userrec* user);
+};
index 49228479fe1e1d2048d259c502160d5b051ea8c7..63b4a1ef11c2a75151e30164581630521578b6da 100644 (file)
@@ -1 +1,27 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "mode.h"\r\rclass InspIRCd;\r\r/** Channel mode +l\r */\rclass ModeChannelLimit : public ModeHandler\r{\r public:\r        ModeChannelLimit(InspIRCd* Instance);\r  ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding);\r        ModePair ModeSet(userrec* source, userrec* dest, chanrec* channel, const std::string &parameter);\r      bool CheckTimeStamp(time_t theirs, time_t ours, const std::string &their_param, const std::string &our_param, chanrec* channel);\r};\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "mode.h"
+
+class InspIRCd;
+
+/** Channel mode +l
+ */
+class ModeChannelLimit : public ModeHandler
+{
+ public:
+       ModeChannelLimit(InspIRCd* Instance);
+       ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding);
+       ModePair ModeSet(userrec* source, userrec* dest, chanrec* channel, const std::string &parameter);
+       bool CheckTimeStamp(time_t theirs, time_t ours, const std::string &their_param, const std::string &our_param, chanrec* channel);
+};
index 885b0321e6c996530d2fa34deb22cce96d22462a..52288de4c7a017cb085fa167e772e8b9ff5cdbc7 100644 (file)
@@ -1 +1,25 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "mode.h"\r\rclass InspIRCd;\r\r/** Channel mode +m\r */\rclass ModeChannelModerated : public ModeHandler\r{\r public:\r    ModeChannelModerated(InspIRCd* Instance);\r      ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding);\r};\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "mode.h"
+
+class InspIRCd;
+
+/** Channel mode +m
+ */
+class ModeChannelModerated : public ModeHandler
+{
+ public:
+       ModeChannelModerated(InspIRCd* Instance);
+       ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding);
+};
index dcc0edccb0c8adabc690f06a764fa0a5e3d2eb14..953e0d6717b27d91410f75686018f533aa98c141 100644 (file)
@@ -1 +1,25 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "mode.h"\r\rclass InspIRCd;\r\r/** Channel mode +n\r */\rclass ModeChannelNoExternal : public ModeHandler\r{\r public:\r   ModeChannelNoExternal(InspIRCd* Instance);\r     ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding);\r};\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "mode.h"
+
+class InspIRCd;
+
+/** Channel mode +n
+ */
+class ModeChannelNoExternal : public ModeHandler
+{
+ public:
+       ModeChannelNoExternal(InspIRCd* Instance);
+       ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding);
+};
index 4198a3f20e92b1ba741c2b060db23cafbb5492cf..c86fb4586d4c66e98c64328aa4d2a8c389719452 100644 (file)
@@ -1 +1,34 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "mode.h"\r#include "channels.h"\r\rclass InspIRCd;\r\r/** Channel mode +o\r */\rclass ModeChannelOp : public ModeHandler\r{\r private:\r public:\r   ModeChannelOp(InspIRCd* Instance);\r     ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding);\r        std::string AddOp(userrec *user,const char *dest,chanrec *chan,int status);\r    std::string DelOp(userrec *user,const char *dest,chanrec *chan,int status);\r    ModePair ModeSet(userrec* source, userrec* dest, chanrec* channel, const std::string &parameter);\r      unsigned int GetPrefixRank();\r  void RemoveMode(chanrec* channel);\r     void RemoveMode(userrec* user);\r};\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "mode.h"
+#include "channels.h"
+
+class InspIRCd;
+
+/** Channel mode +o
+ */
+class ModeChannelOp : public ModeHandler
+{
+ private:
+ public:
+       ModeChannelOp(InspIRCd* Instance);
+       ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding);
+       std::string AddOp(userrec *user,const char *dest,chanrec *chan,int status);
+       std::string DelOp(userrec *user,const char *dest,chanrec *chan,int status);
+       ModePair ModeSet(userrec* source, userrec* dest, chanrec* channel, const std::string &parameter);
+       unsigned int GetPrefixRank();
+       void RemoveMode(chanrec* channel);
+       void RemoveMode(userrec* user);
+};
+
index 123827ea79592006c8ad2b11d3c98eea4fc5d111..ad3f3ae89326d5a03eb2a5b2e43d6d5bde484118 100644 (file)
@@ -1 +1,25 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "mode.h"\r\rclass InspIRCd;\r\r/** Channel mode +p\r */\rclass ModeChannelPrivate : public ModeHandler\r{\r public:\r      ModeChannelPrivate(InspIRCd* Instance);\r        ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding);\r};\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "mode.h"
+
+class InspIRCd;
+
+/** Channel mode +p
+ */
+class ModeChannelPrivate : public ModeHandler
+{
+ public:
+       ModeChannelPrivate(InspIRCd* Instance);
+       ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding);
+};
index 383e5c083d6026926504165a3ba10c296109fc53..0bc229c37cc4e8e521fbd715f60b4517608a5c97 100644 (file)
@@ -1 +1,25 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "mode.h"\r\rclass InspIRCd;\r\r/** Channel mode +s\r */\rclass ModeChannelSecret : public ModeHandler\r{\r public:\r       ModeChannelSecret(InspIRCd* Instance);\r ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding);\r};\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "mode.h"
+
+class InspIRCd;
+
+/** Channel mode +s
+ */
+class ModeChannelSecret : public ModeHandler
+{
+ public:
+       ModeChannelSecret(InspIRCd* Instance);
+       ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding);
+};
index 4ddd51730e36cd59be5f2645478fc3d857deb3b2..8a7517ee336b1628f00643173c51f33fc9dc31d6 100644 (file)
@@ -1 +1,25 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "mode.h"\r\rclass InspIRCd;\r\r/** Channel mode +t\r */\rclass ModeChannelTopicOps : public ModeHandler\r{\r public:\r     ModeChannelTopicOps(InspIRCd* Instance);\r       ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding);\r};\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "mode.h"
+
+class InspIRCd;
+
+/** Channel mode +t
+ */
+class ModeChannelTopicOps : public ModeHandler
+{
+ public:
+       ModeChannelTopicOps(InspIRCd* Instance);
+       ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding);
+};
index a1d40ddc4edde84eb430862413b35ab45c389ca2..75420a6d557f15a25e77a67c32eca0f8d6f67919 100644 (file)
@@ -1 +1,34 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "mode.h"\r#include "channels.h"\r\rclass InspIRCd;\r\r/** Channel mode +v\r */\rclass ModeChannelVoice : public ModeHandler\r{\r private:\r public:\r        ModeChannelVoice(InspIRCd* Instance);\r  ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding);\r        std::string AddVoice(userrec *user,const char *dest,chanrec *chan,int status);\r std::string DelVoice(userrec *user,const char *dest,chanrec *chan,int status);\r ModePair ModeSet(userrec* source, userrec* dest, chanrec* channel, const std::string &parameter);\r      unsigned int GetPrefixRank();\r  void RemoveMode(userrec* user);\r        void RemoveMode(chanrec* channel);\r};\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "mode.h"
+#include "channels.h"
+
+class InspIRCd;
+
+/** Channel mode +v
+ */
+class ModeChannelVoice : public ModeHandler
+{
+ private:
+ public:
+       ModeChannelVoice(InspIRCd* Instance);
+       ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding);
+       std::string AddVoice(userrec *user,const char *dest,chanrec *chan,int status);
+       std::string DelVoice(userrec *user,const char *dest,chanrec *chan,int status);
+       ModePair ModeSet(userrec* source, userrec* dest, chanrec* channel, const std::string &parameter);
+       unsigned int GetPrefixRank();
+       void RemoveMode(userrec* user);
+       void RemoveMode(chanrec* channel);
+};
+
index 4319ac0a50fb6fccda65f1f7c36f050f418445d9..cc7d15102b104dca573dbbf4e7d54ff8efb319ad 100644 (file)
@@ -1 +1,26 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "mode.h"\r\rclass InspIRCd;\r\r/** User mode +i\r */\rclass ModeUserInvisible : public ModeHandler\r{\r public:\r  ModeUserInvisible(InspIRCd* Instance);\r ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding);\r        unsigned int GetCount();\r};\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "mode.h"
+
+class InspIRCd;
+
+/** User mode +i
+ */
+class ModeUserInvisible : public ModeHandler
+{
+ public:
+       ModeUserInvisible(InspIRCd* Instance);
+       ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding);
+       unsigned int GetCount();
+};
index 9a944d41c6bc045044b2e850d55ae0e4751cab1f..cd1275accbcd46d6a61606a990a1147827b86d17 100644 (file)
@@ -1 +1,25 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "mode.h"\r\rclass InspIRCd;\r\r/** User mode +n\r */\rclass ModeUserServerNoticeMask : public ModeHandler\r{\r public:\r   ModeUserServerNoticeMask(InspIRCd* Instance);\r  ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding);\r};\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "mode.h"
+
+class InspIRCd;
+
+/** User mode +n
+ */
+class ModeUserServerNoticeMask : public ModeHandler
+{
+ public:
+       ModeUserServerNoticeMask(InspIRCd* Instance);
+       ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding);
+};
index 7548a087a52f536a4e1d87ed524dd88caaa8b5fa..7dfdb41280e2eff1217818ba301ba8d898bb141d 100644 (file)
@@ -1 +1,26 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "mode.h"\r\rclass InspIRCd;\r\r/** User mode +o\r */\rclass ModeUserOperator : public ModeHandler\r{\r public:\r   ModeUserOperator(InspIRCd* Instance);\r  ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding);\r        unsigned int GetCount();\r};\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "mode.h"
+
+class InspIRCd;
+
+/** User mode +o
+ */
+class ModeUserOperator : public ModeHandler
+{
+ public:
+       ModeUserOperator(InspIRCd* Instance);
+       ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding);
+       unsigned int GetCount();
+};
index 98264298b4db0ea6823eb1b4525d77fc4e5c9bb6..cda223eee1572c596855a2b323cf5510f8ec05e5 100644 (file)
@@ -1 +1,26 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "mode.h"\r\rclass InspIRCd;\r\r/** User mode +s\r */\rclass ModeUserServerNotice : public ModeHandler\r{\r public:\r       ModeUserServerNotice(InspIRCd* Instance);\r      ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding);\r        unsigned int GetCount();\r};\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "mode.h"
+
+class InspIRCd;
+
+/** User mode +s
+ */
+class ModeUserServerNotice : public ModeHandler
+{
+ public:
+       ModeUserServerNotice(InspIRCd* Instance);
+       ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding);
+       unsigned int GetCount();
+};
index 26e21446035631433a4ce9e00d09ee54118160eb..271e959c4a2522f5c51e88eb5b2e6dc16ca35a97 100644 (file)
@@ -1 +1,26 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "mode.h"\r\rclass InspIRCd;\r\r/** User mode +w\r */\rclass ModeUserWallops : public ModeHandler\r{\r public:\r    ModeUserWallops(InspIRCd* Instance);\r   ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding);\r        unsigned int GetCount();\r};\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "mode.h"
+
+class InspIRCd;
+
+/** User mode +w
+ */
+class ModeUserWallops : public ModeHandler
+{
+ public:
+       ModeUserWallops(InspIRCd* Instance);
+       ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding);
+       unsigned int GetCount();
+};
index 51d117b172f46b94dc952cf579f0a5d5fb48a34c..389fa6184455bdce3f639b8f47cb75cd4fba39bf 100644 (file)
@@ -1 +1,1696 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *        the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __MODULES_H\r#define __MODULES_H\r\r/** Used with OnAccessCheck() method of modules\r */\renum AccessControlType {\r ACR_DEFAULT,            // Do default action (act as if the module isnt even loaded)\r   ACR_DENY,               // deny the action\r     ACR_ALLOW,              // allow the action\r    AC_KICK,                // a user is being kicked\r      AC_DEOP,                // a user is being deopped\r     AC_OP,                  // a user is being opped\r       AC_VOICE,               // a user is being voiced\r      AC_DEVOICE,             // a user is being devoiced\r    AC_HALFOP,              // a user is being halfopped\r   AC_DEHALFOP,            // a user is being dehalfopped\r AC_INVITE,              // a user is being invited\r     AC_GENERAL_MODE         // a channel mode is being changed\r};\r\r/** Used to define a set of behavior bits for a module\r */\renum ModuleFlags {\r   VF_STATIC = 1,          // module is static, cannot be /unloadmodule'd\r VF_VENDOR = 2,          // module is a vendor module (came in the original tarball, not 3rd party)\r     VF_SERVICEPROVIDER = 4, // module provides a service to other modules (can be a dependency)\r    VF_COMMON = 8           // module needs to be common on all servers in a network to link\r};\r\r/** Used with SendToMode()\r */\renum WriteModeFlags {\r      WM_AND = 1,\r    WM_OR = 2\r};\r\r/** Used to represent an event type, for user, channel or server\r */\renum TargetTypeFlags {\r      TYPE_USER = 1,\r TYPE_CHANNEL,\r  TYPE_SERVER,\r   TYPE_OTHER\r};\r\r/** Used to represent wether a message was PRIVMSG or NOTICE\r */\renum MessageType {\r     MSG_PRIVMSG = 0,\r       MSG_NOTICE = 1\r};\r\r#include "globals.h"\r#include "dynamic.h"\r#include "base.h"\r#include "ctables.h"\r#include "inspsocket.h"\r#include <string>\r#include <deque>\r#include <sstream>\r#include "timer.h"\r#include "mode.h"\r#include "dns.h"\r\r/** If you change the module API, change this value.\r * If you have enabled ipv6, the sizes of structs is\r * different, and modules will be incompatible with\r * ipv4 servers, so this value will be ten times as\r * high on ipv6 servers.\r */\r#define NATIVE_API_VERSION 11025\r#ifdef IPV6\r#define API_VERSION (NATIVE_API_VERSION * 10)\r#else\r#define API_VERSION (NATIVE_API_VERSION * 1)\r#endif\r\rclass ServerConfig;\r\r/* Forward-delacare module for ModuleMessage etc\r */\rclass Module;\r\r/** Low level definition of a FileReader classes file cache area -\r * a text file seperated into lines.\r */\rtypedef std::deque<std::string> file_cache;\r\r/** A set of strings.\r */\rtypedef file_cache string_list;\r\r/** Holds a list of 'published features' for modules.\r */\rtypedef std::map<std::string,Module*> featurelist;\r\r/** Holds a list of modules which implement an interface\r */\rtypedef std::deque<Module*> modulelist;\r\r/** Holds a list of all modules which implement interfaces, by interface name\r */\rtypedef std::map<std::string, std::pair<int, modulelist> > interfacelist;\r\r/**\r * This #define allows us to call a method in all\r * loaded modules in a readable simple way, e.g.:\r * 'FOREACH_MOD(I_OnConnect,OnConnect(user));'\r */\r#define FOREACH_MOD(y,x) if (ServerInstance->Config->global_implementation[y] > 0) { \\r  for (int _i = 0; _i <= ServerInstance->GetModuleCount(); _i++) { \\r     if (ServerInstance->Config->implement_lists[_i][y]) \\r          try \\r          { \\r                    ServerInstance->modules[_i]->x ; \\r             } \\r            catch (CoreException& modexcept) \\r             { \\r                    ServerInstance->Log(DEFAULT,"Exception cought: %s",modexcept.GetReason()); \\r           } \\r    } \\r  }\r\r/**\r * This #define allows us to call a method in all\r * loaded modules in a readable simple way and pass\r * an instance pointer to the macro. e.g.:\r * 'FOREACH_MOD_I(Instance, OnConnect, OnConnect(user));'\r */\r#define FOREACH_MOD_I(z,y,x) if (z->Config->global_implementation[y] > 0) { \\r      for (int _i = 0; _i <= z->GetModuleCount(); _i++) { \\r          if (z->Config->implement_lists[_i][y]) \\r               try \\r          { \\r                    z->modules[_i]->x ; \\r          } \\r            catch (CoreException& modexcept) \\r             { \\r                    z->Log(DEFAULT,"Exception cought: %s",modexcept.GetReason()); \\r                } \\r    } \\r}\r/**\r * This define is similar to the one above but returns a result in MOD_RESULT.\r * The first module to return a nonzero result is the value to be accepted,\r * and any modules after are ignored.\r */\r#define FOREACH_RESULT(y,x) { if (ServerInstance->Config->global_implementation[y] > 0) { \\r                     MOD_RESULT = 0; \\r                      for (int _i = 0; _i <= ServerInstance->GetModuleCount(); _i++) { \\r                     if (ServerInstance->Config->implement_lists[_i][y]) { \\r                                try \\r                          { \\r                                    int res = ServerInstance->modules[_i]->x ; \\r                                   if (res != 0) { \\r                                              MOD_RESULT = res; \\r                                            break; \\r                                       } \\r                            } \\r                            catch (CoreException& modexcept) \\r                             { \\r                                    ServerInstance->Log(DEFAULT,"Exception cought: %s",modexcept.GetReason()); \\r                           } \\r                    } \\r            } \\r    } \\r }\r\r/**\r * This define is similar to the one above but returns a result in MOD_RESULT.\r * The first module to return a nonzero result is the value to be accepted,\r * and any modules after are ignored.\r */\r#define FOREACH_RESULT_I(z,y,x) { if (z->Config->global_implementation[y] > 0) { \\r                    MOD_RESULT = 0; \\r                      for (int _i = 0; _i <= z->GetModuleCount(); _i++) { \\r                  if (z->Config->implement_lists[_i][y]) { \\r                             try \\r                          { \\r                                    int res = z->modules[_i]->x ; \\r                                        if (res != 0) { \\r                                              MOD_RESULT = res; \\r                                            break; \\r                                       } \\r                            } \\r                            catch (CoreException& modexcept) \\r                             { \\r                                    z->Log(DEBUG,"Exception cought: %s",modexcept.GetReason()); \\r                          } \\r                    } \\r            } \\r    } \\r}\r\r/** Represents a non-local user.\r * (in fact, any FD less than -1 does)\r */\r#define FD_MAGIC_NUMBER -42\r\r/* Useful macros */\r#ifdef WINDOWS\r/** Is a local user */\r#define IS_LOCAL(x) ((x->GetFd() > -1))\r#else\r/** Is a local user */\r#define IS_LOCAL(x) ((x->GetFd() > -1) && (x->GetFd() <= MAX_DESCRIPTORS))\r#endif\r/** Is a remote user */\r#define IS_REMOTE(x) (x->GetFd() < 0)\r/** Is a module created user */\r#define IS_MODULE_CREATED(x) (x->GetFd() == FD_MAGIC_NUMBER)\r/** Is an oper */\r#define IS_OPER(x) (*x->oper)\r/** Is away */\r#define IS_AWAY(x) (*x->awaymsg)\r\r/** Holds a module's Version information.\r *  The four members (set by the constructor only) indicate details as to the version number\r *  of a module. A class of type Version is returned by the GetVersion method of the Module class.\r *  The flags and API values represent the module flags and API version of the module.\r *  The API version of a module must match the API version of the core exactly for the module to\r *  load successfully.\r */\rclass CoreExport Version : public classbase\r{\r public:\r        /** Version numbers, build number, flags and API version\r        */\r    const int Major, Minor, Revision, Build, Flags, API;\r\r  /** Initialize version class\r    */\r    Version(int major, int minor, int revision, int build, int flags, int api_ver);\r};\r\r/** The ModuleMessage class is the base class of Request and Event\r * This class is used to represent a basic data structure which is passed\r * between modules for safe inter-module communications.\r */\rclass CoreExport ModuleMessage : public Extensible\r{\r public:\r   /** Destructor\r  */\r    virtual ~ModuleMessage() {};\r};\r\r/** The Request class is a unicast message directed at a given module.\r * When this class is properly instantiated it may be sent to a module\r * using the Send() method, which will call the given module's OnRequest\r * method with this class as its parameter.\r */\rclass CoreExport Request : public ModuleMessage\r{\r protected:\r  /** This member holds a pointer to arbitary data set by the emitter of the message\r      */\r    char* data;\r    /** This should be a null-terminated string identifying the type of request,\r    * all modules should define this and use it to determine the nature of the\r     * request before they attempt to cast the Request in any way.\r          */\r    const char* id;\r        /** This is a pointer to the sender of the message, which can be used to\r        * directly trigger events, or to create a reply.\r       */\r    Module* source;\r        /** The single destination of the Request\r       */\r    Module* dest;\r public:\r /** Create a new Request\r        * This is for the 'old' way of casting whatever the data is\r    * to char* and hoping you get the right thing at the other end.\r        * This is slowly being depreciated in favor of the 'new' way.\r  */\r    Request(char* anydata, Module* src, Module* dst);\r      /** Create a new Request\r        * This is for the 'new' way of defining a subclass\r     * of Request and defining it in a common header,\r       * passing an object of your Request subclass through\r   * as a Request* and using the ID string to determine\r   * what to cast it back to and the other end. This is\r   * much safer as there are no casts not confirmed by\r    * the ID string, and all casts are child->parent and\r   * can be checked at runtime with dynamic_cast<>()\r      */\r    Request(Module* src, Module* dst, const char* idstr);\r  /** Fetch the Request data\r      */\r    char* GetData();\r       /** Fetch the ID string\r         */\r    const char* GetId();\r   /** Fetch the request source\r    */\r    Module* GetSource();\r   /** Fetch the request destination (should be 'this' in the receiving module)\r    */\r    Module* GetDest();\r     /** Send the Request.\r   * Upon returning the result will be arbitary data returned by the module you\r   * sent the request to. It is up to your module to know what this data is and\r   * how to deal with it.\r         */\r    char* Send();\r};\r\r\r/** The Event class is a unicast message directed at all modules.\r * When the class is properly instantiated it may be sent to all modules\r * using the Send() method, which will trigger the OnEvent method in\r * all modules passing the object as its parameter.\r */\rclass CoreExport Event : public ModuleMessage\r{\r protected:\r /** This member holds a pointer to arbitary data set by the emitter of the message\r      */\r    char* data;\r    /** This is a pointer to the sender of the message, which can be used to\r        * directly trigger events, or to create a reply.\r       */\r    Module* source;\r        /** The event identifier.\r       * This is arbitary text which should be used to distinguish\r    * one type of event from another.\r      */\r    std::string id;\r public:\r       /** Create a new Event\r  */\r    Event(char* anydata, Module* src, const std::string &eventid);\r /** Get the Event data\r  */\r    char* GetData();\r       /** Get the event Source\r        */\r    Module* GetSource();\r   /** Get the event ID.\r   * Use this to determine the event type for safe casting of the data\r    */\r    std::string GetEventID();\r      /** Send the Event.\r     * The return result of an Event::Send() will always be NULL as\r         * no replies are expected.\r     */\r    char* Send(InspIRCd* ServerInstance);\r};\r\r/** This class can be used on its own to represent an exception, or derived to represent a module-specific exception.\r * When a module whishes to abort, e.g. within a constructor, it should throw an exception using ModuleException or\r * a class derived from ModuleException. If a module throws an exception during its constructor, the module will not\r * be loaded. If this happens, the error message returned by ModuleException::GetReason will be displayed to the user\r * attempting to load the module, or dumped to the console if the ircd is currently loading for the first time.\r */\rclass CoreExport CoreException : public std::exception\r{\r protected:\r        /** Holds the error message to be displayed\r     */\r    const std::string err;\r /** Source of the exception\r     */\r    const std::string source;\r public:\r     /** Default constructor, just uses the error mesage 'Core threw an exception'.\r  */\r    CoreException() : err("Core threw an exception"), source("The core") {}\r        /** This constructor can be used to specify an error message before throwing.\r   */\r    CoreException(const std::string &message) : err(message), source("The core") {}\r        /** This constructor can be used to specify an error message before throwing,\r   * and to specify the source of the exception.\r  */\r    CoreException(const std::string &message, const std::string &src) : err(message), source(src) {}\r       /** This destructor solves world hunger, cancels the world debt, and causes the world to end.\r   * Actually no, it does nothing. Never mind.\r    * @throws Nothing!\r     */\r    virtual ~CoreException() throw() {};\r   /** Returns the reason for the exception.\r       * The module should probably put something informative here as the user will see this upon failure.\r    */\r    virtual const char* GetReason()\r        {\r              return err.c_str();\r    }\r\r     virtual const char* GetSource()\r        {\r              return source.c_str();\r }\r};\r\rclass CoreExport ModuleException : public CoreException\r{\r public:\r       /** Default constructor, just uses the error mesage 'Module threw an exception'.\r        */\r    ModuleException() : CoreException("Module threw an exception", "A Module") {}\r\r /** This constructor can be used to specify an error message before throwing.\r   */\r    ModuleException(const std::string &message) : CoreException(message, "A Module") {}\r    /** This destructor solves world hunger, cancels the world debt, and causes the world to end.\r   * Actually no, it does nothing. Never mind.\r    * @throws Nothing!\r     */\r    virtual ~ModuleException() throw() {};\r};\r\r/** Priority types which can be returned from Module::Prioritize()\r */\renum Priority { PRIORITY_FIRST, PRIORITY_DONTCARE, PRIORITY_LAST, PRIORITY_BEFORE, PRIORITY_AFTER };\r\r/** Implementation-specific flags which may be set in Module::Implements()\r */\renum Implementation {    I_OnUserConnect, I_OnUserQuit, I_OnUserDisconnect, I_OnUserJoin, I_OnUserPart, I_OnRehash, I_OnServerRaw, \r                     I_OnUserPreJoin, I_OnUserPreKick, I_OnUserKick, I_OnOper, I_OnInfo, I_OnWhois, I_OnUserPreInvite,\r                      I_OnUserInvite, I_OnUserPreMessage, I_OnUserPreNotice, I_OnUserPreNick, I_OnUserMessage, I_OnUserNotice, I_OnMode,\r                     I_OnGetServerDescription, I_OnSyncUser, I_OnSyncChannel, I_OnSyncChannelMetaData, I_OnSyncUserMetaData,\r                        I_OnDecodeMetaData, I_ProtoSendMode, I_ProtoSendMetaData, I_OnWallops, I_OnChangeHost, I_OnChangeName, I_OnAddGLine,\r                   I_OnAddZLine, I_OnAddQLine, I_OnAddKLine, I_OnAddELine, I_OnDelGLine, I_OnDelZLine, I_OnDelKLine, I_OnDelELine, I_OnDelQLine,\r                  I_OnCleanup, I_OnUserPostNick, I_OnAccessCheck, I_On005Numeric, I_OnKill, I_OnRemoteKill, I_OnLoadModule, I_OnUnloadModule,\r                    I_OnBackgroundTimer, I_OnPreCommand, I_OnCheckReady, I_OnUserRrgister, I_OnCheckInvite,\r                        I_OnCheckKey, I_OnCheckLimit, I_OnCheckBan, I_OnStats, I_OnChangeLocalUserHost, I_OnChangeLocalUserGecos, I_OnLocalTopicChange,\r                        I_OnPostLocalTopicChange, I_OnEvent, I_OnRequest, I_OnOperCompre, I_OnGlobalOper, I_OnPostConnect, I_OnAddBan, I_OnDelBan,\r                     I_OnRawSocketAccept, I_OnRawSocketClose, I_OnRawSocketWrite, I_OnRawSocketRead, I_OnChangeLocalUserGECOS, I_OnUserRegister,\r                    I_OnOperCompare, I_OnChannelDelete, I_OnPostOper, I_OnSyncOtherMetaData, I_OnSetAway, I_OnCancelAway, I_OnUserList,\r                    I_OnPostCommand, I_OnPostJoin, I_OnWhoisLine, I_OnBuildExemptList, I_OnRawSocketConnect, I_OnGarbageCollect, I_OnBufferFlushed };\r\r/** Base class for all InspIRCd modules\r *  This class is the base class for InspIRCd modules. All modules must inherit from this class,\r *  its methods will be called when irc server events occur. class inherited from module must be\r *  instantiated by the ModuleFactory class (see relevent section) for the module to be initialised.\r */\rclass CoreExport Module : public Extensible\r{\r protected:\r        /** Creator/owner pointer\r       */\r    InspIRCd* ServerInstance;\r public:\r\r    /** Default constructor.\r        * Creates a module class.\r      * @param Me An instance of the InspIRCd class which will be saved into ServerInstance for your use\r     * \exception ModuleException Throwing this class, or any class derived from ModuleException, causes loading of the module to abort.\r    */\r    Module(InspIRCd* Me);\r\r /** Default destructor.\r         * destroys a module class\r      */\r    virtual ~Module();\r\r    /** Returns the version number of a Module.\r     * The method should return a Version object with its version information assigned via\r  * Version::Version\r     */\r    virtual Version GetVersion();\r\r /** The Implements function specifies which methods a module should receive events for.\r         * The char* parameter passed to this function contains a set of true or false values\r   * (1 or 0) which indicate wether each function is implemented. You must use the Iimplementation\r        * enum (documented elsewhere on this page) to mark functions as active. For example, to\r        * receive events for OnUserJoin():\r     *\r      * Implements[I_OnUserJoin] = 1;\r        *\r      * @param The implement list\r    */\r    virtual void Implements(char* Implements);\r\r    /** Used to set the 'priority' of a module (e.g. when it is called in relation to other modules.\r        * Some modules prefer to be called before other modules, due to their design. For example, a\r   * module which is expected to operate on complete information would expect to be placed last, so\r       * that any other modules which wish to adjust that information would execute before it, to be sure\r     * its information is correct. You can change your module's priority by returning one of:\r       *\r      * PRIORITY_FIRST - To place your module first in the list\r      * \r     * PRIORITY_LAST - To place your module last in the list\r        *\r      * PRIORITY_DONTCARE - To leave your module as it is (this is the default value, if you do not implement this function)\r         *\r      * The result of InspIRCd::PriorityBefore() - To move your module before another named module\r   *\r      * The result of InspIRCd::PriorityLast() - To move your module after another named module\r      *\r      * For a good working example of this method call, please see src/modules/m_spanningtree.cpp\r    * and src/modules/m_hostchange.so which make use of it. It is highly recommended that unless\r   * your module has a real need to reorder its priority, it should not implement this function,\r  * as many modules changing their priorities can make the system redundant.\r     */\r    virtual Priority Prioritize();\r\r        /** Called when a user connects.\r        * The details of the connecting user are available to you in the parameter userrec *user\r       * @param user The user who is connecting\r       */\r    virtual void OnUserConnect(userrec* user);\r\r    /** Called when a user quits.\r   * The details of the exiting user are available to you in the parameter userrec *user\r  * This event is only called when the user is fully registered when they quit. To catch\r         * raw disconnections, use the OnUserDisconnect method.\r         * @param user The user who is quitting\r         * @param message The user's quit message (as seen by non-opers)\r        * @param oper_message The user's quit message (as seen by opers)\r       */\r    virtual void OnUserQuit(userrec* user, const std::string &message, const std::string &oper_message);\r\r  /** Called whenever a user's socket is closed.\r  * The details of the exiting user are available to you in the parameter userrec *user\r  * This event is called for all users, registered or not, as a cleanup method for modules\r       * which might assign resources to user, such as dns lookups, objects and sockets.\r      * @param user The user who is disconnecting\r    */\r    virtual void OnUserDisconnect(userrec* user);\r\r /** Called whenever a channel is deleted, either by QUIT, KICK or PART.\r         * @param chan The channel being deleted\r        */\r    virtual void OnChannelDelete(chanrec* chan);\r\r  /** Called when a user joins a channel.\r         * The details of the joining user are available to you in the parameter userrec *user,\r         * and the details of the channel they have joined is available in the variable chanrec *channel\r        * @param user The user who is joining\r  * @param channel The channel being joined\r      * @param silent Change this to true if you want to conceal the JOIN command from the other users\r       * of the channel (useful for modules such as auditorium)\r       */\r    virtual void OnUserJoin(userrec* user, chanrec* channel, bool &silent);\r\r       /** Called after a user joins a channel\r         * Identical to OnUserJoin, but called immediately afterwards, when any linking module has\r      * seen the join.\r       * @param user The user who is joining\r  * @param channel The channel being joined\r      */\r    virtual void OnPostJoin(userrec* user, chanrec* channel);\r\r     /** Called when a user parts a channel.\r         * The details of the leaving user are available to you in the parameter userrec *user,\r         * and the details of the channel they have left is available in the variable chanrec *channel\r  * @param user The user who is parting\r  * @param channel The channel being parted\r      * @param partmessage The part message, or an empty string\r      * @param silent Change this to true if you want to conceal the PART command from the other users\r       * of the channel (useful for modules such as auditorium)\r       */\r    virtual void OnUserPart(userrec* user, chanrec* channel, const std::string &partmessage, bool &silent);\r\r       /** Called on rehash.\r   * This method is called prior to a /REHASH or when a SIGHUP is received from the operating\r     * system. You should use it to reload any files so that your module keeps in step with the\r     * rest of the application. If a parameter is given, the core has done nothing. The module\r      * receiving the event can decide if this parameter has any relevence to it.\r    * @param user The user performing the rehash, if any -- if this is server initiated, the\r       * value of this variable will be NULL.\r         * @param parameter The (optional) parameter given to REHASH from the user.\r     */\r    virtual void OnRehash(userrec* user, const std::string &parameter);\r\r   /** Called when a raw command is transmitted or received.\r       * This method is the lowest level of handler available to a module. It will be called with raw\r         * data which is passing through a connected socket. If you wish, you may munge this data by changing\r   * the string parameter "raw". If you do this, after your function exits it will immediately be\r         * cut down to 510 characters plus a carriage return and linefeed. For INBOUND messages only (where\r     * inbound is set to true) the value of user will be the userrec of the connection sending the\r  * data. This is not possible for outbound data because the data may be being routed to multiple targets.\r       * @param raw The raw string in RFC1459 format\r  * @param inbound A flag to indicate wether the data is coming into the daemon or going out to the user\r         * @param user The user record sending the text, when inbound == true.\r  */\r    virtual void OnServerRaw(std::string &raw, bool inbound, userrec* user);\r\r      /** Called whenever a user is about to join a channel, before any processing is done.\r   * Returning a value of 1 from this function stops the process immediately, causing no\r  * output to be sent to the user by the core. If you do this you must produce your own numerics,\r        * notices etc. This is useful for modules which may want to mimic +b, +k, +l etc. Returning -1 from\r    * this function forces the join to be allowed, bypassing restrictions such as banlists, invite, keys etc.\r      *\r      * IMPORTANT NOTE!\r      *\r      * If the user joins a NEW channel which does not exist yet, OnUserPreJoin will be called BEFORE the channel\r    * record is created. This will cause chanrec* chan to be NULL. There is very little you can do in form of\r      * processing on the actual channel record at this point, however the channel NAME will still be passed in\r      * char* cname, so that you could for example implement a channel blacklist or whitelist, etc.\r  * @param user The user joining the channel\r     * @param chan If the  channel is a new channel, this will be NULL, otherwise it will be a pointer to the channel being joined\r  * @param cname The channel name being joined. For new channels this is valid where chan is not.\r        * @param privs A string containing the users privilages when joining the channel. For new channels this will contain "@".\r      * You may alter this string to alter the user's modes on the channel.\r  * @return 1 To prevent the join, 0 to allow it.\r        */\r    virtual int OnUserPreJoin(userrec* user, chanrec* chan, const char* cname, std::string &privs);\r        \r       /** Called whenever a user is about to be kicked.\r       * Returning a value of 1 from this function stops the process immediately, causing no\r  * output to be sent to the user by the core. If you do this you must produce your own numerics,\r        * notices etc.\r         * @param source The user issuing the kick\r      * @param user The user being kicked\r    * @param chan The channel the user is being kicked from\r        * @param reason The kick reason\r        * @return 1 to prevent the kick, 0 to continue normally, -1 to explicitly allow the kick regardless of normal operation\r        */\r    virtual int OnUserPreKick(userrec* source, userrec* user, chanrec* chan, const std::string &reason);\r\r  /** Called whenever a user is kicked.\r   * If this method is called, the kick is already underway and cannot be prevented, so\r   * to prevent a kick, please use Module::OnUserPreKick instead of this method.\r  * @param source The user issuing the kick\r      * @param user The user being kicked\r    * @param chan The channel the user is being kicked from\r        * @param reason The kick reason\r        * @param silent Change this to true if you want to conceal the PART command from the other users\r       * of the channel (useful for modules such as auditorium)\r       */\r    virtual void OnUserKick(userrec* source, userrec* user, chanrec* chan, const std::string &reason, bool &silent);\r\r      /** Called whenever a user opers locally.\r       * The userrec will contain the oper mode 'o' as this function is called after any modifications\r        * are made to the user's structure by the core.\r        * @param user The user who is opering up\r       * @param opertype The opers type name\r  */\r    virtual void OnOper(userrec* user, const std::string &opertype);\r\r      /** Called after a user opers locally.\r  * This is identical to Module::OnOper(), except it is called after OnOper so that other modules\r        * can be gauranteed to already have processed the oper-up, for example m_spanningtree has sent\r         * out the OPERTYPE, etc.\r       * @param user The user who is opering up\r       * @param opertype The opers type name\r  */\r    virtual void OnPostOper(userrec* user, const std::string &opertype);\r   \r       /** Called whenever a user types /INFO.\r         * The userrec will contain the information of the user who typed the command. Modules may use this\r     * method to output their own credits in /INFO (which is the ircd's version of an about box).\r   * It is purposefully not possible to modify any info that has already been output, or halt the list.\r   * You must write a 371 numeric to the user, containing your info in the following format:\r      *\r      * &lt;nick&gt; :information here\r       *\r      * @param user The user issuing /INFO\r   */\r    virtual void OnInfo(userrec* user);\r    \r       /** Called whenever a /WHOIS is performed on a local user.\r      * The source parameter contains the details of the user who issued the WHOIS command, and\r      * the dest parameter contains the information of the user they are whoising.\r   * @param source The user issuing the WHOIS command\r     * @param dest The user who is being WHOISed\r    */\r    virtual void OnWhois(userrec* source, userrec* dest);\r  \r       /** Called whenever a user is about to invite another user into a channel, before any processing is done.\r       * Returning 1 from this function stops the process immediately, causing no\r     * output to be sent to the user by the core. If you do this you must produce your own numerics,\r        * notices etc. This is useful for modules which may want to filter invites to channels.\r        * @param source The user who is issuing the INVITE\r     * @param dest The user being invited\r   * @param channel The channel the user is being invited to\r      * @return 1 to deny the invite, 0 to allow\r     */\r    virtual int OnUserPreInvite(userrec* source,userrec* dest,chanrec* channel);\r   \r       /** Called after a user has been successfully invited to a channel.\r     * You cannot prevent the invite from occuring using this function, to do that,\r         * use OnUserPreInvite instead.\r         * @param source The user who is issuing the INVITE\r     * @param dest The user being invited\r   * @param channel The channel the user is being invited to\r      */\r    virtual void OnUserInvite(userrec* source,userrec* dest,chanrec* channel);\r     \r       /** Called whenever a user is about to PRIVMSG A user or a channel, before any processing is done.\r      * Returning any nonzero value from this function stops the process immediately, causing no\r     * output to be sent to the user by the core. If you do this you must produce your own numerics,\r        * notices etc. This is useful for modules which may want to filter or redirect messages.\r       * target_type can be one of TYPE_USER or TYPE_CHANNEL. If the target_type value is a user,\r     * you must cast dest to a userrec* otherwise you must cast it to a chanrec*, this is the details\r       * of where the message is destined to be sent.\r         * @param user The user sending the message\r     * @param dest The target of the message (chanrec* or userrec*)\r         * @param target_type The type of target (TYPE_USER or TYPE_CHANNEL)\r    * @param text Changeable text being sent by the user\r   * @param status The status being used, e.g. PRIVMSG @#chan has status== '@', 0 to send to everyone.\r    * @param exempt_list A list of users not to send to. For channel messages, this will usually contain just the sender.\r  * It will be ignored for private messages.\r     * @return 1 to deny the NOTICE, 0 to allow it\r  */\r    virtual int OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text,char status, CUList &exempt_list);\r\r   /** Called whenever a user is about to NOTICE A user or a channel, before any processing is done.\r       * Returning any nonzero value from this function stops the process immediately, causing no\r     * output to be sent to the user by the core. If you do this you must produce your own numerics,\r        * notices etc. This is useful for modules which may want to filter or redirect messages.\r       * target_type can be one of TYPE_USER or TYPE_CHANNEL. If the target_type value is a user,\r     * you must cast dest to a userrec* otherwise you must cast it to a chanrec*, this is the details\r       * of where the message is destined to be sent.\r         * You may alter the message text as you wish before relinquishing control to the next module\r   * in the chain, and if no other modules block the text this altered form of the text will be sent out\r  * to the user and possibly to other servers.\r   * @param user The user sending the message\r     * @param dest The target of the message (chanrec* or userrec*)\r         * @param target_type The type of target (TYPE_USER or TYPE_CHANNEL)\r    * @param text Changeable text being sent by the user\r   * @param status The status being used, e.g. PRIVMSG @#chan has status== '@', 0 to send to everyone.\r    * @param exempt_list A list of users not to send to. For channel notices, this will usually contain just the sender.\r   * It will be ignored for private notices.\r      * @return 1 to deny the NOTICE, 0 to allow it\r  */\r    virtual int OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text,char status, CUList &exempt_list);\r\r    /** Called whenever the server wants to build the exemption list for a channel, but is not directly doing a PRIVMSG or NOTICE.\r  * For example, the spanningtree protocol will call this event when passing a privmsg on (but not processing it directly).\r      * @param message_type The message type, either MSG_PRIVMSG or MSG_NOTICE\r       * @param chan The channel to build the exempt list of\r  * @param sender The original sender of the PRIVMSG or NOTICE\r   * @param status The status char to be used for the channel list\r        * @param exempt_list The exempt list to be populated\r   */\r    virtual void OnBuildExemptList(MessageType message_type, chanrec* chan, userrec* sender, char status, CUList &exempt_list);\r    \r       /** Called before any nickchange, local or remote. This can be used to implement Q-lines etc.\r   * Please note that although you can see remote nickchanges through this function, you should\r   * NOT make any changes to the userrec if the user is a remote user as this may cause a desnyc.\r         * check user->server before taking any action (including returning nonzero from the method).\r   * If your method returns nonzero, the nickchange is silently forbidden, and it is down to your\r         * module to generate some meaninful output.\r    * @param user The username changing their nick\r         * @param newnick Their new nickname\r    * @return 1 to deny the change, 0 to allow\r     */\r    virtual int OnUserPreNick(userrec* user, const std::string &newnick);\r\r /** Called after any PRIVMSG sent from a user.\r  * The dest variable contains a userrec* if target_type is TYPE_USER and a chanrec*\r     * if target_type is TYPE_CHANNEL.\r      * @param user The user sending the message\r     * @param dest The target of the message\r        * @param target_type The type of target (TYPE_USER or TYPE_CHANNEL)\r    * @param text the text being sent by the user\r  * @param status The status being used, e.g. PRIVMSG @#chan has status== '@', 0 to send to everyone.\r    */\r    virtual void OnUserMessage(userrec* user, void* dest, int target_type, const std::string &text, char status, const CUList &exempt_list);\r\r      /** Called after any NOTICE sent from a user.\r   * The dest variable contains a userrec* if target_type is TYPE_USER and a chanrec*\r     * if target_type is TYPE_CHANNEL.\r      * @param user The user sending the message\r     * @param dest The target of the message\r        * @param target_type The type of target (TYPE_USER or TYPE_CHANNEL)\r    * @param text the text being sent by the user\r  * @param status The status being used, e.g. NOTICE @#chan has status== '@', 0 to send to everyone.\r     */\r    virtual void OnUserNotice(userrec* user, void* dest, int target_type, const std::string &text, char status, const CUList &exempt_list);\r\r       /** Called after every MODE command sent from a user\r    * The dest variable contains a userrec* if target_type is TYPE_USER and a chanrec*\r     * if target_type is TYPE_CHANNEL. The text variable contains the remainder of the\r      * mode string after the target, e.g. "+wsi" or "+ooo nick1 nick2 nick3".\r       * @param user The user sending the MODEs\r       * @param dest The target of the modes (userrec* or chanrec*)\r   * @param target_type The type of target (TYPE_USER or TYPE_CHANNEL)\r    * @param text The actual modes and their parameters if any\r     */\r    virtual void OnMode(userrec* user, void* dest, int target_type, const std::string &text);\r\r     /** Allows modules to alter or create server descriptions\r       * Whenever a module requires a server description, for example for display in\r  * WHOIS, this function is called in all modules. You may change or define the\r  * description given in std::string &description. If you do, this description\r   * will be shown in the WHOIS fields.\r   * @param servername The servername being searched for\r  * @param description Alterable server description for this server\r      */\r    virtual void OnGetServerDescription(const std::string &servername,std::string &description);\r\r  /** Allows modules to synchronize data which relates to users during a netburst.\r        * When this function is called, it will be called from the module which implements\r     * the linking protocol. This currently is m_spanningtree.so. A pointer to this module\r  * is given in Module* proto, so that you may call its methods such as ProtoSendMode\r    * (see below). This function will be called for every user visible on your side\r        * of the burst, allowing you to for example set modes, etc. Do not use this call to\r    * synchronize data which you have stored using class Extensible -- There is a specialist\r       * function OnSyncUserMetaData and OnSyncChannelMetaData for this!\r      * @param user The user being syncronized\r       * @param proto A pointer to the module handling network protocol\r       * @param opaque An opaque pointer set by the protocol module, should not be modified!\r  */\r    virtual void OnSyncUser(userrec* user, Module* proto, void* opaque);\r\r  /** Allows modules to synchronize data which relates to channels during a netburst.\r     * When this function is called, it will be called from the module which implements\r     * the linking protocol. This currently is m_spanningtree.so. A pointer to this module\r  * is given in Module* proto, so that you may call its methods such as ProtoSendMode\r    * (see below). This function will be called for every user visible on your side\r        * of the burst, allowing you to for example set modes, etc. Do not use this call to\r    * synchronize data which you have stored using class Extensible -- There is a specialist\r       * function OnSyncUserMetaData and OnSyncChannelMetaData for this!\r      *\r      * For a good example of how to use this function, please see src/modules/m_chanprotect.cpp\r     *\r      * @param chan The channel being syncronized\r    * @param proto A pointer to the module handling network protocol\r       * @param opaque An opaque pointer set by the protocol module, should not be modified!\r  */\r    virtual void OnSyncChannel(chanrec* chan, Module* proto, void* opaque);\r\r       /* Allows modules to syncronize metadata related to channels over the network during a netburst.\r        * Whenever the linking module wants to send out data, but doesnt know what the data\r    * represents (e.g. it is Extensible metadata, added to a userrec or chanrec by a module) then\r  * this method is called.You should use the ProtoSendMetaData function after you've\r     * correctly decided how the data should be represented, to send the metadata on its way if it belongs\r  * to your module. For a good example of how to use this method, see src/modules/m_swhois.cpp.\r  * @param chan The channel whos metadata is being syncronized\r   * @param proto A pointer to the module handling network protocol\r       * @param opaque An opaque pointer set by the protocol module, should not be modified!\r  * @param extname The extensions name which is being searched for\r       * @param displayable If this value is true, the data is going to be displayed to a user,\r       * and not sent across the network. Use this to determine wether or not to show sensitive data.\r         */\r    virtual void OnSyncChannelMetaData(chanrec* chan, Module* proto,void* opaque, const std::string &extname, bool displayable = false);\r\r  /* Allows modules to syncronize metadata related to users over the network during a netburst.\r   * Whenever the linking module wants to send out data, but doesnt know what the data\r    * represents (e.g. it is Extensible metadata, added to a userrec or chanrec by a module) then\r  * this method is called. You should use the ProtoSendMetaData function after you've\r    * correctly decided how the data should be represented, to send the metadata on its way if\r     * if it belongs to your module.\r        * @param user The user whos metadata is being syncronized\r      * @param proto A pointer to the module handling network protocol\r       * @param opaque An opaque pointer set by the protocol module, should not be modified!\r  * @param extname The extensions name which is being searched for\r       * @param displayable If this value is true, the data is going to be displayed to a user,\r       * and not sent across the network. Use this to determine wether or not to show sensitive data.\r         */\r    virtual void OnSyncUserMetaData(userrec* user, Module* proto,void* opaque, const std::string &extname, bool displayable = false);\r\r     /* Allows modules to syncronize metadata not related to users or channels, over the network during a netburst.\r  * Whenever the linking module wants to send out data, but doesnt know what the data\r    * represents (e.g. it is Extensible metadata, added to a userrec or chanrec by a module) then\r  * this method is called. You should use the ProtoSendMetaData function after you've\r    * correctly decided how the data should be represented, to send the metadata on its way if\r     * if it belongs to your module.\r        * @param proto A pointer to the module handling network protocol\r       * @param opaque An opaque pointer set by the protocol module, should not be modified!\r  * @param displayable If this value is true, the data is going to be displayed to a user,\r       * and not sent across the network. Use this to determine wether or not to show sensitive data.\r         */\r    virtual void OnSyncOtherMetaData(Module* proto, void* opaque, bool displayable = false);\r\r      /** Allows module data, sent via ProtoSendMetaData, to be decoded again by a receiving module.\r  * Please see src/modules/m_swhois.cpp for a working example of how to use this method call.\r    * @param target_type The type of item to decode data for, TYPE_USER or TYPE_CHANNEL\r    * @param target The chanrec* or userrec* that data should be added to\r  * @param extname The extension name which is being sent\r        * @param extdata The extension data, encoded at the other end by an identical module through OnSyncChannelMetaData or OnSyncUserMetaData\r       */\r    virtual void OnDecodeMetaData(int target_type, void* target, const std::string &extname, const std::string &extdata);\r\r /** Implemented by modules which provide the ability to link servers.\r   * These modules will implement this method, which allows transparent sending of servermodes\r    * down the network link as a broadcast, without a module calling it having to know the format\r  * of the MODE command before the actual mode string.\r   *\r      * More documentation to follow soon. Please see src/modules/m_chanprotect.cpp for examples\r     * of how to use this function.\r         *\r      * @param opaque An opaque pointer set by the protocol module, should not be modified!\r  * @param target_type The type of item to decode data for, TYPE_USER or TYPE_CHANNEL\r    * @param target The chanrec* or userrec* that modes should be sent for\r         * @param modeline The modes and parameters to be sent\r  */\r    virtual void ProtoSendMode(void* opaque, int target_type, void* target, const std::string &modeline);\r\r /** Implemented by modules which provide the ability to link servers.\r   * These modules will implement this method, which allows metadata (extra data added to\r         * user and channel records using class Extensible, Extensible::Extend, etc) to be sent\r         * to other servers on a netburst and decoded at the other end by the same module on a\r  * different server.\r    *\r      * More documentation to follow soon. Please see src/modules/m_swhois.cpp for example of\r        * how to use this function.\r    * @param opaque An opaque pointer set by the protocol module, should not be modified!\r  * @param target_type The type of item to decode data for, TYPE_USER or TYPE_CHANNEL\r    * @param target The chanrec* or userrec* that metadata should be sent for\r      * @param extname The extension name to send metadata for\r       * @param extdata Encoded data for this extension name, which will be encoded at the oppsite end by an identical module using OnDecodeMetaData\r  */\r    virtual void ProtoSendMetaData(void* opaque, int target_type, void* target, const std::string &extname, const std::string &extdata);\r   \r       /** Called after every WALLOPS command.\r         * @param user The user sending the WALLOPS\r     * @param text The content of the WALLOPS message\r       */\r    virtual void OnWallops(userrec* user, const std::string &text);\r\r       /** Called whenever a user's hostname is changed.\r       * This event triggers after the host has been set.\r     * @param user The user whos host is being changed\r      * @param newhost The new hostname being set\r    */\r    virtual void OnChangeHost(userrec* user, const std::string &newhost);\r\r /** Called whenever a user's GECOS (realname) is changed.\r       * This event triggers after the name has been set.\r     * @param user The user who's GECOS is being changed\r    * @param gecos The new GECOS being set on the user\r     */\r    virtual void OnChangeName(userrec* user, const std::string &gecos);\r\r   /** Called whenever a gline is added by a local user.\r   * This method is triggered after the line is added.\r    * @param duration The duration of the line in seconds\r  * @param source The sender of the line\r         * @param reason The reason text to be displayed\r        * @param hostmask The hostmask to add\r  */\r    virtual void OnAddGLine(long duration, userrec* source, const std::string &reason, const std::string &hostmask);\r\r      /** Called whenever a zline is added by a local user.\r   * This method is triggered after the line is added.\r    * @param duration The duration of the line in seconds\r  * @param source The sender of the line\r         * @param reason The reason text to be displayed\r        * @param ipmask The hostmask to add\r    */\r    virtual void OnAddZLine(long duration, userrec* source, const std::string &reason, const std::string &ipmask);\r\r        /** Called whenever a kline is added by a local user.\r   * This method is triggered after the line is added.\r    * @param duration The duration of the line in seconds\r  * @param source The sender of the line\r         * @param reason The reason text to be displayed\r        * @param hostmask The hostmask to add\r  */\r    virtual void OnAddKLine(long duration, userrec* source, const std::string &reason, const std::string &hostmask);\r\r      /** Called whenever a qline is added by a local user.\r   * This method is triggered after the line is added.\r    * @param duration The duration of the line in seconds\r  * @param source The sender of the line\r         * @param reason The reason text to be displayed\r        * @param nickmask The hostmask to add\r  */\r    virtual void OnAddQLine(long duration, userrec* source, const std::string &reason, const std::string &nickmask);\r\r      /** Called whenever a eline is added by a local user.\r   * This method is triggered after the line is added.\r    * @param duration The duration of the line in seconds\r  * @param source The sender of the line\r         * @param reason The reason text to be displayed\r        * @param hostmask The hostmask to add\r  */\r    virtual void OnAddELine(long duration, userrec* source, const std::string &reason, const std::string &hostmask);\r\r      /** Called whenever a gline is deleted.\r         * This method is triggered after the line is deleted.\r  * @param source The user removing the line\r     * @param hostmask The hostmask to delete\r       */\r    virtual void OnDelGLine(userrec* source, const std::string &hostmask);\r\r        /** Called whenever a zline is deleted.\r         * This method is triggered after the line is deleted.\r  * @param source The user removing the line\r     * @param hostmask The hostmask to delete\r       */\r    virtual void OnDelZLine(userrec* source, const std::string &ipmask);\r\r  /** Called whenever a kline is deleted.\r         * This method is triggered after the line is deleted.\r  * @param source The user removing the line\r     * @param hostmask The hostmask to delete\r       */\r    virtual void OnDelKLine(userrec* source, const std::string &hostmask);\r \r       /** Called whenever a qline is deleted.\r         * This method is triggered after the line is deleted.\r  * @param source The user removing the line\r     * @param hostmask The hostmask to delete\r       */\r    virtual void OnDelQLine(userrec* source, const std::string &nickmask);\r\r        /** Called whenever a eline is deleted.\r         * This method is triggered after the line is deleted.\r  * @param source The user removing the line\r     * @param hostmask The hostmask to delete\r       */\r    virtual void OnDelELine(userrec* source, const std::string &hostmask);\r\r        /** Called before your module is unloaded to clean up Extensibles.\r      * This method is called once for every user and channel on the network,\r        * so that when your module unloads it may clear up any remaining data\r  * in the form of Extensibles added using Extensible::Extend().\r         * If the target_type variable is TYPE_USER, then void* item refers to\r  * a userrec*, otherwise it refers to a chanrec*.\r       * @param target_type The type of item being cleaned\r    * @param item A pointer to the item's class\r    */\r    virtual void OnCleanup(int target_type, void* item);\r\r  /** Called after any nickchange, local or remote. This can be used to track users after nickchanges\r     * have been applied. Please note that although you can see remote nickchanges through this function, you should\r        * NOT make any changes to the userrec if the user is a remote user as this may cause a desnyc.\r         * check user->server before taking any action (including returning nonzero from the method).\r   * Because this method is called after the nickchange is taken place, no return values are possible\r     * to indicate forbidding of the nick change. Use OnUserPreNick for this.\r       * @param user The user changing their nick\r     * @param oldnick The old nickname of the user before the nickchange\r    */\r    virtual void OnUserPostNick(userrec* user, const std::string &oldnick);\r\r       /** Called before an action which requires a channel privilage check.\r   * This function is called before many functions which check a users status on a channel, for example\r   * before opping a user, deopping a user, kicking a user, etc.\r  * There are several values for access_type which indicate for what reason access is being checked.\r     * These are:<br><br>\r   * AC_KICK (0) - A user is being kicked<br>\r     * AC_DEOP (1) - a user is being deopped<br>\r    * AC_OP (2) - a user is being opped<br>\r        * AC_VOICE (3) - a user is being voiced<br>\r    * AC_DEVOICE (4) - a user is being devoiced<br>\r        * AC_HALFOP (5) - a user is being halfopped<br>\r        * AC_DEHALFOP (6) - a user is being dehalfopped<br>\r    * AC_INVITE () - a user is being invited<br>\r   * AC_GENERAL_MODE (8) - a user channel mode is being changed<br><br>\r   * Upon returning from your function you must return either ACR_DEFAULT, to indicate the module wishes\r  * to do nothing, or ACR_DENY where approprate to deny the action, and ACR_ALLOW where appropriate to allow\r     * the action. Please note that in the case of some access checks (such as AC_GENERAL_MODE) access may be\r       * denied 'upstream' causing other checks such as AC_DEOP to not be reached. Be very careful with use of the\r    * AC_GENERAL_MODE type, as it may inadvertently override the behaviour of other modules. When the access_type\r  * is AC_GENERAL_MODE, the destination of the mode will be NULL (as it has not yet been determined).\r    * @param source The source of the access check\r         * @param dest The destination of the access check\r      * @param channel The channel which is being checked\r    * @param access_type See above\r         */\r    virtual int OnAccessCheck(userrec* source,userrec* dest,chanrec* channel,int access_type);\r\r    /** Called when a 005 numeric is about to be output.\r    * The module should modify the 005 numeric if needed to indicate its features.\r         * @param output The 005 string to be modified if neccessary.\r   */\r    virtual void On005Numeric(std::string &output);\r\r       /** Called when a client is disconnected by KILL.\r       * If a client is killed by a server, e.g. a nickname collision or protocol error,\r      * source is NULL.\r      * Return 1 from this function to prevent the kill, and 0 from this function to allow\r   * it as normal. If you prevent the kill no output will be sent to the client, it is\r    * down to your module to generate this information.\r    * NOTE: It is NOT advisable to stop kills which originate from servers or remote users.\r        * If you do so youre risking race conditions, desyncs and worse!\r       * @param source The user sending the KILL\r      * @param dest The user being killed\r    * @param reason The kill reason\r        * @return 1 to prevent the kill, 0 to allow\r    */\r    virtual int OnKill(userrec* source, userrec* dest, const std::string &reason);\r\r        /** Called when an oper wants to disconnect a remote user via KILL\r      * @param source The user sending the KILL\r      * @param dest The user being killed\r    * @param reason The kill reason\r        */\r    virtual void OnRemoteKill(userrec* source, userrec* dest, const std::string &reason, const std::string &operreason);\r\r  /** Called whenever a module is loaded.\r         * mod will contain a pointer to the module, and string will contain its name,\r  * for example m_widgets.so. This function is primary for dependency checking,\r  * your module may decide to enable some extra features if it sees that you have\r        * for example loaded "m_killwidgets.so" with "m_makewidgets.so". It is highly\r  * recommended that modules do *NOT* bail if they cannot satisfy dependencies,\r  * but instead operate under reduced functionality, unless the dependency is\r    * absolutely neccessary (e.g. a module that extends the features of another\r    * module).\r     * @param mod A pointer to the new module\r       * @param name The new module's filename\r        */\r    virtual void OnLoadModule(Module* mod,const std::string &name);\r\r       /** Called whenever a module is unloaded.\r       * mod will contain a pointer to the module, and string will contain its name,\r  * for example m_widgets.so. This function is primary for dependency checking,\r  * your module may decide to enable some extra features if it sees that you have\r        * for example loaded "m_killwidgets.so" with "m_makewidgets.so". It is highly\r  * recommended that modules do *NOT* bail if they cannot satisfy dependencies,\r  * but instead operate under reduced functionality, unless the dependency is\r    * absolutely neccessary (e.g. a module that extends the features of another\r    * module).\r     * @param mod Pointer to the module being unloaded (still valid)\r        * @param name The filename of the module being unloaded\r        */\r    virtual void OnUnloadModule(Module* mod,const std::string &name);\r\r     /** Called once every five seconds for background processing.\r   * This timer can be used to control timed features. Its period is not accurate\r         * enough to be used as a clock, but it is gauranteed to be called at least once in\r     * any five second period, directly from the main loop of the server.\r   * @param curtime The current timer derived from time(2)\r        */\r    virtual void OnBackgroundTimer(time_t curtime);\r\r       /** Called whenever any command is about to be executed.\r        * This event occurs for all registered commands, wether they are registered in the core,\r       * or another module, and for invalid commands. Invalid commands may only be sent to this\r       * function when the value of validated is false. By returning 1 from this method you may prevent the\r   * command being executed. If you do this, no output is created by the core, and it is\r  * down to your module to produce any output neccessary.\r        * Note that unless you return 1, you should not destroy any structures (e.g. by using\r  * InspIRCd::QuitUser) otherwise when the command's handler function executes after your\r        * method returns, it will be passed an invalid pointer to the user object and crash!)\r  * @param command The command being executed\r    * @param parameters An array of array of characters containing the parameters for the command\r  * @param pcnt The nuimber of parameters passed to the command\r  * @param user the user issuing the command\r     * @param validated True if the command has passed all checks, e.g. it is recognised, has enough parameters, the user has permission to execute it, etc.\r        * @param original_line The entire original line as passed to the parser from the user\r  * @return 1 to block the command, 0 to allow\r   */\r    virtual int OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line);\r\r     /** Called after any command has been executed.\r         * This event occurs for all registered commands, wether they are registered in the core,\r       * or another module, but it will not occur for invalid commands (e.g. ones which do not\r        * exist within the command table). The result code returned by the command handler is\r  * provided.\r    * @param command The command being executed\r    * @param parameters An array of array of characters containing the parameters for the command\r  * @param pcnt The nuimber of parameters passed to the command\r  * @param user the user issuing the command\r     * @param result The return code given by the command handler, one of CMD_SUCCESS or CMD_FAILURE\r        * @param original_line The entire original line as passed to the parser from the user\r  */\r    virtual void OnPostCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, CmdResult result, const std::string &original_line);\r\r /** Called to check if a user who is connecting can now be allowed to register\r  * If any modules return false for this function, the user is held in the waiting\r       * state until all modules return true. For example a module which implements ident\r     * lookups will continue to return false for a user until their ident lookup is completed.\r      * Note that the registration timeout for a user overrides these checks, if the registration\r    * timeout is reached, the user is disconnected even if modules report that the user is\r         * not ready to connect.\r        * @param user The user to check\r        * @return true to indicate readiness, false if otherwise\r       */\r    virtual bool OnCheckReady(userrec* user);\r\r     /** Called whenever a user is about to register their connection (e.g. before the user\r  * is sent the MOTD etc). Modules can use this method if they are performing a function\r         * which must be done before the actual connection is completed (e.g. ident lookups,\r    * dnsbl lookups, etc).\r         * Note that you should NOT delete the user record here by causing a disconnection!\r     * Use OnUserConnect for that instead.\r  * @param user The user registering\r     * @return 1 to indicate user quit, 0 to continue\r       */\r    virtual int OnUserRegister(userrec* user);\r\r    /** Called whenever a user joins a channel, to determine if invite checks should go ahead or not.\r       * This method will always be called for each join, wether or not the channel is actually +i, and\r       * determines the outcome of an if statement around the whole section of invite checking code.\r  * return 1 to explicitly allow the join to go ahead or 0 to ignore the event.\r  * @param user The user joining the channel\r     * @param chan The channel being joined\r         * @return 1 to explicitly allow the join, 0 to proceed as normal\r       */\r    virtual int OnCheckInvite(userrec* user, chanrec* chan);\r\r      /** Called whenever a user joins a channel, to determine if key checks should go ahead or not.\r  * This method will always be called for each join, wether or not the channel is actually +k, and\r       * determines the outcome of an if statement around the whole section of key checking code.\r     * if the user specified no key, the keygiven string will be a valid but empty value.\r   * return 1 to explicitly allow the join to go ahead or 0 to ignore the event.\r  * @param user The user joining the channel\r     * @param chan The channel being joined\r         * @return 1 to explicitly allow the join, 0 to proceed as normal\r       */\r    virtual int OnCheckKey(userrec* user, chanrec* chan, const std::string &keygiven);\r\r    /** Called whenever a user joins a channel, to determine if channel limit checks should go ahead or not.\r        * This method will always be called for each join, wether or not the channel is actually +l, and\r       * determines the outcome of an if statement around the whole section of channel limit checking code.\r   * return 1 to explicitly allow the join to go ahead or 0 to ignore the event.\r  * @param user The user joining the channel\r     * @param chan The channel being joined\r         * @return 1 to explicitly allow the join, 0 to proceed as normal\r       */\r    virtual int OnCheckLimit(userrec* user, chanrec* chan);\r\r       /** Called whenever a user joins a channel, to determine if banlist checks should go ahead or not.\r      * This method will always be called for each join, wether or not the user actually matches a channel ban, and\r  * determines the outcome of an if statement around the whole section of ban checking code.\r     * return 1 to explicitly allow the join to go ahead or 0 to ignore the event.\r  * @param user The user joining the channel\r     * @param chan The channel being joined\r         * @return 1 to explicitly allow the join, 0 to proceed as normal\r       */\r    virtual int OnCheckBan(userrec* user, chanrec* chan);\r\r /** Called on all /STATS commands\r       * This method is triggered for all /STATS use, including stats symbols handled by the core.\r    * @param symbol the symbol provided to /STATS\r  * @param user the user issuing the /STATS command\r      * @param results A string_list to append results into. You should put all your results\r         * into this string_list, rather than displaying them directly, so that your handler will\r       * work when remote STATS queries are received.\r         * @return 1 to block the /STATS from being processed by the core, 0 to allow it\r        */\r    virtual int OnStats(char symbol, userrec* user, string_list &results);\r\r        /** Called whenever a change of a local users displayed host is attempted.\r      * Return 1 to deny the host change, or 0 to allow it.\r  * @param user The user whos host will be changed\r       * @param newhost The new hostname\r      * @return 1 to deny the host change, 0 to allow\r        */\r    virtual int OnChangeLocalUserHost(userrec* user, const std::string &newhost);\r\r /** Called whenever a change of a local users GECOS (fullname field) is attempted.\r      * return 1 to deny the name change, or 0 to allow it.\r  * @param user The user whos GECOS will be changed\r      * @param newhost The new GECOS\r         * @return 1 to deny the GECOS change, 0 to allow\r       */\r    virtual int OnChangeLocalUserGECOS(userrec* user, const std::string &newhost); \r\r       /** Called whenever a topic is changed by a local user.\r         * Return 1 to deny the topic change, or 0 to allow it.\r         * @param user The user changing the topic\r      * @param chan The channels who's topic is being changed\r        * @param topic The actual topic text\r   * @param 1 to block the topic change, 0 to allow\r       */\r    virtual int OnLocalTopicChange(userrec* user, chanrec* chan, const std::string &topic);\r\r       /** Called whenever a local topic has been changed.\r     * To block topic changes you must use OnLocalTopicChange instead.\r      * @param user The user changing the topic\r      * @param chan The channels who's topic is being changed\r        * @param topic The actual topic text\r   */\r    virtual void OnPostLocalTopicChange(userrec* user, chanrec* chan, const std::string &topic);\r\r  /** Called whenever an Event class is sent to all module by another module.\r     * Please see the documentation of Event::Send() for further information. The Event sent can\r    * always be assumed to be non-NULL, you should *always* check the value of Event::GetEventID()\r         * before doing anything to the event data, and you should *not* change the event data in any way!\r      * @param event The Event class being received\r  */\r    virtual void OnEvent(Event* event);\r\r   /** Called whenever a Request class is sent to your module by another module.\r   * Please see the documentation of Request::Send() for further information. The Request sent\r    * can always be assumed to be non-NULL, you should not change the request object or its data.\r  * Your method may return arbitary data in the char* result which the requesting module\r         * may be able to use for pre-determined purposes (e.g. the results of an SQL query, etc).\r      * @param request The Request class being received\r      */\r    virtual char* OnRequest(Request* request);\r\r    /** Called whenever an oper password is to be compared to what a user has input.\r        * The password field (from the config file) is in 'password' and is to be compared against\r     * 'input'. This method allows for encryption of oper passwords and much more besides.\r  * You should return a nonzero value if you want to allow the comparison or zero if you wish\r    * to do nothing.\r       * @param password The oper's password\r  * @param input The password entered\r    * @param tagnumber The tag number (from the configuration file) of this oper's tag\r     * @return 1 to match the passwords, 0 to do nothing. -1 to not match, and not continue.\r        */\r    virtual int OnOperCompare(const std::string &password, const std::string &input, int tagnumber);\r\r      /** Called whenever a user is given usermode +o, anywhere on the network.\r       * You cannot override this and prevent it from happening as it is already happened and\r         * such a task must be performed by another server. You can however bounce modes by sending\r     * servermodes out to reverse mode changes.\r     * @param user The user who is opering\r  */\r    virtual void OnGlobalOper(userrec* user);\r\r     /** Called after a user has fully connected and all modules have executed OnUserConnect\r         * This event is informational only. You should not change any user information in this\r         * event. To do so, use the OnUserConnect method to change the state of local users.\r    * This is called for both local and remote users.\r      * @param user The user who is connecting\r       */\r    virtual void OnPostConnect(userrec* user);\r\r    /** Called whenever a ban is added to a channel's list.\r         * Return a non-zero value to 'eat' the mode change and prevent the ban from being added.\r       * @param source The user adding the ban\r        * @param channel The channel the ban is being added to\r         * @param banmask The ban mask being added\r      * @return 1 to block the ban, 0 to continue as normal\r  */\r    virtual int OnAddBan(userrec* source, chanrec* channel,const std::string &banmask);\r\r   /** Called whenever a ban is removed from a channel's list.\r     * Return a non-zero value to 'eat' the mode change and prevent the ban from being removed.\r     * @param source The user deleting the ban\r      * @param channel The channel the ban is being deleted from\r     * @param banmask The ban mask being deleted\r    * @return 1 to block the unban, 0 to continue as normal\r        */\r    virtual int OnDelBan(userrec* source, chanrec* channel,const std::string &banmask);\r\r   /** Called immediately after any  connection is accepted. This is intended for raw socket\r       * processing (e.g. modules which wrap the tcp connection within another library) and provides\r  * no information relating to a user record as the connection has not been assigned yet.\r        * There are no return values from this call as all modules get an opportunity if required to\r   * process the connection.\r      * @param fd The file descriptor returned from accept()\r         * @param ip The IP address of the connecting user\r      * @param localport The local port number the user connected to\r         */\r    virtual void OnRawSocketAccept(int fd, const std::string &ip, int localport);\r\r /** Called immediately before any write() operation on a user's socket in the core. Because\r     * this event is a low level event no user information is associated with it. It is intended\r    * for use by modules which may wrap connections within another API such as SSL for example.\r    * return a non-zero result if you have handled the write operation, in which case the core\r     * will not call write().\r       * @param fd The file descriptor of the socket\r  * @param buffer A char* buffer being written\r   * @param Number of characters to write\r         * @return Number of characters actually written or 0 if you didn't handle the operation\r        */\r    virtual int OnRawSocketWrite(int fd, const char* buffer, int count);\r\r  /** Called immediately before any socket is closed. When this event is called, shutdown()\r       * has not yet been called on the socket.\r       * @param fd The file descriptor of the socket prior to close()\r         */\r    virtual void OnRawSocketClose(int fd);\r\r        /** Called immediately upon connection of an outbound InspSocket which has been hooked\r  * by a module.\r         * @param fd The file descriptor of the socket immediately after connect()\r      */\r    virtual void OnRawSocketConnect(int fd);\r\r      /** Called immediately before any read() operation on a client socket in the core.\r      * This occurs AFTER the select() or poll() so there is always data waiting to be read\r  * when this event occurs.\r      * Your event should return 1 if it has handled the reading itself, which prevents the core\r     * just using read(). You should place any data read into buffer, up to but NOT GREATER THAN\r    * the value of count. The value of readresult must be identical to an actual result that might\r         * be returned from the read() system call, for example, number of bytes read upon success,\r     * 0 upon EOF or closed socket, and -1 for error. If your function returns a nonzero value,\r     * you MUST set readresult.\r     * @param fd The file descriptor of the socket\r  * @param buffer A char* buffer being read to\r   * @param count The size of the buffer\r  * @param readresult The amount of characters read, or 0\r        * @return nonzero if the event was handled, in which case readresult must be valid on exit\r     */\r    virtual int OnRawSocketRead(int fd, char* buffer, unsigned int count, int &readresult);\r\r       /** Called whenever a user sets away.\r   * This method has no parameter for the away message, as it is available in the\r         * user record as userrec::awaymsg.\r     * @param user The user setting away\r    */\r    virtual void OnSetAway(userrec* user);\r\r        /** Called when a user cancels their away state.\r        * @param user The user returning from away\r     */\r    virtual void OnCancelAway(userrec* user);\r\r     /** Called whenever a NAMES list is requested.\r  * You can produce the nameslist yourself, overriding the current list,\r         * and if you do you must return 1. If you do not handle the names list,\r        * return 0.\r    * @param The user requesting the NAMES list\r    * @param Ptr The channel the NAMES list is requested for\r       * @param userlist The user list for the channel (you may change this pointer.\r  * If you want to change the values, take a copy first, and change the copy, then\r       * point the pointer at your copy)\r      * @return 1 to prevent the user list being sent to the client, 0 to allow it\r   */\r    virtual int OnUserList(userrec* user, chanrec* Ptr, CUList* &userlist);\r\r       /** Called whenever a line of WHOIS output is sent to a user.\r   * You may change the numeric and the text of the output by changing\r    * the values numeric and text, but you cannot change the user the\r      * numeric is sent to. You may however change the user's userrec values.\r        * @param user The user the numeric is being sent to\r    * @param dest The user being WHOISed\r   * @param numeric The numeric of the line being sent\r    * @param text The text of the numeric, including any parameters\r        * @return nonzero to drop the line completely so that the user does not\r        * receive it, or zero to allow the line to be sent.\r    */\r    virtual int OnWhoisLine(userrec* user, userrec* dest, int &numeric, std::string &text);\r\r       /** Called at intervals for modules to garbage-collect any hashes etc.\r  * Certain data types such as hash_map 'leak' buckets, which must be\r    * tidied up and freed by copying into a new item every so often. This\r  * method is called when it is time to do that.\r         */\r    virtual void OnGarbageCollect();\r\r      /** Called whenever a user's write buffer has been completely sent.\r     * This is called when the user's write buffer is completely empty, and\r         * there are no more pending bytes to be written and no pending write events\r    * in the socket engine's queue. This may be used to refill the buffer with\r     * data which is being spooled in a controlled manner, e.g. LIST lines.\r         * @param user The user who's buffer is now empty.\r      */\r    virtual void OnBufferFlushed(userrec* user);\r};\r\r\r#define CONF_NOT_A_NUMBER     0x000010\r#define CONF_NOT_UNSIGNED      0x000080\r#define CONF_VALUE_NOT_FOUND   0x000100\r#define CONF_FILE_NOT_FOUND    0x000200\r\r\r/** Allows reading of values from configuration files\r * This class allows a module to read from either the main configuration file (inspircd.conf) or from\r * a module-specified configuration file. It may either be instantiated with one parameter or none.\r * Constructing the class using one parameter allows you to specify a path to your own configuration\r * file, otherwise, inspircd.conf is read.\r */\rclass CoreExport ConfigReader : public classbase\r{\r  protected:\r InspIRCd* ServerInstance;\r      /** The contents of the configuration file\r      * This protected member should never be accessed by a module (and cannot be accessed unless the\r        * core is changed). It will contain a pointer to the configuration file data with unneeded data\r        * (such as comments) stripped from it.\r         */\r    ConfigDataHash* data;\r  /** Used to store errors\r        */\r    std::ostringstream* errorlog;\r  /** If we're using our own config data hash or not\r      */\r    bool privatehash;\r      /** True if an error occured reading the config file\r    */\r    bool readerror;\r        /** Error code\r  */\r    long error;\r    \r  public:\r     /** Default constructor.\r        * This constructor initialises the ConfigReader class to read the inspircd.conf file\r   * as specified when running ./configure.\r       */\r    ConfigReader(InspIRCd* Instance);\r      /** Overloaded constructor.\r     * This constructor initialises the ConfigReader class to read a user-specified config file\r     */\r    ConfigReader(InspIRCd* Instance, const std::string &filename);\r /** Default destructor.\r         * This method destroys the ConfigReader class.\r         */\r    ~ConfigReader();\r\r      /** Retrieves a value from the config file.\r     * This method retrieves a value from the config file. Where multiple copies of the tag\r         * exist in the config file, index indicates which of the values to retrieve.\r   */\r    std::string ReadValue(const std::string &tag, const std::string &name, int index, bool allow_linefeeds = false);\r       /** Retrieves a value from the config file.\r     * This method retrieves a value from the config file. Where multiple copies of the tag\r         * exist in the config file, index indicates which of the values to retrieve. If the\r    * tag is not found the default value is returned instead.\r      */\r    std::string ReadValue(const std::string &tag, const std::string &name, const std::string &default_value, int index, bool allow_linefeeds = false);\r\r    /** Retrieves a boolean value from the config file.\r     * This method retrieves a boolean value from the config file. Where multiple copies of the tag\r         * exist in the config file, index indicates which of the values to retrieve. The values "1", "yes"\r     * and "true" in the config file count as true to ReadFlag, and any other value counts as false.\r        */\r    bool ReadFlag(const std::string &tag, const std::string &name, int index);\r     /** Retrieves a boolean value from the config file.\r     * This method retrieves a boolean value from the config file. Where multiple copies of the tag\r         * exist in the config file, index indicates which of the values to retrieve. The values "1", "yes"\r     * and "true" in the config file count as true to ReadFlag, and any other value counts as false.\r        * If the tag is not found, the default value is used instead.\r  */\r    bool ReadFlag(const std::string &tag, const std::string &name, const std::string &default_value, int index);\r\r  /** Retrieves an integer value from the config file.\r    * This method retrieves an integer value from the config file. Where multiple copies of the tag\r        * exist in the config file, index indicates which of the values to retrieve. Any invalid integer\r       * values in the tag will cause the objects error value to be set, and any call to GetError() will\r      * return CONF_INVALID_NUMBER to be returned. needs_unsigned is set if the number must be unsigned.\r     * If a signed number is placed into a tag which is specified unsigned, 0 will be returned and GetError()\r       * will return CONF_NOT_UNSIGNED\r        */\r    long ReadInteger(const std::string &tag, const std::string &name, int index, bool needs_unsigned);\r     /** Retrieves an integer value from the config file.\r    * This method retrieves an integer value from the config file. Where multiple copies of the tag\r        * exist in the config file, index indicates which of the values to retrieve. Any invalid integer\r       * values in the tag will cause the objects error value to be set, and any call to GetError() will\r      * return CONF_INVALID_NUMBER to be returned. needs_unsigned is set if the number must be unsigned.\r     * If a signed number is placed into a tag which is specified unsigned, 0 will be returned and GetError()\r       * will return CONF_NOT_UNSIGNED. If the tag is not found, the default value is used instead.\r   */\r    long ReadInteger(const std::string &tag, const std::string &name, const std::string &default_value, int index, bool needs_unsigned);\r\r  /** Returns the last error to occur.\r    * Valid errors can be found by looking in modules.h. Any nonzero value indicates an error condition.\r   * A call to GetError() resets the error flag back to 0.\r        */\r    long GetError();\r       /** Counts the number of times a given tag appears in the config file.\r  * This method counts the number of times a tag appears in a config file, for use where\r         * there are several tags of the same kind, e.g. with opers and connect types. It can be\r        * used with the index value of ConfigReader::ReadValue to loop through all copies of a\r         * multiple instance tag.\r       */\r    int Enumerate(const std::string &tag);\r /** Returns true if a config file is valid.\r     * This method is partially implemented and will only return false if the config\r        * file does not exist or could not be opened.\r  */\r    bool Verify();\r /** Dumps the list of errors in a config file to an output location. If bail is true,\r   * then the program will abort. If bail is false and user points to a valid user\r        * record, the error report will be spooled to the given user by means of NOTICE.\r       * if bool is false AND user is false, the error report will be spooled to all opers\r    * by means of a NOTICE to all opers.\r   */\r    void DumpErrors(bool bail,userrec* user);\r\r     /** Returns the number of items within a tag.\r   * For example if the tag was &lt;test tag="blah" data="foo"&gt; then this\r      * function would return 2. Spaces and newlines both qualify as valid seperators\r        * between values.\r      */\r    int EnumerateValues(const std::string &tag, int index);\r};\r\r\r\r/** Caches a text file into memory and can be used to retrieve lines from it.\r * This class contains methods for read-only manipulation of a text file in memory.\r * Either use the constructor type with one parameter to load a file into memory\r * at construction, or use the LoadFile method to load a file.\r */\rclass CoreExport FileReader : public classbase\r{\r   InspIRCd* ServerInstance;\r      /** The file contents\r   */\r    file_cache fc;\r\r        /** Content size in bytes\r       */\r    unsigned long contentsize;\r\r    /** Calculate content size in bytes\r     */\r    void CalcSize();\r\r public:\r     /** Default constructor.\r        * This method does not load any file into memory, you must use the LoadFile method\r     * after constructing the class this way.\r       */\r    FileReader(InspIRCd* Instance);\r\r       /** Secondary constructor.\r      * This method initialises the class with a file loaded into it ready for GetLine and\r   * and other methods to be called. If the file could not be loaded, FileReader::FileSize\r        * returns 0.\r   */\r    FileReader(InspIRCd* Instance, const std::string &filename);\r\r  /** Default destructor.\r         * This deletes the memory allocated to the file.\r       */\r    ~FileReader();\r\r        /** Used to load a file.\r        * This method loads a file into the class ready for GetLine and\r        * and other methods to be called. If the file could not be loaded, FileReader::FileSize\r        * returns 0.\r   */\r    void LoadFile(const std::string &filename);\r\r   /** Returns the whole content of the file as std::string\r        */\r    std::string Contents();\r\r       /** Returns the entire size of the file as std::string\r  */\r    unsigned long ContentSize();\r\r  /** Returns true if the file exists\r     * This function will return false if the file could not be opened.\r     */\r    bool Exists();\r \r       /** Retrieve one line from the file.\r    * This method retrieves one line from the text file. If an empty non-NULL string is returned,\r  * the index was out of bounds, or the line had no data on it.\r  */\r    std::string GetLine(int x);\r\r   /** Returns the size of the file in lines.\r      * This method returns the number of lines in the read file. If it is 0, no lines have been\r     * read into memory, either because the file is empty or it does not exist, or cannot be\r        * opened due to permission problems.\r   */\r    int FileSize();\r};\r\r\r/** Instantiates classes inherited from Module.\r * This class creates a class inherited from type Module, using new. This is to allow for modules\r * to create many different variants of Module, dependent on architecture, configuration, etc.\r * In most cases, the simple class shown in the example module m_foobar.so will suffice for most\r * modules.\r */\rclass CoreExport ModuleFactory : public classbase\r{\r public:\r    /** The default constructor does nothing.\r       */\r    ModuleFactory() { }\r    /** The default destructor does nothing\r         */\r    virtual ~ModuleFactory() { }\r   /** Creates a new module.\r       * Your inherited class of ModuleFactory must return a pointer to your Module class\r     * using this method.\r   */\r    virtual Module * CreateModule(InspIRCd* Me) = 0;\r};\r\r/** A DLLFactory (designed to load shared objects) containing a ModuleFactory.\r */\rtypedef DLLFactory<ModuleFactory> ircd_module;\r\r/** A list of loaded Modules\r */\rtypedef std::vector<Module*> ModuleList;\r\r/** A list of loaded ModuleFactories\r */\rtypedef std::vector<ircd_module*> FactoryList;\r\r/** This definition is used as shorthand for the various classes\r * and functions needed to make a module loadable by the OS.\r * It defines the class factory and external init_module function.\r */\r#define MODULE_INIT(y) \\r      class Factory : public ModuleFactory \\r { \\r     public: \\r             virtual Module * CreateModule(InspIRCd* Me) \\r          { \\r                    return new y(Me); \\r            } \\r    }; \\r   extern "C" DllExport void * init_module(void) \\r        { \\r            return new Factory; \\r  }\r\r#endif\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *         the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __MODULES_H
+#define __MODULES_H
+
+/** Used with OnAccessCheck() method of modules
+ */
+enum AccessControlType {
+       ACR_DEFAULT,            // Do default action (act as if the module isnt even loaded)
+       ACR_DENY,               // deny the action
+       ACR_ALLOW,              // allow the action
+       AC_KICK,                // a user is being kicked
+       AC_DEOP,                // a user is being deopped
+       AC_OP,                  // a user is being opped
+       AC_VOICE,               // a user is being voiced
+       AC_DEVOICE,             // a user is being devoiced
+       AC_HALFOP,              // a user is being halfopped
+       AC_DEHALFOP,            // a user is being dehalfopped
+       AC_INVITE,              // a user is being invited
+       AC_GENERAL_MODE         // a channel mode is being changed
+};
+
+/** Used to define a set of behavior bits for a module
+ */
+enum ModuleFlags {
+       VF_STATIC = 1,          // module is static, cannot be /unloadmodule'd
+       VF_VENDOR = 2,          // module is a vendor module (came in the original tarball, not 3rd party)
+       VF_SERVICEPROVIDER = 4, // module provides a service to other modules (can be a dependency)
+       VF_COMMON = 8           // module needs to be common on all servers in a network to link
+};
+
+/** Used with SendToMode()
+ */
+enum WriteModeFlags {
+       WM_AND = 1,
+       WM_OR = 2
+};
+
+/** Used to represent an event type, for user, channel or server
+ */
+enum TargetTypeFlags {
+       TYPE_USER = 1,
+       TYPE_CHANNEL,
+       TYPE_SERVER,
+       TYPE_OTHER
+};
+
+/** Used to represent wether a message was PRIVMSG or NOTICE
+ */
+enum MessageType {
+       MSG_PRIVMSG = 0,
+       MSG_NOTICE = 1
+};
+
+#include "globals.h"
+#include "dynamic.h"
+#include "base.h"
+#include "ctables.h"
+#include "inspsocket.h"
+#include <string>
+#include <deque>
+#include <sstream>
+#include "timer.h"
+#include "mode.h"
+#include "dns.h"
+
+/** If you change the module API, change this value.
+ * If you have enabled ipv6, the sizes of structs is
+ * different, and modules will be incompatible with
+ * ipv4 servers, so this value will be ten times as
+ * high on ipv6 servers.
+ */
+#define NATIVE_API_VERSION 11025
+#ifdef IPV6
+#define API_VERSION (NATIVE_API_VERSION * 10)
+#else
+#define API_VERSION (NATIVE_API_VERSION * 1)
+#endif
+
+class ServerConfig;
+
+/* Forward-delacare module for ModuleMessage etc
+ */
+class Module;
+
+/** Low level definition of a FileReader classes file cache area -
+ * a text file seperated into lines.
+ */
+typedef std::deque<std::string> file_cache;
+
+/** A set of strings.
+ */
+typedef file_cache string_list;
+
+/** Holds a list of 'published features' for modules.
+ */
+typedef std::map<std::string,Module*> featurelist;
+
+/** Holds a list of modules which implement an interface
+ */
+typedef std::deque<Module*> modulelist;
+
+/** Holds a list of all modules which implement interfaces, by interface name
+ */
+typedef std::map<std::string, std::pair<int, modulelist> > interfacelist;
+
+/**
+ * This #define allows us to call a method in all
+ * loaded modules in a readable simple way, e.g.:
+ * 'FOREACH_MOD(I_OnConnect,OnConnect(user));'
+ */
+#define FOREACH_MOD(y,x) if (ServerInstance->Config->global_implementation[y] > 0) { \
+       for (int _i = 0; _i <= ServerInstance->GetModuleCount(); _i++) { \
+       if (ServerInstance->Config->implement_lists[_i][y]) \
+               try \
+               { \
+                       ServerInstance->modules[_i]->x ; \
+               } \
+               catch (CoreException& modexcept) \
+               { \
+                       ServerInstance->Log(DEFAULT,"Exception cought: %s",modexcept.GetReason()); \
+               } \
+       } \
+  }
+
+/**
+ * This #define allows us to call a method in all
+ * loaded modules in a readable simple way and pass
+ * an instance pointer to the macro. e.g.:
+ * 'FOREACH_MOD_I(Instance, OnConnect, OnConnect(user));'
+ */
+#define FOREACH_MOD_I(z,y,x) if (z->Config->global_implementation[y] > 0) { \
+       for (int _i = 0; _i <= z->GetModuleCount(); _i++) { \
+               if (z->Config->implement_lists[_i][y]) \
+               try \
+               { \
+                       z->modules[_i]->x ; \
+               } \
+               catch (CoreException& modexcept) \
+               { \
+                       z->Log(DEFAULT,"Exception cought: %s",modexcept.GetReason()); \
+               } \
+       } \
+}
+/**
+ * This define is similar to the one above but returns a result in MOD_RESULT.
+ * The first module to return a nonzero result is the value to be accepted,
+ * and any modules after are ignored.
+ */
+#define FOREACH_RESULT(y,x) { if (ServerInstance->Config->global_implementation[y] > 0) { \
+                       MOD_RESULT = 0; \
+                       for (int _i = 0; _i <= ServerInstance->GetModuleCount(); _i++) { \
+                       if (ServerInstance->Config->implement_lists[_i][y]) { \
+                               try \
+                               { \
+                                       int res = ServerInstance->modules[_i]->x ; \
+                                       if (res != 0) { \
+                                               MOD_RESULT = res; \
+                                               break; \
+                                       } \
+                               } \
+                               catch (CoreException& modexcept) \
+                               { \
+                                       ServerInstance->Log(DEFAULT,"Exception cought: %s",modexcept.GetReason()); \
+                               } \
+                       } \
+               } \
+       } \
+ }
+
+/**
+ * This define is similar to the one above but returns a result in MOD_RESULT.
+ * The first module to return a nonzero result is the value to be accepted,
+ * and any modules after are ignored.
+ */
+#define FOREACH_RESULT_I(z,y,x) { if (z->Config->global_implementation[y] > 0) { \
+                       MOD_RESULT = 0; \
+                       for (int _i = 0; _i <= z->GetModuleCount(); _i++) { \
+                       if (z->Config->implement_lists[_i][y]) { \
+                               try \
+                               { \
+                                       int res = z->modules[_i]->x ; \
+                                       if (res != 0) { \
+                                               MOD_RESULT = res; \
+                                               break; \
+                                       } \
+                               } \
+                               catch (CoreException& modexcept) \
+                               { \
+                                       z->Log(DEBUG,"Exception cought: %s",modexcept.GetReason()); \
+                               } \
+                       } \
+               } \
+       } \
+}
+
+/** Represents a non-local user.
+ * (in fact, any FD less than -1 does)
+ */
+#define FD_MAGIC_NUMBER -42
+
+/* Useful macros */
+#ifdef WINDOWS
+/** Is a local user */
+#define IS_LOCAL(x) ((x->GetFd() > -1))
+#else
+/** Is a local user */
+#define IS_LOCAL(x) ((x->GetFd() > -1) && (x->GetFd() <= MAX_DESCRIPTORS))
+#endif
+/** Is a remote user */
+#define IS_REMOTE(x) (x->GetFd() < 0)
+/** Is a module created user */
+#define IS_MODULE_CREATED(x) (x->GetFd() == FD_MAGIC_NUMBER)
+/** Is an oper */
+#define IS_OPER(x) (*x->oper)
+/** Is away */
+#define IS_AWAY(x) (*x->awaymsg)
+
+/** Holds a module's Version information.
+ *  The four members (set by the constructor only) indicate details as to the version number
+ *  of a module. A class of type Version is returned by the GetVersion method of the Module class.
+ *  The flags and API values represent the module flags and API version of the module.
+ *  The API version of a module must match the API version of the core exactly for the module to
+ *  load successfully.
+ */
+class CoreExport Version : public classbase
+{
+ public:
+        /** Version numbers, build number, flags and API version
+         */
+        const int Major, Minor, Revision, Build, Flags, API;
+
+        /** Initialize version class
+         */
+        Version(int major, int minor, int revision, int build, int flags, int api_ver);
+};
+
+/** The ModuleMessage class is the base class of Request and Event
+ * This class is used to represent a basic data structure which is passed
+ * between modules for safe inter-module communications.
+ */
+class CoreExport ModuleMessage : public Extensible
+{
+ public:
+       /** Destructor
+        */
+       virtual ~ModuleMessage() {};
+};
+
+/** The Request class is a unicast message directed at a given module.
+ * When this class is properly instantiated it may be sent to a module
+ * using the Send() method, which will call the given module's OnRequest
+ * method with this class as its parameter.
+ */
+class CoreExport Request : public ModuleMessage
+{
+ protected:
+       /** This member holds a pointer to arbitary data set by the emitter of the message
+        */
+       char* data;
+       /** This should be a null-terminated string identifying the type of request,
+        * all modules should define this and use it to determine the nature of the
+        * request before they attempt to cast the Request in any way.
+        */
+       const char* id;
+       /** This is a pointer to the sender of the message, which can be used to
+        * directly trigger events, or to create a reply.
+        */
+       Module* source;
+       /** The single destination of the Request
+        */
+       Module* dest;
+ public:
+       /** Create a new Request
+        * This is for the 'old' way of casting whatever the data is
+        * to char* and hoping you get the right thing at the other end.
+        * This is slowly being depreciated in favor of the 'new' way.
+        */
+       Request(char* anydata, Module* src, Module* dst);
+       /** Create a new Request
+        * This is for the 'new' way of defining a subclass
+        * of Request and defining it in a common header,
+        * passing an object of your Request subclass through
+        * as a Request* and using the ID string to determine
+        * what to cast it back to and the other end. This is
+        * much safer as there are no casts not confirmed by
+        * the ID string, and all casts are child->parent and
+        * can be checked at runtime with dynamic_cast<>()
+        */
+       Request(Module* src, Module* dst, const char* idstr);
+       /** Fetch the Request data
+        */
+       char* GetData();
+       /** Fetch the ID string
+        */
+       const char* GetId();
+       /** Fetch the request source
+        */
+       Module* GetSource();
+       /** Fetch the request destination (should be 'this' in the receiving module)
+        */
+       Module* GetDest();
+       /** Send the Request.
+        * Upon returning the result will be arbitary data returned by the module you
+        * sent the request to. It is up to your module to know what this data is and
+        * how to deal with it.
+        */
+       char* Send();
+};
+
+
+/** The Event class is a unicast message directed at all modules.
+ * When the class is properly instantiated it may be sent to all modules
+ * using the Send() method, which will trigger the OnEvent method in
+ * all modules passing the object as its parameter.
+ */
+class CoreExport Event : public ModuleMessage
+{
+ protected:
+       /** This member holds a pointer to arbitary data set by the emitter of the message
+        */
+       char* data;
+       /** This is a pointer to the sender of the message, which can be used to
+        * directly trigger events, or to create a reply.
+        */
+       Module* source;
+       /** The event identifier.
+        * This is arbitary text which should be used to distinguish
+        * one type of event from another.
+        */
+       std::string id;
+ public:
+       /** Create a new Event
+        */
+       Event(char* anydata, Module* src, const std::string &eventid);
+       /** Get the Event data
+        */
+       char* GetData();
+       /** Get the event Source
+        */
+       Module* GetSource();
+       /** Get the event ID.
+        * Use this to determine the event type for safe casting of the data
+        */
+       std::string GetEventID();
+       /** Send the Event.
+        * The return result of an Event::Send() will always be NULL as
+        * no replies are expected.
+        */
+       char* Send(InspIRCd* ServerInstance);
+};
+
+/** This class can be used on its own to represent an exception, or derived to represent a module-specific exception.
+ * When a module whishes to abort, e.g. within a constructor, it should throw an exception using ModuleException or
+ * a class derived from ModuleException. If a module throws an exception during its constructor, the module will not
+ * be loaded. If this happens, the error message returned by ModuleException::GetReason will be displayed to the user
+ * attempting to load the module, or dumped to the console if the ircd is currently loading for the first time.
+ */
+class CoreExport CoreException : public std::exception
+{
+ protected:
+       /** Holds the error message to be displayed
+        */
+       const std::string err;
+       /** Source of the exception
+        */
+       const std::string source;
+ public:
+       /** Default constructor, just uses the error mesage 'Core threw an exception'.
+        */
+       CoreException() : err("Core threw an exception"), source("The core") {}
+       /** This constructor can be used to specify an error message before throwing.
+        */
+       CoreException(const std::string &message) : err(message), source("The core") {}
+       /** This constructor can be used to specify an error message before throwing,
+        * and to specify the source of the exception.
+        */
+       CoreException(const std::string &message, const std::string &src) : err(message), source(src) {}
+       /** This destructor solves world hunger, cancels the world debt, and causes the world to end.
+        * Actually no, it does nothing. Never mind.
+        * @throws Nothing!
+        */
+       virtual ~CoreException() throw() {};
+       /** Returns the reason for the exception.
+        * The module should probably put something informative here as the user will see this upon failure.
+        */
+       virtual const char* GetReason()
+       {
+               return err.c_str();
+       }
+
+       virtual const char* GetSource()
+       {
+               return source.c_str();
+       }
+};
+
+class CoreExport ModuleException : public CoreException
+{
+ public:
+       /** Default constructor, just uses the error mesage 'Module threw an exception'.
+        */
+       ModuleException() : CoreException("Module threw an exception", "A Module") {}
+
+       /** This constructor can be used to specify an error message before throwing.
+        */
+       ModuleException(const std::string &message) : CoreException(message, "A Module") {}
+       /** This destructor solves world hunger, cancels the world debt, and causes the world to end.
+        * Actually no, it does nothing. Never mind.
+        * @throws Nothing!
+        */
+       virtual ~ModuleException() throw() {};
+};
+
+/** Priority types which can be returned from Module::Prioritize()
+ */
+enum Priority { PRIORITY_FIRST, PRIORITY_DONTCARE, PRIORITY_LAST, PRIORITY_BEFORE, PRIORITY_AFTER };
+
+/** Implementation-specific flags which may be set in Module::Implements()
+ */
+enum Implementation {  I_OnUserConnect, I_OnUserQuit, I_OnUserDisconnect, I_OnUserJoin, I_OnUserPart, I_OnRehash, I_OnServerRaw, 
+                       I_OnUserPreJoin, I_OnUserPreKick, I_OnUserKick, I_OnOper, I_OnInfo, I_OnWhois, I_OnUserPreInvite,
+                       I_OnUserInvite, I_OnUserPreMessage, I_OnUserPreNotice, I_OnUserPreNick, I_OnUserMessage, I_OnUserNotice, I_OnMode,
+                       I_OnGetServerDescription, I_OnSyncUser, I_OnSyncChannel, I_OnSyncChannelMetaData, I_OnSyncUserMetaData,
+                       I_OnDecodeMetaData, I_ProtoSendMode, I_ProtoSendMetaData, I_OnWallops, I_OnChangeHost, I_OnChangeName, I_OnAddGLine,
+                       I_OnAddZLine, I_OnAddQLine, I_OnAddKLine, I_OnAddELine, I_OnDelGLine, I_OnDelZLine, I_OnDelKLine, I_OnDelELine, I_OnDelQLine,
+                       I_OnCleanup, I_OnUserPostNick, I_OnAccessCheck, I_On005Numeric, I_OnKill, I_OnRemoteKill, I_OnLoadModule, I_OnUnloadModule,
+                       I_OnBackgroundTimer, I_OnPreCommand, I_OnCheckReady, I_OnUserRrgister, I_OnCheckInvite,
+                       I_OnCheckKey, I_OnCheckLimit, I_OnCheckBan, I_OnStats, I_OnChangeLocalUserHost, I_OnChangeLocalUserGecos, I_OnLocalTopicChange,
+                       I_OnPostLocalTopicChange, I_OnEvent, I_OnRequest, I_OnOperCompre, I_OnGlobalOper, I_OnPostConnect, I_OnAddBan, I_OnDelBan,
+                       I_OnRawSocketAccept, I_OnRawSocketClose, I_OnRawSocketWrite, I_OnRawSocketRead, I_OnChangeLocalUserGECOS, I_OnUserRegister,
+                       I_OnOperCompare, I_OnChannelDelete, I_OnPostOper, I_OnSyncOtherMetaData, I_OnSetAway, I_OnCancelAway, I_OnUserList,
+                       I_OnPostCommand, I_OnPostJoin, I_OnWhoisLine, I_OnBuildExemptList, I_OnRawSocketConnect, I_OnGarbageCollect, I_OnBufferFlushed };
+
+/** Base class for all InspIRCd modules
+ *  This class is the base class for InspIRCd modules. All modules must inherit from this class,
+ *  its methods will be called when irc server events occur. class inherited from module must be
+ *  instantiated by the ModuleFactory class (see relevent section) for the module to be initialised.
+ */
+class CoreExport Module : public Extensible
+{
+ protected:
+       /** Creator/owner pointer
+        */
+       InspIRCd* ServerInstance;
+ public:
+
+       /** Default constructor.
+        * Creates a module class.
+        * @param Me An instance of the InspIRCd class which will be saved into ServerInstance for your use
+        * \exception ModuleException Throwing this class, or any class derived from ModuleException, causes loading of the module to abort.
+        */
+       Module(InspIRCd* Me);
+
+       /** Default destructor.
+        * destroys a module class
+        */
+       virtual ~Module();
+
+       /** Returns the version number of a Module.
+        * The method should return a Version object with its version information assigned via
+        * Version::Version
+        */
+       virtual Version GetVersion();
+
+       /** The Implements function specifies which methods a module should receive events for.
+        * The char* parameter passed to this function contains a set of true or false values
+        * (1 or 0) which indicate wether each function is implemented. You must use the Iimplementation
+        * enum (documented elsewhere on this page) to mark functions as active. For example, to
+        * receive events for OnUserJoin():
+        *
+        * Implements[I_OnUserJoin] = 1;
+        *
+        * @param The implement list
+        */
+       virtual void Implements(char* Implements);
+
+       /** Used to set the 'priority' of a module (e.g. when it is called in relation to other modules.
+        * Some modules prefer to be called before other modules, due to their design. For example, a
+        * module which is expected to operate on complete information would expect to be placed last, so
+        * that any other modules which wish to adjust that information would execute before it, to be sure
+        * its information is correct. You can change your module's priority by returning one of:
+        *
+        * PRIORITY_FIRST - To place your module first in the list
+        * 
+        * PRIORITY_LAST - To place your module last in the list
+        *
+        * PRIORITY_DONTCARE - To leave your module as it is (this is the default value, if you do not implement this function)
+        *
+        * The result of InspIRCd::PriorityBefore() - To move your module before another named module
+        *
+        * The result of InspIRCd::PriorityLast() - To move your module after another named module
+        *
+        * For a good working example of this method call, please see src/modules/m_spanningtree.cpp
+        * and src/modules/m_hostchange.so which make use of it. It is highly recommended that unless
+        * your module has a real need to reorder its priority, it should not implement this function,
+        * as many modules changing their priorities can make the system redundant.
+        */
+       virtual Priority Prioritize();
+
+       /** Called when a user connects.
+        * The details of the connecting user are available to you in the parameter userrec *user
+        * @param user The user who is connecting
+        */
+       virtual void OnUserConnect(userrec* user);
+
+       /** Called when a user quits.
+        * The details of the exiting user are available to you in the parameter userrec *user
+        * This event is only called when the user is fully registered when they quit. To catch
+        * raw disconnections, use the OnUserDisconnect method.
+        * @param user The user who is quitting
+        * @param message The user's quit message (as seen by non-opers)
+        * @param oper_message The user's quit message (as seen by opers)
+        */
+       virtual void OnUserQuit(userrec* user, const std::string &message, const std::string &oper_message);
+
+       /** Called whenever a user's socket is closed.
+        * The details of the exiting user are available to you in the parameter userrec *user
+        * This event is called for all users, registered or not, as a cleanup method for modules
+        * which might assign resources to user, such as dns lookups, objects and sockets.
+        * @param user The user who is disconnecting
+        */
+       virtual void OnUserDisconnect(userrec* user);
+
+       /** Called whenever a channel is deleted, either by QUIT, KICK or PART.
+        * @param chan The channel being deleted
+        */
+       virtual void OnChannelDelete(chanrec* chan);
+
+       /** Called when a user joins a channel.
+        * The details of the joining user are available to you in the parameter userrec *user,
+        * and the details of the channel they have joined is available in the variable chanrec *channel
+        * @param user The user who is joining
+        * @param channel The channel being joined
+        * @param silent Change this to true if you want to conceal the JOIN command from the other users
+        * of the channel (useful for modules such as auditorium)
+        */
+       virtual void OnUserJoin(userrec* user, chanrec* channel, bool &silent);
+
+       /** Called after a user joins a channel
+        * Identical to OnUserJoin, but called immediately afterwards, when any linking module has
+        * seen the join.
+        * @param user The user who is joining
+        * @param channel The channel being joined
+        */
+       virtual void OnPostJoin(userrec* user, chanrec* channel);
+
+       /** Called when a user parts a channel.
+        * The details of the leaving user are available to you in the parameter userrec *user,
+        * and the details of the channel they have left is available in the variable chanrec *channel
+        * @param user The user who is parting
+        * @param channel The channel being parted
+        * @param partmessage The part message, or an empty string
+        * @param silent Change this to true if you want to conceal the PART command from the other users
+        * of the channel (useful for modules such as auditorium)
+        */
+       virtual void OnUserPart(userrec* user, chanrec* channel, const std::string &partmessage, bool &silent);
+
+       /** Called on rehash.
+        * This method is called prior to a /REHASH or when a SIGHUP is received from the operating
+        * system. You should use it to reload any files so that your module keeps in step with the
+        * rest of the application. If a parameter is given, the core has done nothing. The module
+        * receiving the event can decide if this parameter has any relevence to it.
+        * @param user The user performing the rehash, if any -- if this is server initiated, the
+        * value of this variable will be NULL.
+        * @param parameter The (optional) parameter given to REHASH from the user.
+        */
+       virtual void OnRehash(userrec* user, const std::string &parameter);
+
+       /** Called when a raw command is transmitted or received.
+        * This method is the lowest level of handler available to a module. It will be called with raw
+        * data which is passing through a connected socket. If you wish, you may munge this data by changing
+        * the string parameter "raw". If you do this, after your function exits it will immediately be
+        * cut down to 510 characters plus a carriage return and linefeed. For INBOUND messages only (where
+        * inbound is set to true) the value of user will be the userrec of the connection sending the
+        * data. This is not possible for outbound data because the data may be being routed to multiple targets.
+        * @param raw The raw string in RFC1459 format
+        * @param inbound A flag to indicate wether the data is coming into the daemon or going out to the user
+        * @param user The user record sending the text, when inbound == true.
+        */
+       virtual void OnServerRaw(std::string &raw, bool inbound, userrec* user);
+
+       /** Called whenever a user is about to join a channel, before any processing is done.
+        * Returning a value of 1 from this function stops the process immediately, causing no
+        * output to be sent to the user by the core. If you do this you must produce your own numerics,
+        * notices etc. This is useful for modules which may want to mimic +b, +k, +l etc. Returning -1 from
+        * this function forces the join to be allowed, bypassing restrictions such as banlists, invite, keys etc.
+        *
+        * IMPORTANT NOTE!
+        *
+        * If the user joins a NEW channel which does not exist yet, OnUserPreJoin will be called BEFORE the channel
+        * record is created. This will cause chanrec* chan to be NULL. There is very little you can do in form of
+        * processing on the actual channel record at this point, however the channel NAME will still be passed in
+        * char* cname, so that you could for example implement a channel blacklist or whitelist, etc.
+        * @param user The user joining the channel
+        * @param chan If the  channel is a new channel, this will be NULL, otherwise it will be a pointer to the channel being joined
+        * @param cname The channel name being joined. For new channels this is valid where chan is not.
+        * @param privs A string containing the users privilages when joining the channel. For new channels this will contain "@".
+        * You may alter this string to alter the user's modes on the channel.
+        * @return 1 To prevent the join, 0 to allow it.
+        */
+       virtual int OnUserPreJoin(userrec* user, chanrec* chan, const char* cname, std::string &privs);
+       
+       /** Called whenever a user is about to be kicked.
+        * Returning a value of 1 from this function stops the process immediately, causing no
+        * output to be sent to the user by the core. If you do this you must produce your own numerics,
+        * notices etc.
+        * @param source The user issuing the kick
+        * @param user The user being kicked
+        * @param chan The channel the user is being kicked from
+        * @param reason The kick reason
+        * @return 1 to prevent the kick, 0 to continue normally, -1 to explicitly allow the kick regardless of normal operation
+        */
+       virtual int OnUserPreKick(userrec* source, userrec* user, chanrec* chan, const std::string &reason);
+
+       /** Called whenever a user is kicked.
+        * If this method is called, the kick is already underway and cannot be prevented, so
+        * to prevent a kick, please use Module::OnUserPreKick instead of this method.
+        * @param source The user issuing the kick
+        * @param user The user being kicked
+        * @param chan The channel the user is being kicked from
+        * @param reason The kick reason
+        * @param silent Change this to true if you want to conceal the PART command from the other users
+        * of the channel (useful for modules such as auditorium)
+        */
+       virtual void OnUserKick(userrec* source, userrec* user, chanrec* chan, const std::string &reason, bool &silent);
+
+       /** Called whenever a user opers locally.
+        * The userrec will contain the oper mode 'o' as this function is called after any modifications
+        * are made to the user's structure by the core.
+        * @param user The user who is opering up
+        * @param opertype The opers type name
+        */
+       virtual void OnOper(userrec* user, const std::string &opertype);
+
+       /** Called after a user opers locally.
+        * This is identical to Module::OnOper(), except it is called after OnOper so that other modules
+        * can be gauranteed to already have processed the oper-up, for example m_spanningtree has sent
+        * out the OPERTYPE, etc.
+        * @param user The user who is opering up
+        * @param opertype The opers type name
+        */
+       virtual void OnPostOper(userrec* user, const std::string &opertype);
+       
+       /** Called whenever a user types /INFO.
+        * The userrec will contain the information of the user who typed the command. Modules may use this
+        * method to output their own credits in /INFO (which is the ircd's version of an about box).
+        * It is purposefully not possible to modify any info that has already been output, or halt the list.
+        * You must write a 371 numeric to the user, containing your info in the following format:
+        *
+        * &lt;nick&gt; :information here
+        *
+        * @param user The user issuing /INFO
+        */
+       virtual void OnInfo(userrec* user);
+       
+       /** Called whenever a /WHOIS is performed on a local user.
+        * The source parameter contains the details of the user who issued the WHOIS command, and
+        * the dest parameter contains the information of the user they are whoising.
+        * @param source The user issuing the WHOIS command
+        * @param dest The user who is being WHOISed
+        */
+       virtual void OnWhois(userrec* source, userrec* dest);
+       
+       /** Called whenever a user is about to invite another user into a channel, before any processing is done.
+        * Returning 1 from this function stops the process immediately, causing no
+        * output to be sent to the user by the core. If you do this you must produce your own numerics,
+        * notices etc. This is useful for modules which may want to filter invites to channels.
+        * @param source The user who is issuing the INVITE
+        * @param dest The user being invited
+        * @param channel The channel the user is being invited to
+        * @return 1 to deny the invite, 0 to allow
+        */
+       virtual int OnUserPreInvite(userrec* source,userrec* dest,chanrec* channel);
+       
+       /** Called after a user has been successfully invited to a channel.
+        * You cannot prevent the invite from occuring using this function, to do that,
+        * use OnUserPreInvite instead.
+        * @param source The user who is issuing the INVITE
+        * @param dest The user being invited
+        * @param channel The channel the user is being invited to
+        */
+       virtual void OnUserInvite(userrec* source,userrec* dest,chanrec* channel);
+       
+       /** Called whenever a user is about to PRIVMSG A user or a channel, before any processing is done.
+        * Returning any nonzero value from this function stops the process immediately, causing no
+        * output to be sent to the user by the core. If you do this you must produce your own numerics,
+        * notices etc. This is useful for modules which may want to filter or redirect messages.
+        * target_type can be one of TYPE_USER or TYPE_CHANNEL. If the target_type value is a user,
+        * you must cast dest to a userrec* otherwise you must cast it to a chanrec*, this is the details
+        * of where the message is destined to be sent.
+        * @param user The user sending the message
+        * @param dest The target of the message (chanrec* or userrec*)
+        * @param target_type The type of target (TYPE_USER or TYPE_CHANNEL)
+        * @param text Changeable text being sent by the user
+        * @param status The status being used, e.g. PRIVMSG @#chan has status== '@', 0 to send to everyone.
+        * @param exempt_list A list of users not to send to. For channel messages, this will usually contain just the sender.
+        * It will be ignored for private messages.
+        * @return 1 to deny the NOTICE, 0 to allow it
+        */
+       virtual int OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text,char status, CUList &exempt_list);
+
+       /** Called whenever a user is about to NOTICE A user or a channel, before any processing is done.
+        * Returning any nonzero value from this function stops the process immediately, causing no
+        * output to be sent to the user by the core. If you do this you must produce your own numerics,
+        * notices etc. This is useful for modules which may want to filter or redirect messages.
+        * target_type can be one of TYPE_USER or TYPE_CHANNEL. If the target_type value is a user,
+        * you must cast dest to a userrec* otherwise you must cast it to a chanrec*, this is the details
+        * of where the message is destined to be sent.
+        * You may alter the message text as you wish before relinquishing control to the next module
+        * in the chain, and if no other modules block the text this altered form of the text will be sent out
+        * to the user and possibly to other servers.
+        * @param user The user sending the message
+        * @param dest The target of the message (chanrec* or userrec*)
+        * @param target_type The type of target (TYPE_USER or TYPE_CHANNEL)
+        * @param text Changeable text being sent by the user
+        * @param status The status being used, e.g. PRIVMSG @#chan has status== '@', 0 to send to everyone.
+        * @param exempt_list A list of users not to send to. For channel notices, this will usually contain just the sender.
+        * It will be ignored for private notices.
+        * @return 1 to deny the NOTICE, 0 to allow it
+        */
+       virtual int OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text,char status, CUList &exempt_list);
+
+       /** Called whenever the server wants to build the exemption list for a channel, but is not directly doing a PRIVMSG or NOTICE.
+        * For example, the spanningtree protocol will call this event when passing a privmsg on (but not processing it directly).
+        * @param message_type The message type, either MSG_PRIVMSG or MSG_NOTICE
+        * @param chan The channel to build the exempt list of
+        * @param sender The original sender of the PRIVMSG or NOTICE
+        * @param status The status char to be used for the channel list
+        * @param exempt_list The exempt list to be populated
+        */
+       virtual void OnBuildExemptList(MessageType message_type, chanrec* chan, userrec* sender, char status, CUList &exempt_list);
+       
+       /** Called before any nickchange, local or remote. This can be used to implement Q-lines etc.
+        * Please note that although you can see remote nickchanges through this function, you should
+        * NOT make any changes to the userrec if the user is a remote user as this may cause a desnyc.
+        * check user->server before taking any action (including returning nonzero from the method).
+        * If your method returns nonzero, the nickchange is silently forbidden, and it is down to your
+        * module to generate some meaninful output.
+        * @param user The username changing their nick
+        * @param newnick Their new nickname
+        * @return 1 to deny the change, 0 to allow
+        */
+       virtual int OnUserPreNick(userrec* user, const std::string &newnick);
+
+       /** Called after any PRIVMSG sent from a user.
+        * The dest variable contains a userrec* if target_type is TYPE_USER and a chanrec*
+        * if target_type is TYPE_CHANNEL.
+        * @param user The user sending the message
+        * @param dest The target of the message
+        * @param target_type The type of target (TYPE_USER or TYPE_CHANNEL)
+        * @param text the text being sent by the user
+        * @param status The status being used, e.g. PRIVMSG @#chan has status== '@', 0 to send to everyone.
+        */
+       virtual void OnUserMessage(userrec* user, void* dest, int target_type, const std::string &text, char status, const CUList &exempt_list);
+
+       /** Called after any NOTICE sent from a user.
+        * The dest variable contains a userrec* if target_type is TYPE_USER and a chanrec*
+        * if target_type is TYPE_CHANNEL.
+        * @param user The user sending the message
+        * @param dest The target of the message
+        * @param target_type The type of target (TYPE_USER or TYPE_CHANNEL)
+        * @param text the text being sent by the user
+        * @param status The status being used, e.g. NOTICE @#chan has status== '@', 0 to send to everyone.
+        */
+       virtual void OnUserNotice(userrec* user, void* dest, int target_type, const std::string &text, char status, const CUList &exempt_list);
+
+       /** Called after every MODE command sent from a user
+        * The dest variable contains a userrec* if target_type is TYPE_USER and a chanrec*
+        * if target_type is TYPE_CHANNEL. The text variable contains the remainder of the
+        * mode string after the target, e.g. "+wsi" or "+ooo nick1 nick2 nick3".
+        * @param user The user sending the MODEs
+        * @param dest The target of the modes (userrec* or chanrec*)
+        * @param target_type The type of target (TYPE_USER or TYPE_CHANNEL)
+        * @param text The actual modes and their parameters if any
+        */
+       virtual void OnMode(userrec* user, void* dest, int target_type, const std::string &text);
+
+       /** Allows modules to alter or create server descriptions
+        * Whenever a module requires a server description, for example for display in
+        * WHOIS, this function is called in all modules. You may change or define the
+        * description given in std::string &description. If you do, this description
+        * will be shown in the WHOIS fields.
+        * @param servername The servername being searched for
+        * @param description Alterable server description for this server
+        */
+       virtual void OnGetServerDescription(const std::string &servername,std::string &description);
+
+       /** Allows modules to synchronize data which relates to users during a netburst.
+        * When this function is called, it will be called from the module which implements
+        * the linking protocol. This currently is m_spanningtree.so. A pointer to this module
+        * is given in Module* proto, so that you may call its methods such as ProtoSendMode
+        * (see below). This function will be called for every user visible on your side
+        * of the burst, allowing you to for example set modes, etc. Do not use this call to
+        * synchronize data which you have stored using class Extensible -- There is a specialist
+        * function OnSyncUserMetaData and OnSyncChannelMetaData for this!
+        * @param user The user being syncronized
+        * @param proto A pointer to the module handling network protocol
+        * @param opaque An opaque pointer set by the protocol module, should not be modified!
+        */
+       virtual void OnSyncUser(userrec* user, Module* proto, void* opaque);
+
+       /** Allows modules to synchronize data which relates to channels during a netburst.
+        * When this function is called, it will be called from the module which implements
+        * the linking protocol. This currently is m_spanningtree.so. A pointer to this module
+        * is given in Module* proto, so that you may call its methods such as ProtoSendMode
+        * (see below). This function will be called for every user visible on your side
+        * of the burst, allowing you to for example set modes, etc. Do not use this call to
+        * synchronize data which you have stored using class Extensible -- There is a specialist
+        * function OnSyncUserMetaData and OnSyncChannelMetaData for this!
+        *
+        * For a good example of how to use this function, please see src/modules/m_chanprotect.cpp
+        *
+        * @param chan The channel being syncronized
+        * @param proto A pointer to the module handling network protocol
+        * @param opaque An opaque pointer set by the protocol module, should not be modified!
+        */
+       virtual void OnSyncChannel(chanrec* chan, Module* proto, void* opaque);
+
+       /* Allows modules to syncronize metadata related to channels over the network during a netburst.
+        * Whenever the linking module wants to send out data, but doesnt know what the data
+        * represents (e.g. it is Extensible metadata, added to a userrec or chanrec by a module) then
+        * this method is called.You should use the ProtoSendMetaData function after you've
+        * correctly decided how the data should be represented, to send the metadata on its way if it belongs
+        * to your module. For a good example of how to use this method, see src/modules/m_swhois.cpp.
+        * @param chan The channel whos metadata is being syncronized
+        * @param proto A pointer to the module handling network protocol
+        * @param opaque An opaque pointer set by the protocol module, should not be modified!
+        * @param extname The extensions name which is being searched for
+        * @param displayable If this value is true, the data is going to be displayed to a user,
+        * and not sent across the network. Use this to determine wether or not to show sensitive data.
+        */
+       virtual void OnSyncChannelMetaData(chanrec* chan, Module* proto,void* opaque, const std::string &extname, bool displayable = false);
+
+       /* Allows modules to syncronize metadata related to users over the network during a netburst.
+        * Whenever the linking module wants to send out data, but doesnt know what the data
+        * represents (e.g. it is Extensible metadata, added to a userrec or chanrec by a module) then
+        * this method is called. You should use the ProtoSendMetaData function after you've
+        * correctly decided how the data should be represented, to send the metadata on its way if
+        * if it belongs to your module.
+        * @param user The user whos metadata is being syncronized
+        * @param proto A pointer to the module handling network protocol
+        * @param opaque An opaque pointer set by the protocol module, should not be modified!
+        * @param extname The extensions name which is being searched for
+        * @param displayable If this value is true, the data is going to be displayed to a user,
+        * and not sent across the network. Use this to determine wether or not to show sensitive data.
+        */
+       virtual void OnSyncUserMetaData(userrec* user, Module* proto,void* opaque, const std::string &extname, bool displayable = false);
+
+       /* Allows modules to syncronize metadata not related to users or channels, over the network during a netburst.
+        * Whenever the linking module wants to send out data, but doesnt know what the data
+        * represents (e.g. it is Extensible metadata, added to a userrec or chanrec by a module) then
+        * this method is called. You should use the ProtoSendMetaData function after you've
+        * correctly decided how the data should be represented, to send the metadata on its way if
+        * if it belongs to your module.
+        * @param proto A pointer to the module handling network protocol
+        * @param opaque An opaque pointer set by the protocol module, should not be modified!
+        * @param displayable If this value is true, the data is going to be displayed to a user,
+        * and not sent across the network. Use this to determine wether or not to show sensitive data.
+        */
+       virtual void OnSyncOtherMetaData(Module* proto, void* opaque, bool displayable = false);
+
+       /** Allows module data, sent via ProtoSendMetaData, to be decoded again by a receiving module.
+        * Please see src/modules/m_swhois.cpp for a working example of how to use this method call.
+        * @param target_type The type of item to decode data for, TYPE_USER or TYPE_CHANNEL
+        * @param target The chanrec* or userrec* that data should be added to
+        * @param extname The extension name which is being sent
+        * @param extdata The extension data, encoded at the other end by an identical module through OnSyncChannelMetaData or OnSyncUserMetaData
+        */
+       virtual void OnDecodeMetaData(int target_type, void* target, const std::string &extname, const std::string &extdata);
+
+       /** Implemented by modules which provide the ability to link servers.
+        * These modules will implement this method, which allows transparent sending of servermodes
+        * down the network link as a broadcast, without a module calling it having to know the format
+        * of the MODE command before the actual mode string.
+        *
+        * More documentation to follow soon. Please see src/modules/m_chanprotect.cpp for examples
+        * of how to use this function.
+        *
+        * @param opaque An opaque pointer set by the protocol module, should not be modified!
+        * @param target_type The type of item to decode data for, TYPE_USER or TYPE_CHANNEL
+        * @param target The chanrec* or userrec* that modes should be sent for
+        * @param modeline The modes and parameters to be sent
+        */
+       virtual void ProtoSendMode(void* opaque, int target_type, void* target, const std::string &modeline);
+
+       /** Implemented by modules which provide the ability to link servers.
+        * These modules will implement this method, which allows metadata (extra data added to
+        * user and channel records using class Extensible, Extensible::Extend, etc) to be sent
+        * to other servers on a netburst and decoded at the other end by the same module on a
+        * different server.
+        *
+        * More documentation to follow soon. Please see src/modules/m_swhois.cpp for example of
+        * how to use this function.
+        * @param opaque An opaque pointer set by the protocol module, should not be modified!
+        * @param target_type The type of item to decode data for, TYPE_USER or TYPE_CHANNEL
+        * @param target The chanrec* or userrec* that metadata should be sent for
+        * @param extname The extension name to send metadata for
+        * @param extdata Encoded data for this extension name, which will be encoded at the oppsite end by an identical module using OnDecodeMetaData
+        */
+       virtual void ProtoSendMetaData(void* opaque, int target_type, void* target, const std::string &extname, const std::string &extdata);
+       
+       /** Called after every WALLOPS command.
+        * @param user The user sending the WALLOPS
+        * @param text The content of the WALLOPS message
+        */
+       virtual void OnWallops(userrec* user, const std::string &text);
+
+       /** Called whenever a user's hostname is changed.
+        * This event triggers after the host has been set.
+        * @param user The user whos host is being changed
+        * @param newhost The new hostname being set
+        */
+       virtual void OnChangeHost(userrec* user, const std::string &newhost);
+
+       /** Called whenever a user's GECOS (realname) is changed.
+        * This event triggers after the name has been set.
+        * @param user The user who's GECOS is being changed
+        * @param gecos The new GECOS being set on the user
+        */
+       virtual void OnChangeName(userrec* user, const std::string &gecos);
+
+       /** Called whenever a gline is added by a local user.
+        * This method is triggered after the line is added.
+        * @param duration The duration of the line in seconds
+        * @param source The sender of the line
+        * @param reason The reason text to be displayed
+        * @param hostmask The hostmask to add
+        */
+       virtual void OnAddGLine(long duration, userrec* source, const std::string &reason, const std::string &hostmask);
+
+       /** Called whenever a zline is added by a local user.
+        * This method is triggered after the line is added.
+        * @param duration The duration of the line in seconds
+        * @param source The sender of the line
+        * @param reason The reason text to be displayed
+        * @param ipmask The hostmask to add
+        */
+       virtual void OnAddZLine(long duration, userrec* source, const std::string &reason, const std::string &ipmask);
+
+       /** Called whenever a kline is added by a local user.
+        * This method is triggered after the line is added.
+        * @param duration The duration of the line in seconds
+        * @param source The sender of the line
+        * @param reason The reason text to be displayed
+        * @param hostmask The hostmask to add
+        */
+       virtual void OnAddKLine(long duration, userrec* source, const std::string &reason, const std::string &hostmask);
+
+       /** Called whenever a qline is added by a local user.
+        * This method is triggered after the line is added.
+        * @param duration The duration of the line in seconds
+        * @param source The sender of the line
+        * @param reason The reason text to be displayed
+        * @param nickmask The hostmask to add
+        */
+       virtual void OnAddQLine(long duration, userrec* source, const std::string &reason, const std::string &nickmask);
+
+       /** Called whenever a eline is added by a local user.
+        * This method is triggered after the line is added.
+        * @param duration The duration of the line in seconds
+        * @param source The sender of the line
+        * @param reason The reason text to be displayed
+        * @param hostmask The hostmask to add
+        */
+       virtual void OnAddELine(long duration, userrec* source, const std::string &reason, const std::string &hostmask);
+
+       /** Called whenever a gline is deleted.
+        * This method is triggered after the line is deleted.
+        * @param source The user removing the line
+        * @param hostmask The hostmask to delete
+        */
+       virtual void OnDelGLine(userrec* source, const std::string &hostmask);
+
+       /** Called whenever a zline is deleted.
+        * This method is triggered after the line is deleted.
+        * @param source The user removing the line
+        * @param hostmask The hostmask to delete
+        */
+       virtual void OnDelZLine(userrec* source, const std::string &ipmask);
+
+       /** Called whenever a kline is deleted.
+        * This method is triggered after the line is deleted.
+        * @param source The user removing the line
+        * @param hostmask The hostmask to delete
+        */
+       virtual void OnDelKLine(userrec* source, const std::string &hostmask);
+       
+       /** Called whenever a qline is deleted.
+        * This method is triggered after the line is deleted.
+        * @param source The user removing the line
+        * @param hostmask The hostmask to delete
+        */
+       virtual void OnDelQLine(userrec* source, const std::string &nickmask);
+
+       /** Called whenever a eline is deleted.
+        * This method is triggered after the line is deleted.
+        * @param source The user removing the line
+        * @param hostmask The hostmask to delete
+        */
+       virtual void OnDelELine(userrec* source, const std::string &hostmask);
+
+       /** Called before your module is unloaded to clean up Extensibles.
+        * This method is called once for every user and channel on the network,
+        * so that when your module unloads it may clear up any remaining data
+        * in the form of Extensibles added using Extensible::Extend().
+        * If the target_type variable is TYPE_USER, then void* item refers to
+        * a userrec*, otherwise it refers to a chanrec*.
+        * @param target_type The type of item being cleaned
+        * @param item A pointer to the item's class
+        */
+       virtual void OnCleanup(int target_type, void* item);
+
+       /** Called after any nickchange, local or remote. This can be used to track users after nickchanges
+        * have been applied. Please note that although you can see remote nickchanges through this function, you should
+        * NOT make any changes to the userrec if the user is a remote user as this may cause a desnyc.
+        * check user->server before taking any action (including returning nonzero from the method).
+        * Because this method is called after the nickchange is taken place, no return values are possible
+        * to indicate forbidding of the nick change. Use OnUserPreNick for this.
+        * @param user The user changing their nick
+        * @param oldnick The old nickname of the user before the nickchange
+        */
+       virtual void OnUserPostNick(userrec* user, const std::string &oldnick);
+
+       /** Called before an action which requires a channel privilage check.
+        * This function is called before many functions which check a users status on a channel, for example
+        * before opping a user, deopping a user, kicking a user, etc.
+        * There are several values for access_type which indicate for what reason access is being checked.
+        * These are:<br><br>
+        * AC_KICK (0) - A user is being kicked<br>
+        * AC_DEOP (1) - a user is being deopped<br>
+        * AC_OP (2) - a user is being opped<br>
+        * AC_VOICE (3) - a user is being voiced<br>
+        * AC_DEVOICE (4) - a user is being devoiced<br>
+        * AC_HALFOP (5) - a user is being halfopped<br>
+        * AC_DEHALFOP (6) - a user is being dehalfopped<br>
+        * AC_INVITE () - a user is being invited<br>
+        * AC_GENERAL_MODE (8) - a user channel mode is being changed<br><br>
+        * Upon returning from your function you must return either ACR_DEFAULT, to indicate the module wishes
+        * to do nothing, or ACR_DENY where approprate to deny the action, and ACR_ALLOW where appropriate to allow
+        * the action. Please note that in the case of some access checks (such as AC_GENERAL_MODE) access may be
+        * denied 'upstream' causing other checks such as AC_DEOP to not be reached. Be very careful with use of the
+        * AC_GENERAL_MODE type, as it may inadvertently override the behaviour of other modules. When the access_type
+        * is AC_GENERAL_MODE, the destination of the mode will be NULL (as it has not yet been determined).
+        * @param source The source of the access check
+        * @param dest The destination of the access check
+        * @param channel The channel which is being checked
+        * @param access_type See above
+        */
+       virtual int OnAccessCheck(userrec* source,userrec* dest,chanrec* channel,int access_type);
+
+       /** Called when a 005 numeric is about to be output.
+        * The module should modify the 005 numeric if needed to indicate its features.
+        * @param output The 005 string to be modified if neccessary.
+        */
+       virtual void On005Numeric(std::string &output);
+
+       /** Called when a client is disconnected by KILL.
+        * If a client is killed by a server, e.g. a nickname collision or protocol error,
+        * source is NULL.
+        * Return 1 from this function to prevent the kill, and 0 from this function to allow
+        * it as normal. If you prevent the kill no output will be sent to the client, it is
+        * down to your module to generate this information.
+        * NOTE: It is NOT advisable to stop kills which originate from servers or remote users.
+        * If you do so youre risking race conditions, desyncs and worse!
+        * @param source The user sending the KILL
+        * @param dest The user being killed
+        * @param reason The kill reason
+        * @return 1 to prevent the kill, 0 to allow
+        */
+       virtual int OnKill(userrec* source, userrec* dest, const std::string &reason);
+
+       /** Called when an oper wants to disconnect a remote user via KILL
+        * @param source The user sending the KILL
+        * @param dest The user being killed
+        * @param reason The kill reason
+        */
+       virtual void OnRemoteKill(userrec* source, userrec* dest, const std::string &reason, const std::string &operreason);
+
+       /** Called whenever a module is loaded.
+        * mod will contain a pointer to the module, and string will contain its name,
+        * for example m_widgets.so. This function is primary for dependency checking,
+        * your module may decide to enable some extra features if it sees that you have
+        * for example loaded "m_killwidgets.so" with "m_makewidgets.so". It is highly
+        * recommended that modules do *NOT* bail if they cannot satisfy dependencies,
+        * but instead operate under reduced functionality, unless the dependency is
+        * absolutely neccessary (e.g. a module that extends the features of another
+        * module).
+        * @param mod A pointer to the new module
+        * @param name The new module's filename
+        */
+       virtual void OnLoadModule(Module* mod,const std::string &name);
+
+       /** Called whenever a module is unloaded.
+        * mod will contain a pointer to the module, and string will contain its name,
+        * for example m_widgets.so. This function is primary for dependency checking,
+        * your module may decide to enable some extra features if it sees that you have
+        * for example loaded "m_killwidgets.so" with "m_makewidgets.so". It is highly
+        * recommended that modules do *NOT* bail if they cannot satisfy dependencies,
+        * but instead operate under reduced functionality, unless the dependency is
+        * absolutely neccessary (e.g. a module that extends the features of another
+        * module).
+        * @param mod Pointer to the module being unloaded (still valid)
+        * @param name The filename of the module being unloaded
+        */
+       virtual void OnUnloadModule(Module* mod,const std::string &name);
+
+       /** Called once every five seconds for background processing.
+        * This timer can be used to control timed features. Its period is not accurate
+        * enough to be used as a clock, but it is gauranteed to be called at least once in
+        * any five second period, directly from the main loop of the server.
+        * @param curtime The current timer derived from time(2)
+        */
+       virtual void OnBackgroundTimer(time_t curtime);
+
+       /** Called whenever any command is about to be executed.
+        * This event occurs for all registered commands, wether they are registered in the core,
+        * or another module, and for invalid commands. Invalid commands may only be sent to this
+        * function when the value of validated is false. By returning 1 from this method you may prevent the
+        * command being executed. If you do this, no output is created by the core, and it is
+        * down to your module to produce any output neccessary.
+        * Note that unless you return 1, you should not destroy any structures (e.g. by using
+        * InspIRCd::QuitUser) otherwise when the command's handler function executes after your
+        * method returns, it will be passed an invalid pointer to the user object and crash!)
+        * @param command The command being executed
+        * @param parameters An array of array of characters containing the parameters for the command
+        * @param pcnt The nuimber of parameters passed to the command
+        * @param user the user issuing the command
+        * @param validated True if the command has passed all checks, e.g. it is recognised, has enough parameters, the user has permission to execute it, etc.
+        * @param original_line The entire original line as passed to the parser from the user
+        * @return 1 to block the command, 0 to allow
+        */
+       virtual int OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line);
+
+       /** Called after any command has been executed.
+        * This event occurs for all registered commands, wether they are registered in the core,
+        * or another module, but it will not occur for invalid commands (e.g. ones which do not
+        * exist within the command table). The result code returned by the command handler is
+        * provided.
+        * @param command The command being executed
+        * @param parameters An array of array of characters containing the parameters for the command
+        * @param pcnt The nuimber of parameters passed to the command
+        * @param user the user issuing the command
+        * @param result The return code given by the command handler, one of CMD_SUCCESS or CMD_FAILURE
+        * @param original_line The entire original line as passed to the parser from the user
+        */
+       virtual void OnPostCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, CmdResult result, const std::string &original_line);
+
+       /** Called to check if a user who is connecting can now be allowed to register
+        * If any modules return false for this function, the user is held in the waiting
+        * state until all modules return true. For example a module which implements ident
+        * lookups will continue to return false for a user until their ident lookup is completed.
+        * Note that the registration timeout for a user overrides these checks, if the registration
+        * timeout is reached, the user is disconnected even if modules report that the user is
+        * not ready to connect.
+        * @param user The user to check
+        * @return true to indicate readiness, false if otherwise
+        */
+       virtual bool OnCheckReady(userrec* user);
+
+       /** Called whenever a user is about to register their connection (e.g. before the user
+        * is sent the MOTD etc). Modules can use this method if they are performing a function
+        * which must be done before the actual connection is completed (e.g. ident lookups,
+        * dnsbl lookups, etc).
+        * Note that you should NOT delete the user record here by causing a disconnection!
+        * Use OnUserConnect for that instead.
+        * @param user The user registering
+        * @return 1 to indicate user quit, 0 to continue
+        */
+       virtual int OnUserRegister(userrec* user);
+
+       /** Called whenever a user joins a channel, to determine if invite checks should go ahead or not.
+        * This method will always be called for each join, wether or not the channel is actually +i, and
+        * determines the outcome of an if statement around the whole section of invite checking code.
+        * return 1 to explicitly allow the join to go ahead or 0 to ignore the event.
+        * @param user The user joining the channel
+        * @param chan The channel being joined
+        * @return 1 to explicitly allow the join, 0 to proceed as normal
+        */
+       virtual int OnCheckInvite(userrec* user, chanrec* chan);
+
+       /** Called whenever a user joins a channel, to determine if key checks should go ahead or not.
+        * This method will always be called for each join, wether or not the channel is actually +k, and
+        * determines the outcome of an if statement around the whole section of key checking code.
+        * if the user specified no key, the keygiven string will be a valid but empty value.
+        * return 1 to explicitly allow the join to go ahead or 0 to ignore the event.
+        * @param user The user joining the channel
+        * @param chan The channel being joined
+        * @return 1 to explicitly allow the join, 0 to proceed as normal
+        */
+       virtual int OnCheckKey(userrec* user, chanrec* chan, const std::string &keygiven);
+
+       /** Called whenever a user joins a channel, to determine if channel limit checks should go ahead or not.
+        * This method will always be called for each join, wether or not the channel is actually +l, and
+        * determines the outcome of an if statement around the whole section of channel limit checking code.
+        * return 1 to explicitly allow the join to go ahead or 0 to ignore the event.
+        * @param user The user joining the channel
+        * @param chan The channel being joined
+        * @return 1 to explicitly allow the join, 0 to proceed as normal
+        */
+       virtual int OnCheckLimit(userrec* user, chanrec* chan);
+
+       /** Called whenever a user joins a channel, to determine if banlist checks should go ahead or not.
+        * This method will always be called for each join, wether or not the user actually matches a channel ban, and
+        * determines the outcome of an if statement around the whole section of ban checking code.
+        * return 1 to explicitly allow the join to go ahead or 0 to ignore the event.
+        * @param user The user joining the channel
+        * @param chan The channel being joined
+        * @return 1 to explicitly allow the join, 0 to proceed as normal
+        */
+       virtual int OnCheckBan(userrec* user, chanrec* chan);
+
+       /** Called on all /STATS commands
+        * This method is triggered for all /STATS use, including stats symbols handled by the core.
+        * @param symbol the symbol provided to /STATS
+        * @param user the user issuing the /STATS command
+        * @param results A string_list to append results into. You should put all your results
+        * into this string_list, rather than displaying them directly, so that your handler will
+        * work when remote STATS queries are received.
+        * @return 1 to block the /STATS from being processed by the core, 0 to allow it
+        */
+       virtual int OnStats(char symbol, userrec* user, string_list &results);
+
+       /** Called whenever a change of a local users displayed host is attempted.
+        * Return 1 to deny the host change, or 0 to allow it.
+        * @param user The user whos host will be changed
+        * @param newhost The new hostname
+        * @return 1 to deny the host change, 0 to allow
+        */
+       virtual int OnChangeLocalUserHost(userrec* user, const std::string &newhost);
+
+       /** Called whenever a change of a local users GECOS (fullname field) is attempted.
+        * return 1 to deny the name change, or 0 to allow it.
+        * @param user The user whos GECOS will be changed
+        * @param newhost The new GECOS
+        * @return 1 to deny the GECOS change, 0 to allow
+        */
+       virtual int OnChangeLocalUserGECOS(userrec* user, const std::string &newhost); 
+
+       /** Called whenever a topic is changed by a local user.
+        * Return 1 to deny the topic change, or 0 to allow it.
+        * @param user The user changing the topic
+        * @param chan The channels who's topic is being changed
+        * @param topic The actual topic text
+        * @param 1 to block the topic change, 0 to allow
+        */
+       virtual int OnLocalTopicChange(userrec* user, chanrec* chan, const std::string &topic);
+
+       /** Called whenever a local topic has been changed.
+        * To block topic changes you must use OnLocalTopicChange instead.
+        * @param user The user changing the topic
+        * @param chan The channels who's topic is being changed
+        * @param topic The actual topic text
+        */
+       virtual void OnPostLocalTopicChange(userrec* user, chanrec* chan, const std::string &topic);
+
+       /** Called whenever an Event class is sent to all module by another module.
+        * Please see the documentation of Event::Send() for further information. The Event sent can
+        * always be assumed to be non-NULL, you should *always* check the value of Event::GetEventID()
+        * before doing anything to the event data, and you should *not* change the event data in any way!
+        * @param event The Event class being received
+        */
+       virtual void OnEvent(Event* event);
+
+       /** Called whenever a Request class is sent to your module by another module.
+        * Please see the documentation of Request::Send() for further information. The Request sent
+        * can always be assumed to be non-NULL, you should not change the request object or its data.
+        * Your method may return arbitary data in the char* result which the requesting module
+        * may be able to use for pre-determined purposes (e.g. the results of an SQL query, etc).
+        * @param request The Request class being received
+        */
+       virtual char* OnRequest(Request* request);
+
+       /** Called whenever an oper password is to be compared to what a user has input.
+        * The password field (from the config file) is in 'password' and is to be compared against
+        * 'input'. This method allows for encryption of oper passwords and much more besides.
+        * You should return a nonzero value if you want to allow the comparison or zero if you wish
+        * to do nothing.
+        * @param password The oper's password
+        * @param input The password entered
+        * @param tagnumber The tag number (from the configuration file) of this oper's tag
+        * @return 1 to match the passwords, 0 to do nothing. -1 to not match, and not continue.
+        */
+       virtual int OnOperCompare(const std::string &password, const std::string &input, int tagnumber);
+
+       /** Called whenever a user is given usermode +o, anywhere on the network.
+        * You cannot override this and prevent it from happening as it is already happened and
+        * such a task must be performed by another server. You can however bounce modes by sending
+        * servermodes out to reverse mode changes.
+        * @param user The user who is opering
+        */
+       virtual void OnGlobalOper(userrec* user);
+
+       /** Called after a user has fully connected and all modules have executed OnUserConnect
+        * This event is informational only. You should not change any user information in this
+        * event. To do so, use the OnUserConnect method to change the state of local users.
+        * This is called for both local and remote users.
+        * @param user The user who is connecting
+        */
+       virtual void OnPostConnect(userrec* user);
+
+       /** Called whenever a ban is added to a channel's list.
+        * Return a non-zero value to 'eat' the mode change and prevent the ban from being added.
+        * @param source The user adding the ban
+        * @param channel The channel the ban is being added to
+        * @param banmask The ban mask being added
+        * @return 1 to block the ban, 0 to continue as normal
+        */
+       virtual int OnAddBan(userrec* source, chanrec* channel,const std::string &banmask);
+
+       /** Called whenever a ban is removed from a channel's list.
+        * Return a non-zero value to 'eat' the mode change and prevent the ban from being removed.
+        * @param source The user deleting the ban
+        * @param channel The channel the ban is being deleted from
+        * @param banmask The ban mask being deleted
+        * @return 1 to block the unban, 0 to continue as normal
+        */
+       virtual int OnDelBan(userrec* source, chanrec* channel,const std::string &banmask);
+
+       /** Called immediately after any  connection is accepted. This is intended for raw socket
+        * processing (e.g. modules which wrap the tcp connection within another library) and provides
+        * no information relating to a user record as the connection has not been assigned yet.
+        * There are no return values from this call as all modules get an opportunity if required to
+        * process the connection.
+        * @param fd The file descriptor returned from accept()
+        * @param ip The IP address of the connecting user
+        * @param localport The local port number the user connected to
+        */
+       virtual void OnRawSocketAccept(int fd, const std::string &ip, int localport);
+
+       /** Called immediately before any write() operation on a user's socket in the core. Because
+        * this event is a low level event no user information is associated with it. It is intended
+        * for use by modules which may wrap connections within another API such as SSL for example.
+        * return a non-zero result if you have handled the write operation, in which case the core
+        * will not call write().
+        * @param fd The file descriptor of the socket
+        * @param buffer A char* buffer being written
+        * @param Number of characters to write
+        * @return Number of characters actually written or 0 if you didn't handle the operation
+        */
+       virtual int OnRawSocketWrite(int fd, const char* buffer, int count);
+
+       /** Called immediately before any socket is closed. When this event is called, shutdown()
+        * has not yet been called on the socket.
+        * @param fd The file descriptor of the socket prior to close()
+        */
+       virtual void OnRawSocketClose(int fd);
+
+       /** Called immediately upon connection of an outbound InspSocket which has been hooked
+        * by a module.
+        * @param fd The file descriptor of the socket immediately after connect()
+        */
+       virtual void OnRawSocketConnect(int fd);
+
+       /** Called immediately before any read() operation on a client socket in the core.
+        * This occurs AFTER the select() or poll() so there is always data waiting to be read
+        * when this event occurs.
+        * Your event should return 1 if it has handled the reading itself, which prevents the core
+        * just using read(). You should place any data read into buffer, up to but NOT GREATER THAN
+        * the value of count. The value of readresult must be identical to an actual result that might
+        * be returned from the read() system call, for example, number of bytes read upon success,
+        * 0 upon EOF or closed socket, and -1 for error. If your function returns a nonzero value,
+        * you MUST set readresult.
+        * @param fd The file descriptor of the socket
+        * @param buffer A char* buffer being read to
+        * @param count The size of the buffer
+        * @param readresult The amount of characters read, or 0
+        * @return nonzero if the event was handled, in which case readresult must be valid on exit
+        */
+       virtual int OnRawSocketRead(int fd, char* buffer, unsigned int count, int &readresult);
+
+       /** Called whenever a user sets away.
+        * This method has no parameter for the away message, as it is available in the
+        * user record as userrec::awaymsg.
+        * @param user The user setting away
+        */
+       virtual void OnSetAway(userrec* user);
+
+       /** Called when a user cancels their away state.
+        * @param user The user returning from away
+        */
+       virtual void OnCancelAway(userrec* user);
+
+       /** Called whenever a NAMES list is requested.
+        * You can produce the nameslist yourself, overriding the current list,
+        * and if you do you must return 1. If you do not handle the names list,
+        * return 0.
+        * @param The user requesting the NAMES list
+        * @param Ptr The channel the NAMES list is requested for
+        * @param userlist The user list for the channel (you may change this pointer.
+        * If you want to change the values, take a copy first, and change the copy, then
+        * point the pointer at your copy)
+        * @return 1 to prevent the user list being sent to the client, 0 to allow it
+        */
+       virtual int OnUserList(userrec* user, chanrec* Ptr, CUList* &userlist);
+
+       /** Called whenever a line of WHOIS output is sent to a user.
+        * You may change the numeric and the text of the output by changing
+        * the values numeric and text, but you cannot change the user the
+        * numeric is sent to. You may however change the user's userrec values.
+        * @param user The user the numeric is being sent to
+        * @param dest The user being WHOISed
+        * @param numeric The numeric of the line being sent
+        * @param text The text of the numeric, including any parameters
+        * @return nonzero to drop the line completely so that the user does not
+        * receive it, or zero to allow the line to be sent.
+        */
+       virtual int OnWhoisLine(userrec* user, userrec* dest, int &numeric, std::string &text);
+
+       /** Called at intervals for modules to garbage-collect any hashes etc.
+        * Certain data types such as hash_map 'leak' buckets, which must be
+        * tidied up and freed by copying into a new item every so often. This
+        * method is called when it is time to do that.
+        */
+       virtual void OnGarbageCollect();
+
+       /** Called whenever a user's write buffer has been completely sent.
+        * This is called when the user's write buffer is completely empty, and
+        * there are no more pending bytes to be written and no pending write events
+        * in the socket engine's queue. This may be used to refill the buffer with
+        * data which is being spooled in a controlled manner, e.g. LIST lines.
+        * @param user The user who's buffer is now empty.
+        */
+       virtual void OnBufferFlushed(userrec* user);
+};
+
+
+#define CONF_NOT_A_NUMBER      0x000010
+#define CONF_NOT_UNSIGNED      0x000080
+#define CONF_VALUE_NOT_FOUND   0x000100
+#define CONF_FILE_NOT_FOUND    0x000200
+
+
+/** Allows reading of values from configuration files
+ * This class allows a module to read from either the main configuration file (inspircd.conf) or from
+ * a module-specified configuration file. It may either be instantiated with one parameter or none.
+ * Constructing the class using one parameter allows you to specify a path to your own configuration
+ * file, otherwise, inspircd.conf is read.
+ */
+class CoreExport ConfigReader : public classbase
+{
+  protected:
+       InspIRCd* ServerInstance;
+       /** The contents of the configuration file
+        * This protected member should never be accessed by a module (and cannot be accessed unless the
+        * core is changed). It will contain a pointer to the configuration file data with unneeded data
+        * (such as comments) stripped from it.
+        */
+       ConfigDataHash* data;
+       /** Used to store errors
+        */
+       std::ostringstream* errorlog;
+       /** If we're using our own config data hash or not
+        */
+       bool privatehash;
+       /** True if an error occured reading the config file
+        */
+       bool readerror;
+       /** Error code
+        */
+       long error;
+       
+  public:
+       /** Default constructor.
+        * This constructor initialises the ConfigReader class to read the inspircd.conf file
+        * as specified when running ./configure.
+        */
+       ConfigReader(InspIRCd* Instance);
+       /** Overloaded constructor.
+        * This constructor initialises the ConfigReader class to read a user-specified config file
+        */
+       ConfigReader(InspIRCd* Instance, const std::string &filename);
+       /** Default destructor.
+        * This method destroys the ConfigReader class.
+        */
+       ~ConfigReader();
+
+       /** Retrieves a value from the config file.
+        * This method retrieves a value from the config file. Where multiple copies of the tag
+        * exist in the config file, index indicates which of the values to retrieve.
+        */
+       std::string ReadValue(const std::string &tag, const std::string &name, int index, bool allow_linefeeds = false);
+       /** Retrieves a value from the config file.
+        * This method retrieves a value from the config file. Where multiple copies of the tag
+        * exist in the config file, index indicates which of the values to retrieve. If the
+        * tag is not found the default value is returned instead.
+        */
+       std::string ReadValue(const std::string &tag, const std::string &name, const std::string &default_value, int index, bool allow_linefeeds = false);
+
+       /** Retrieves a boolean value from the config file.
+        * This method retrieves a boolean value from the config file. Where multiple copies of the tag
+        * exist in the config file, index indicates which of the values to retrieve. The values "1", "yes"
+        * and "true" in the config file count as true to ReadFlag, and any other value counts as false.
+        */
+       bool ReadFlag(const std::string &tag, const std::string &name, int index);
+       /** Retrieves a boolean value from the config file.
+        * This method retrieves a boolean value from the config file. Where multiple copies of the tag
+        * exist in the config file, index indicates which of the values to retrieve. The values "1", "yes"
+        * and "true" in the config file count as true to ReadFlag, and any other value counts as false.
+        * If the tag is not found, the default value is used instead.
+        */
+       bool ReadFlag(const std::string &tag, const std::string &name, const std::string &default_value, int index);
+
+       /** Retrieves an integer value from the config file.
+        * This method retrieves an integer value from the config file. Where multiple copies of the tag
+        * exist in the config file, index indicates which of the values to retrieve. Any invalid integer
+        * values in the tag will cause the objects error value to be set, and any call to GetError() will
+        * return CONF_INVALID_NUMBER to be returned. needs_unsigned is set if the number must be unsigned.
+        * If a signed number is placed into a tag which is specified unsigned, 0 will be returned and GetError()
+        * will return CONF_NOT_UNSIGNED
+        */
+       long ReadInteger(const std::string &tag, const std::string &name, int index, bool needs_unsigned);
+       /** Retrieves an integer value from the config file.
+        * This method retrieves an integer value from the config file. Where multiple copies of the tag
+        * exist in the config file, index indicates which of the values to retrieve. Any invalid integer
+        * values in the tag will cause the objects error value to be set, and any call to GetError() will
+        * return CONF_INVALID_NUMBER to be returned. needs_unsigned is set if the number must be unsigned.
+        * If a signed number is placed into a tag which is specified unsigned, 0 will be returned and GetError()
+        * will return CONF_NOT_UNSIGNED. If the tag is not found, the default value is used instead.
+        */
+       long ReadInteger(const std::string &tag, const std::string &name, const std::string &default_value, int index, bool needs_unsigned);
+
+       /** Returns the last error to occur.
+        * Valid errors can be found by looking in modules.h. Any nonzero value indicates an error condition.
+        * A call to GetError() resets the error flag back to 0.
+        */
+       long GetError();
+       /** Counts the number of times a given tag appears in the config file.
+        * This method counts the number of times a tag appears in a config file, for use where
+        * there are several tags of the same kind, e.g. with opers and connect types. It can be
+        * used with the index value of ConfigReader::ReadValue to loop through all copies of a
+        * multiple instance tag.
+        */
+       int Enumerate(const std::string &tag);
+       /** Returns true if a config file is valid.
+        * This method is partially implemented and will only return false if the config
+        * file does not exist or could not be opened.
+        */
+       bool Verify();
+       /** Dumps the list of errors in a config file to an output location. If bail is true,
+        * then the program will abort. If bail is false and user points to a valid user
+        * record, the error report will be spooled to the given user by means of NOTICE.
+        * if bool is false AND user is false, the error report will be spooled to all opers
+        * by means of a NOTICE to all opers.
+        */
+       void DumpErrors(bool bail,userrec* user);
+
+       /** Returns the number of items within a tag.
+        * For example if the tag was &lt;test tag="blah" data="foo"&gt; then this
+        * function would return 2. Spaces and newlines both qualify as valid seperators
+        * between values.
+        */
+       int EnumerateValues(const std::string &tag, int index);
+};
+
+
+
+/** Caches a text file into memory and can be used to retrieve lines from it.
+ * This class contains methods for read-only manipulation of a text file in memory.
+ * Either use the constructor type with one parameter to load a file into memory
+ * at construction, or use the LoadFile method to load a file.
+ */
+class CoreExport FileReader : public classbase
+{
+       InspIRCd* ServerInstance;
+       /** The file contents
+        */
+       file_cache fc;
+
+       /** Content size in bytes
+        */
+       unsigned long contentsize;
+
+       /** Calculate content size in bytes
+        */
+       void CalcSize();
+
+ public:
+       /** Default constructor.
+        * This method does not load any file into memory, you must use the LoadFile method
+        * after constructing the class this way.
+        */
+       FileReader(InspIRCd* Instance);
+
+       /** Secondary constructor.
+        * This method initialises the class with a file loaded into it ready for GetLine and
+        * and other methods to be called. If the file could not be loaded, FileReader::FileSize
+        * returns 0.
+        */
+       FileReader(InspIRCd* Instance, const std::string &filename);
+
+       /** Default destructor.
+        * This deletes the memory allocated to the file.
+        */
+       ~FileReader();
+
+       /** Used to load a file.
+        * This method loads a file into the class ready for GetLine and
+        * and other methods to be called. If the file could not be loaded, FileReader::FileSize
+        * returns 0.
+        */
+       void LoadFile(const std::string &filename);
+
+       /** Returns the whole content of the file as std::string
+        */
+       std::string Contents();
+
+       /** Returns the entire size of the file as std::string
+        */
+       unsigned long ContentSize();
+
+       /** Returns true if the file exists
+        * This function will return false if the file could not be opened.
+        */
+       bool Exists();
+       /** Retrieve one line from the file.
+        * This method retrieves one line from the text file. If an empty non-NULL string is returned,
+        * the index was out of bounds, or the line had no data on it.
+        */
+       std::string GetLine(int x);
+
+       /** Returns the size of the file in lines.
+        * This method returns the number of lines in the read file. If it is 0, no lines have been
+        * read into memory, either because the file is empty or it does not exist, or cannot be
+        * opened due to permission problems.
+        */
+       int FileSize();
+};
+
+
+/** Instantiates classes inherited from Module.
+ * This class creates a class inherited from type Module, using new. This is to allow for modules
+ * to create many different variants of Module, dependent on architecture, configuration, etc.
+ * In most cases, the simple class shown in the example module m_foobar.so will suffice for most
+ * modules.
+ */
+class CoreExport ModuleFactory : public classbase
+{
+ public:
+       /** The default constructor does nothing.
+        */
+       ModuleFactory() { }
+       /** The default destructor does nothing
+        */
+       virtual ~ModuleFactory() { }
+       /** Creates a new module.
+        * Your inherited class of ModuleFactory must return a pointer to your Module class
+        * using this method.
+        */
+       virtual Module * CreateModule(InspIRCd* Me) = 0;
+};
+
+/** A DLLFactory (designed to load shared objects) containing a ModuleFactory.
+ */
+typedef DLLFactory<ModuleFactory> ircd_module;
+
+/** A list of loaded Modules
+ */
+typedef std::vector<Module*> ModuleList;
+
+/** A list of loaded ModuleFactories
+ */
+typedef std::vector<ircd_module*> FactoryList;
+
+/** This definition is used as shorthand for the various classes
+ * and functions needed to make a module loadable by the OS.
+ * It defines the class factory and external init_module function.
+ */
+#define MODULE_INIT(y) \
+       class Factory : public ModuleFactory \
+       { \
+        public: \
+               virtual Module * CreateModule(InspIRCd* Me) \
+               { \
+                       return new y(Me); \
+               } \
+       }; \
+       extern "C" DllExport void * init_module(void) \
+       { \
+               return new Factory; \
+       }
+
+#endif
+
index b318fdc265bff0677767565284b8bcbcfd1e41c8..db8be55f88cf7babb10368c2e3acd01144b620fd 100644 (file)
@@ -1 +1,85 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __SNOMASKS_H__\r#define __SNOMASKS_H__\r\r#include <string>\r#include <vector>\r#include <map>\r#include "configreader.h"\r#include "inspircd.h"\r\r/** A list of snomasks which are valid, and their descriptive texts\r */\rtypedef std::map<char, std::string> SnoList;\r\r/** Snomask manager handles routing of SNOMASK (usermode +n) messages to opers.\r * Modules and the core can enable and disable snomask characters. If they do,\r * then sending snomasks using these characters becomes possible.\r */\rclass CoreExport SnomaskManager : public Extensible\r{\r private:\r     /** Creator/owner\r       */\r    InspIRCd* ServerInstance;\r      /** Currently active snomask list\r       */\r    SnoList SnoMasks;\r      /** Set up the default (core available) snomask chars\r   */\r    void SetupDefaults();\r public:\r /** Create a new SnomaskManager\r         */\r    SnomaskManager(InspIRCd* Instance);\r    /** Delete SnomaskManager\r       */\r    ~SnomaskManager();\r\r    /** Enable a snomask.\r   * @param letter The snomask letter to enable. Once enabled,\r    * server notices may be routed to users with this letter in\r    * their list, and users may add this letter to their list.\r     * @param description The descriptive text sent along with any\r  * server notices, at the start of the notice, e.g. "GLOBOPS".\r  * @return True if the snomask was enabled, false if it already\r         * exists.\r      */\r    bool EnableSnomask(char letter, const std::string &description);\r       /** Disable a snomask.\r  * @param letter The snomask letter to disable.\r         * @return True if the snomask was disabled, false if it didn't\r         * exist.\r       */\r    bool DisableSnomask(char letter);\r      /** Write to all users with a given snomask.\r    * @param letter The snomask letter to write to\r         * @param text The text to send to the users\r    */\r    void WriteToSnoMask(char letter, const std::string &text);\r     /** Write to all users with a given snomask.\r    * @param letter The snomask letter to write to\r         * @param text A format string containing text to send\r  * @param ... Format arguments\r  */\r    void WriteToSnoMask(char letter, const char* text, ...);\r       /** Check if a snomask is enabled.\r      * @param letter The snomask letter to check.\r   * @return True if the snomask has been enabled.\r        */\r    bool IsEnabled(char letter);\r};\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __SNOMASKS_H__
+#define __SNOMASKS_H__
+
+#include <string>
+#include <vector>
+#include <map>
+#include "configreader.h"
+#include "inspircd.h"
+
+/** A list of snomasks which are valid, and their descriptive texts
+ */
+typedef std::map<char, std::string> SnoList;
+
+/** Snomask manager handles routing of SNOMASK (usermode +n) messages to opers.
+ * Modules and the core can enable and disable snomask characters. If they do,
+ * then sending snomasks using these characters becomes possible.
+ */
+class CoreExport SnomaskManager : public Extensible
+{
+ private:
+       /** Creator/owner
+        */
+       InspIRCd* ServerInstance;
+       /** Currently active snomask list
+        */
+       SnoList SnoMasks;
+       /** Set up the default (core available) snomask chars
+        */
+       void SetupDefaults();
+ public:
+       /** Create a new SnomaskManager
+        */
+       SnomaskManager(InspIRCd* Instance);
+       /** Delete SnomaskManager
+        */
+       ~SnomaskManager();
+
+       /** Enable a snomask.
+        * @param letter The snomask letter to enable. Once enabled,
+        * server notices may be routed to users with this letter in
+        * their list, and users may add this letter to their list.
+        * @param description The descriptive text sent along with any
+        * server notices, at the start of the notice, e.g. "GLOBOPS".
+        * @return True if the snomask was enabled, false if it already
+        * exists.
+        */
+       bool EnableSnomask(char letter, const std::string &description);
+       /** Disable a snomask.
+        * @param letter The snomask letter to disable.
+        * @return True if the snomask was disabled, false if it didn't
+        * exist.
+        */
+       bool DisableSnomask(char letter);
+       /** Write to all users with a given snomask.
+        * @param letter The snomask letter to write to
+        * @param text The text to send to the users
+        */
+       void WriteToSnoMask(char letter, const std::string &text);
+       /** Write to all users with a given snomask.
+        * @param letter The snomask letter to write to
+        * @param text A format string containing text to send
+        * @param ... Format arguments
+        */
+       void WriteToSnoMask(char letter, const char* text, ...);
+       /** Check if a snomask is enabled.
+        * @param letter The snomask letter to check.
+        * @return True if the snomask has been enabled.
+        */
+       bool IsEnabled(char letter);
+};
+
+#endif
index 458cbe69045dd3f06ad507f9fbe1dd7cea3a0d07..57725b95fedc0edcc4168c73c3126e18b05b9c90 100644 (file)
@@ -1 +1,225 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef INSPIRCD_SOCKET_H\r#define INSPIRCD_SOCKET_H\r\r#ifndef WIN32\r\r#include <arpa/inet.h>\r#include <sys/time.h>\r#include <sys/resource.h>\r#include <sys/types.h>\r#include <sys/socket.h>\r#include <sys/stat.h>\r#include <netinet/in.h>\r#include <unistd.h>\r#include <fcntl.h>\r#include <netdb.h>\r\r#else\r\r#include "inspircd_win32wrapper.h"\r\r#endif\r\r#include <errno.h>\r#include "inspircd_config.h"\r#include "socketengine.h"\r\r/* Accept Define */\r#ifdef CONFIG_USE_IOCP\r/* IOCP wrapper for accept() */\r#define _accept(s, addr, addrlen) __accept_socket(s, addr, addrlen, m_acceptEvent)\r/* IOCP wrapper for getsockname() */\r#define _getsockname(fd, sockptr, socklen) __getsockname(fd, sockptr, socklen, m_acceptEvent)\r/* IOCP wrapper for recvfrom() */\r#define _recvfrom(s, buf, len, flags, from, fromlen) __recvfrom(s, buf, len, flags, from, fromlen, ((IOCPEngine*)ServerInstance->SE)->udp_ov)\r#else\r/* No wrapper for recvfrom() */\r#define _recvfrom recvfrom\r/* No wrapper for accept() */\r#define _accept accept\r/* No wrapper for getsockname() */\r#define _getsockname getsockname\r#endif\r\r/* Contains irc-specific definitions */\rnamespace irc\r{\r       /** This namespace contains various protocol-independent helper classes.\r        * It also contains some types which are often used by the core and modules\r     * in place of inet_* functions and types.\r      */\r    namespace sockets\r      {\r\r     /* macros to the relevant system address description structs */\r#ifdef IPV6\r            /** insp_sockaddr for ipv6\r              */\r            typedef struct sockaddr_in6 insp_sockaddr;\r             /** insp_inaddr for ipv6\r                */\r            typedef struct in6_addr     insp_inaddr;\r#define AF_FAMILY AF_INET6\r#define PF_PROTOCOL PF_INET6\r\r#else\r                /** insp_sockaddr for ipv4\r              */\r            typedef struct sockaddr_in  insp_sockaddr;\r             /** insp_inaddr for ipv4\r                */\r            typedef struct in_addr      insp_inaddr;\r#define AF_FAMILY AF_INET\r#define PF_PROTOCOL PF_INET\r\r#endif\r         /** Match raw binary data using CIDR rules.\r             * \r             * This function will use binary comparison to compare the\r              * two bit sequences, address and mask, up to mask_bits\r                 * bits in size. If they match, it will return true.\r            * @param address The whole address, of 4 or 16 bytes in length\r                 * @param mask The mask, from 1 to 16 bytes in length, anything\r                 * from 1 to 128 bits of which is significant\r           * @param mask_Bits How many bits of the mask parameter are significant\r                 * for this comparison.\r                 * @returns True if the first mask_bits of address matches the first\r            * mask_bits of mask.\r           */\r            CoreExport bool MatchCIDRBits(unsigned char* address, unsigned char* mask, unsigned int mask_bits);\r\r           /** Match CIDR, without matching username/nickname parts.\r               *\r              * This function will compare a human-readable address against a human-\r                 * readable CIDR mask, for example 1.2.3.4 against 1.2.0.0/16. This\r             * method supports both IPV4 and IPV6 addresses.\r                * @param address The human readable address, e.g. 1.2.3.4\r              * @param cidr_mask The human readable mask, e.g. 1.2.0.0/16\r            * @return True if the mask matches the address\r                 */\r            CoreExport bool MatchCIDR(const char* address, const char* cidr_mask);\r\r                /** Match CIDR, including an optional username/nickname part.\r           *\r              * This function will compare a human-readable address (plus\r            * optional username and nickname) against a human-readable\r             * CIDR mask, for example joe!bloggs\@1.2.3.4 against\r           * *!bloggs\@1.2.0.0/16. This method supports both IPV4 and\r             * IPV6 addresses.\r              * @param address The human readable address, e.g. fred\@1.2.3.4\r                * @param cidr_mask The human readable mask, e.g. *\@1.2.0.0/16\r                 * @return True if the mask matches the address\r                 */\r            CoreExport bool MatchCIDR(const char* address, const char* cidr_mask, bool match_with_username);\r\r              /** Convert an insp_inaddr into human readable form.\r            * \r             * @param n An insp_inaddr (IP address) structure\r               * @return A human-readable address. IPV6 addresses\r             * will be shortened to remove fields which are 0.\r              */\r            CoreExport const char* insp_ntoa(insp_inaddr n);\r\r              /** Convert a human-readable address into an insp_inaddr.\r               * \r             * @param a A human-readable address\r            * @param n An insp_inaddr struct which the result\r              * will be copied into on success.\r              * @return This method will return a negative value if address\r          * does not contain a valid address family. 0 if the address is\r                 * does not contain a valid string representing a valid network\r                 * address. A positive value is returned if the network address\r                 * was successfully converted.\r\r                 * or any other number upon failure.\r            */\r            CoreExport int insp_aton(const char* a, insp_inaddr* n);\r\r              /** Make a socket file descriptor a blocking socket\r             * @param s A valid file descriptor\r             */\r            CoreExport void Blocking(int s);\r\r              /** Make a socket file descriptor into a nonblocking socket\r             * @param s A valid file descriptor\r             */\r            CoreExport void NonBlocking(int s);\r\r           /** Create a new valid file descriptor using socket()\r           * @return On return this function will return a value >= 0 for success,\r                * or a negative value upon failure (negative values are invalid file\r           * descriptors)\r                 */\r            CoreExport int OpenTCPSocket(char* addr, int socktype = SOCK_STREAM);\r  }\r}\r\r/** This class handles incoming connections on client ports.\r * It will create a new userrec for every valid connection\r * and assign it a file descriptor.\r */\rclass CoreExport ListenSocket : public EventHandler\r{\r protected:\r /** The creator/owner of this object\r    */\r    InspIRCd* ServerInstance;\r      /** Socket description (shown in stats p) */\r   std::string desc;\r      /** Socket address family */\r   int family;\r    /** Address socket is bound to */\r      std::string bind_addr;\r /** Port socket is bound to */\r int bind_port;\r public:\r        /** Create a new listening socket\r       */\r    ListenSocket(InspIRCd* Instance, int port, char* addr);\r        /** Handle an I/O event\r         */\r    void HandleEvent(EventType et, int errornum = 0);\r      /** Close the socket\r    */\r    ~ListenSocket();\r       /** Set descriptive text\r        */\r    void SetDescription(const std::string &description)\r    {\r              desc = description;\r    }\r      /** Get description for socket\r  */\r    const std::string& GetDescription()\r    {\r              return desc;\r   }\r      /** Get port number for socket\r  */\r    int GetPort()\r  {\r              return bind_port;\r      }\r      /** Get IP address socket is bound to\r   */\r    std::string &GetIP()\r   {\r              return bind_addr;\r      }\r};\r\r#endif\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef INSPIRCD_SOCKET_H
+#define INSPIRCD_SOCKET_H
+
+#ifndef WIN32
+
+#include <arpa/inet.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <netdb.h>
+
+#else
+
+#include "inspircd_win32wrapper.h"
+
+#endif
+
+#include <errno.h>
+#include "inspircd_config.h"
+#include "socketengine.h"
+
+/* Accept Define */
+#ifdef CONFIG_USE_IOCP
+/* IOCP wrapper for accept() */
+#define _accept(s, addr, addrlen) __accept_socket(s, addr, addrlen, m_acceptEvent)
+/* IOCP wrapper for getsockname() */
+#define _getsockname(fd, sockptr, socklen) __getsockname(fd, sockptr, socklen, m_acceptEvent)
+/* IOCP wrapper for recvfrom() */
+#define _recvfrom(s, buf, len, flags, from, fromlen) __recvfrom(s, buf, len, flags, from, fromlen, ((IOCPEngine*)ServerInstance->SE)->udp_ov)
+#else
+/* No wrapper for recvfrom() */
+#define _recvfrom recvfrom
+/* No wrapper for accept() */
+#define _accept accept
+/* No wrapper for getsockname() */
+#define _getsockname getsockname
+#endif
+
+/* Contains irc-specific definitions */
+namespace irc
+{
+       /** This namespace contains various protocol-independent helper classes.
+        * It also contains some types which are often used by the core and modules
+        * in place of inet_* functions and types.
+        */
+       namespace sockets
+       {
+
+       /* macros to the relevant system address description structs */
+#ifdef IPV6
+               /** insp_sockaddr for ipv6
+                */
+               typedef struct sockaddr_in6 insp_sockaddr;
+               /** insp_inaddr for ipv6
+                */
+               typedef struct in6_addr     insp_inaddr;
+#define AF_FAMILY AF_INET6
+#define PF_PROTOCOL PF_INET6
+
+#else
+               /** insp_sockaddr for ipv4
+                */
+               typedef struct sockaddr_in  insp_sockaddr;
+               /** insp_inaddr for ipv4
+                */
+               typedef struct in_addr      insp_inaddr;
+#define AF_FAMILY AF_INET
+#define PF_PROTOCOL PF_INET
+
+#endif
+               /** Match raw binary data using CIDR rules.
+                * 
+                * This function will use binary comparison to compare the
+                * two bit sequences, address and mask, up to mask_bits
+                * bits in size. If they match, it will return true.
+                * @param address The whole address, of 4 or 16 bytes in length
+                * @param mask The mask, from 1 to 16 bytes in length, anything
+                * from 1 to 128 bits of which is significant
+                * @param mask_Bits How many bits of the mask parameter are significant
+                * for this comparison.
+                * @returns True if the first mask_bits of address matches the first
+                * mask_bits of mask.
+                */
+               CoreExport bool MatchCIDRBits(unsigned char* address, unsigned char* mask, unsigned int mask_bits);
+
+               /** Match CIDR, without matching username/nickname parts.
+                *
+                * This function will compare a human-readable address against a human-
+                * readable CIDR mask, for example 1.2.3.4 against 1.2.0.0/16. This
+                * method supports both IPV4 and IPV6 addresses.
+                * @param address The human readable address, e.g. 1.2.3.4
+                * @param cidr_mask The human readable mask, e.g. 1.2.0.0/16
+                * @return True if the mask matches the address
+                */
+               CoreExport bool MatchCIDR(const char* address, const char* cidr_mask);
+
+               /** Match CIDR, including an optional username/nickname part.
+                *
+                * This function will compare a human-readable address (plus
+                * optional username and nickname) against a human-readable
+                * CIDR mask, for example joe!bloggs\@1.2.3.4 against
+                * *!bloggs\@1.2.0.0/16. This method supports both IPV4 and
+                * IPV6 addresses.
+                * @param address The human readable address, e.g. fred\@1.2.3.4
+                * @param cidr_mask The human readable mask, e.g. *\@1.2.0.0/16
+                * @return True if the mask matches the address
+                */
+               CoreExport bool MatchCIDR(const char* address, const char* cidr_mask, bool match_with_username);
+
+               /** Convert an insp_inaddr into human readable form.
+                * 
+                * @param n An insp_inaddr (IP address) structure
+                * @return A human-readable address. IPV6 addresses
+                * will be shortened to remove fields which are 0.
+                */
+               CoreExport const char* insp_ntoa(insp_inaddr n);
+
+               /** Convert a human-readable address into an insp_inaddr.
+                * 
+                * @param a A human-readable address
+                * @param n An insp_inaddr struct which the result
+                * will be copied into on success.
+                * @return This method will return a negative value if address
+                * does not contain a valid address family. 0 if the address is
+                * does not contain a valid string representing a valid network
+                * address. A positive value is returned if the network address
+                * was successfully converted.
+
+                * or any other number upon failure.
+                */
+               CoreExport int insp_aton(const char* a, insp_inaddr* n);
+
+               /** Make a socket file descriptor a blocking socket
+                * @param s A valid file descriptor
+                */
+               CoreExport void Blocking(int s);
+
+               /** Make a socket file descriptor into a nonblocking socket
+                * @param s A valid file descriptor
+                */
+               CoreExport void NonBlocking(int s);
+
+               /** Create a new valid file descriptor using socket()
+                * @return On return this function will return a value >= 0 for success,
+                * or a negative value upon failure (negative values are invalid file
+                * descriptors)
+                */
+               CoreExport int OpenTCPSocket(char* addr, int socktype = SOCK_STREAM);
+       }
+}
+
+/** This class handles incoming connections on client ports.
+ * It will create a new userrec for every valid connection
+ * and assign it a file descriptor.
+ */
+class CoreExport ListenSocket : public EventHandler
+{
+ protected:
+       /** The creator/owner of this object
+        */
+       InspIRCd* ServerInstance;
+       /** Socket description (shown in stats p) */
+       std::string desc;
+       /** Socket address family */
+       int family;
+       /** Address socket is bound to */
+       std::string bind_addr;
+       /** Port socket is bound to */
+       int bind_port;
+ public:
+       /** Create a new listening socket
+        */
+       ListenSocket(InspIRCd* Instance, int port, char* addr);
+       /** Handle an I/O event
+        */
+       void HandleEvent(EventType et, int errornum = 0);
+       /** Close the socket
+        */
+       ~ListenSocket();
+       /** Set descriptive text
+        */
+       void SetDescription(const std::string &description)
+       {
+               desc = description;
+       }
+       /** Get description for socket
+        */
+       const std::string& GetDescription()
+       {
+               return desc;
+       }
+       /** Get port number for socket
+        */
+       int GetPort()
+       {
+               return bind_port;
+       }
+       /** Get IP address socket is bound to
+        */
+       std::string &GetIP()
+       {
+               return bind_addr;
+       }
+};
+
+#endif
+
index e34aa3941dd7d06c965f4a6a0b406393798cc68e..ce701beff4a14ac3f510737ecc42bc19c2467987 100644 (file)
@@ -1 +1,296 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __SOCKETENGINE__\r#define __SOCKETENGINE__\r\r#include <vector>\r#include <string>\r#include <map>\r#include "inspircd_config.h"\r#include "base.h"\r\r/** Types of event an EventHandler may receive.\r * EVENT_READ is a readable file descriptor,\r * and EVENT_WRITE is a writeable file descriptor.\r * EVENT_ERROR can always occur, and indicates\r * a write error or read error on the socket,\r * e.g. EOF condition or broken pipe.\r */\renum EventType\r{\r     /** Read event */\r      EVENT_READ      =       0,\r     /** Write event */\r     EVENT_WRITE     =       1,\r     /** Error event */\r     EVENT_ERROR     =       2\r};\r\rclass InspIRCd;\r\r/** This class is a basic I/O handler class.\r * Any object which wishes to receive basic I/O events\r * from the socketengine must derive from this class and\r * implement the HandleEvent() method. The derived class\r * must then be added to SocketEngine using the method\r * SocketEngine::AddFd(), after which point the derived\r * class will receive events to its HandleEvent() method.\r * The derived class should also implement one of Readable()\r * and Writeable(). In the current implementation, only\r * Readable() is used. If this returns true, the socketengine\r * inserts a readable socket. If it is false, the socketengine\r * inserts a writeable socket. The derived class should never\r * change the value this function returns without first\r * deleting the socket from the socket engine. The only\r * requirement beyond this for an event handler is that it\r * must have a file descriptor. What this file descriptor\r * is actually attached to is completely up to you.\r */\rclass CoreExport EventHandler : public Extensible\r{\r protected:\r     /** File descriptor.\r    * All events which can be handled\r      * must have a file descriptor.\r         * This allows you to add events for\r    * sockets, fifo's, pipes, and various\r  * other forms of IPC.\r  */\r    int fd;\r public:\r       /** Get the current file descriptor\r     * @return The file descriptor of this handler\r  */\r    int GetFd();\r\r  /** Set a new file desciptor\r    * @param FD The new file descriptor. Do not\r    * call this method without first deleting the\r  * object from the SocketEngine if you have\r     * added it to a SocketEngine instance.\r         */\r    void SetFd(int FD);\r\r   /** Constructor\r         */\r    EventHandler() {}\r\r     /** Destructor\r  */\r    virtual ~EventHandler() {}\r\r    /** Override this function to indicate readability.\r     * @return This should return true if the function\r      * wishes to receive EVENT_READ events. Do not change\r   * what this function returns while the event handler\r   * is still added to a SocketEngine instance!\r   * If this function is unimplemented, the base class\r    * will return true.\r    *\r      * NOTE: You cannot set both Readable() and\r     * Writeable() to true. If you wish to receive\r  * a write event for your object, you must call\r         * SocketEngine::WantWrite() instead. This will\r         * trigger your objects next EVENT_WRITE type event.\r    */\r    virtual bool Readable();\r\r      /** Override this function to indicate writeability.\r    * @return This should return true if the function\r      * wishes to receive EVENT_WRITE events. Do not change\r  * what this function returns while the event handler\r   * is still added to a SocketEngine instance!\r   * If this function is unimplemented, the base class\r    * will return false.\r   *\r      * NOTE: You cannot set both Readable() and\r     * Writeable() to true. If you wish to receive\r  * a write event for your object, you must call\r         * SocketEngine::WantWrite() instead. This will\r         * trigger your objects next EVENT_WRITE type event.\r    */\r    virtual bool Writeable();\r\r     /** Process an I/O event.\r       * You MUST implement this function in your derived\r     * class, and it will be called whenever read or write\r  * events are received, depending on what your functions\r        * Readable() and Writeable() returns and wether you\r    * previously made a call to SocketEngine::WantWrite().\r         * @param et either one of EVENT_READ for read events,\r  * and EVENT_WRITE for write events.\r    */\r    virtual void HandleEvent(EventType et, int errornum = 0) = 0;\r\r#ifdef WINDOWS\r\r /** "Fake" file descriptor. This is windows-specific.\r   */\r    int m_internalFd;\r\r     /** Pointer to read event. We delete this so the buffer can't be used\r   * after the socket is deleted, and so it doesn't leak memory\r   */\r    void* m_readEvent;\r     /** Pointer to a write event.\r   */\r    void* m_writeEvent;\r    /** Pointer to an accept event.\r         */\r    void* m_acceptEvent;\r\r#endif\r};\r\r/** Provides basic file-descriptor-based I/O support.\r * The actual socketengine class presents the\r * same interface on all operating systems, but\r * its private members and internal behaviour\r * should be treated as blackboxed, and vary\r * from system to system and upon the config\r * settings chosen by the server admin. The current\r * version supports select, epoll and kqueue.\r * The configure script will enable a socket engine\r * based upon what OS is detected, and will derive\r * a class from SocketEngine based upon what it finds.\r * The derived classes file will also implement a\r * classfactory, SocketEngineFactory, which will\r * create a derived instance of SocketEngine using\r * polymorphism so that the core and modules do not\r * have to be aware of which SocketEngine derived\r * class they are using.\r */\rclass CoreExport SocketEngine : public Extensible\r{\rprotected:\r   /** Owner/Creator\r       */\r    InspIRCd* ServerInstance;\r      /** Handle to socket engine, where needed.\r      */\r    int EngineHandle;\r      /** Current number of descriptors in the engine\r         */\r    int CurrentSetSize;\r    /** Reference table, contains all current handlers\r      */\r    EventHandler* ref[MAX_DESCRIPTORS];\rpublic:\r\r   /** Constructor.\r        * The constructor transparently initializes\r    * the socket engine which the ircd is using.\r   * Please note that if there is a catastrophic\r  * failure (for example, you try and enable\r     * epoll on a 2.4 linux kernel) then this\r       * function may bail back to the shell.\r         * @param Instance The creator/owner of this object\r     */\r    SocketEngine(InspIRCd* Instance);\r\r     /** Destructor.\r         * The destructor transparently tidies up\r       * any resources used by the socket engine.\r     */\r    virtual ~SocketEngine();\r\r      /** Add an EventHandler object to the engine.\r   * Use AddFd to add a file descriptor to the\r    * engine and have the socket engine monitor\r    * it. You must provide an object derived from\r  * EventHandler which implements HandleEvent()\r  * and optionally Readable() and Writeable().\r   * @param eh An event handling object to add\r    */\r    virtual bool AddFd(EventHandler* eh);\r\r /** If you call this function and pass it an\r    * event handler, that event handler will\r       * receive the next available write event,\r      * even if the socket is a readable socket only.\r        * Developers should avoid constantly keeping\r   * an eventhandler in the writeable state,\r      * as this will consume large amounts of\r        * CPU time.\r    * @param eh An event handler which wants to\r    * receive the next writeability event.\r         */\r    virtual void WantWrite(EventHandler* eh);\r\r     /** Returns the maximum number of file descriptors\r      * you may store in the socket engine at any one time.\r  * @return The maximum fd value\r         */\r    virtual int GetMaxFds();\r\r      /** Returns the number of file descriptor slots\r         * which are available for storing fds.\r         * @return The number of remaining fd's\r         */\r    virtual int GetRemainingFds();\r\r        /** Delete an event handler from the engine.\r    * This function call deletes an EventHandler\r   * from the engine, returning true if it succeeded\r      * and false if it failed. This does not free the\r       * EventHandler pointer using delete, if this is\r        * required you must do this yourself.\r  * Note on forcing deletes. DO NOT DO THIS! This is\r     * extremely dangerous and will most likely render the\r  * socketengine dead. This was added only for handling\r  * very rare cases where broken 3rd party libs destroys\r         * the OS socket beyond our control. If you can't explain\r       * in minute details why forcing is absolutely necessary\r        * then you don't need it. That was a NO!\r       * @param eh The event handler object to remove\r         * @param force *DANGEROUS* See method description!\r     * @return True if the event handler was removed\r        */\r    virtual bool DelFd(EventHandler* eh, bool force = false);\r\r     /** Returns true if a file descriptor exists in\r         * the socket engine's list.\r    * @param fd The event handler to look for\r      * @return True if this fd has an event handler\r         */\r    virtual bool HasFd(int fd);\r\r   /** Returns the EventHandler attached to a specific fd.\r         * If the fd isnt in the socketengine, returns NULL.\r    * @param fd The event handler to look for\r      * @return A pointer to the event handler, or NULL\r      */\r    virtual EventHandler* GetRef(int fd);\r\r /** Waits for events and dispatches them to handlers.\r   * Please note that this doesnt wait long, only\r         * a couple of milliseconds. It returns the number of\r   * events which occured during this call.\r       * This method will dispatch events to their handlers\r   * by calling their EventHandler::HandleEvent()\r         * methods with the neccessary EventType value.\r         * @return The number of events which have occured.\r     */\r    virtual int DispatchEvents();\r\r /** Returns the socket engines name.\r    * This returns the name of the engine for use\r  * in /VERSION responses.\r       * @return The socket engine name\r       */\r    virtual std::string GetName();\r};\r\r#endif\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __SOCKETENGINE__
+#define __SOCKETENGINE__
+
+#include <vector>
+#include <string>
+#include <map>
+#include "inspircd_config.h"
+#include "base.h"
+
+/** Types of event an EventHandler may receive.
+ * EVENT_READ is a readable file descriptor,
+ * and EVENT_WRITE is a writeable file descriptor.
+ * EVENT_ERROR can always occur, and indicates
+ * a write error or read error on the socket,
+ * e.g. EOF condition or broken pipe.
+ */
+enum EventType
+{
+       /** Read event */
+       EVENT_READ      =       0,
+       /** Write event */
+       EVENT_WRITE     =       1,
+       /** Error event */
+       EVENT_ERROR     =       2
+};
+
+class InspIRCd;
+
+/** This class is a basic I/O handler class.
+ * Any object which wishes to receive basic I/O events
+ * from the socketengine must derive from this class and
+ * implement the HandleEvent() method. The derived class
+ * must then be added to SocketEngine using the method
+ * SocketEngine::AddFd(), after which point the derived
+ * class will receive events to its HandleEvent() method.
+ * The derived class should also implement one of Readable()
+ * and Writeable(). In the current implementation, only
+ * Readable() is used. If this returns true, the socketengine
+ * inserts a readable socket. If it is false, the socketengine
+ * inserts a writeable socket. The derived class should never
+ * change the value this function returns without first
+ * deleting the socket from the socket engine. The only
+ * requirement beyond this for an event handler is that it
+ * must have a file descriptor. What this file descriptor
+ * is actually attached to is completely up to you.
+ */
+class CoreExport EventHandler : public Extensible
+{
+ protected:
+       /** File descriptor.
+        * All events which can be handled
+        * must have a file descriptor.
+        * This allows you to add events for
+        * sockets, fifo's, pipes, and various
+        * other forms of IPC.
+        */
+       int fd;
+ public:
+       /** Get the current file descriptor
+        * @return The file descriptor of this handler
+        */
+       int GetFd();
+
+       /** Set a new file desciptor
+        * @param FD The new file descriptor. Do not
+        * call this method without first deleting the
+        * object from the SocketEngine if you have
+        * added it to a SocketEngine instance.
+        */
+       void SetFd(int FD);
+
+       /** Constructor
+        */
+       EventHandler() {}
+
+       /** Destructor
+        */
+       virtual ~EventHandler() {}
+
+       /** Override this function to indicate readability.
+        * @return This should return true if the function
+        * wishes to receive EVENT_READ events. Do not change
+        * what this function returns while the event handler
+        * is still added to a SocketEngine instance!
+        * If this function is unimplemented, the base class
+        * will return true.
+        *
+        * NOTE: You cannot set both Readable() and
+        * Writeable() to true. If you wish to receive
+        * a write event for your object, you must call
+        * SocketEngine::WantWrite() instead. This will
+        * trigger your objects next EVENT_WRITE type event.
+        */
+       virtual bool Readable();
+
+       /** Override this function to indicate writeability.
+        * @return This should return true if the function
+        * wishes to receive EVENT_WRITE events. Do not change
+        * what this function returns while the event handler
+        * is still added to a SocketEngine instance!
+        * If this function is unimplemented, the base class
+        * will return false.
+        *
+        * NOTE: You cannot set both Readable() and
+        * Writeable() to true. If you wish to receive
+        * a write event for your object, you must call
+        * SocketEngine::WantWrite() instead. This will
+        * trigger your objects next EVENT_WRITE type event.
+        */
+       virtual bool Writeable();
+
+       /** Process an I/O event.
+        * You MUST implement this function in your derived
+        * class, and it will be called whenever read or write
+        * events are received, depending on what your functions
+        * Readable() and Writeable() returns and wether you
+        * previously made a call to SocketEngine::WantWrite().
+        * @param et either one of EVENT_READ for read events,
+        * and EVENT_WRITE for write events.
+        */
+       virtual void HandleEvent(EventType et, int errornum = 0) = 0;
+
+#ifdef WINDOWS
+
+       /** "Fake" file descriptor. This is windows-specific.
+        */
+       int m_internalFd;
+
+       /** Pointer to read event. We delete this so the buffer can't be used
+        * after the socket is deleted, and so it doesn't leak memory
+        */
+       void* m_readEvent;
+       /** Pointer to a write event.
+        */
+       void* m_writeEvent;
+       /** Pointer to an accept event.
+        */
+       void* m_acceptEvent;
+
+#endif
+};
+
+/** Provides basic file-descriptor-based I/O support.
+ * The actual socketengine class presents the
+ * same interface on all operating systems, but
+ * its private members and internal behaviour
+ * should be treated as blackboxed, and vary
+ * from system to system and upon the config
+ * settings chosen by the server admin. The current
+ * version supports select, epoll and kqueue.
+ * The configure script will enable a socket engine
+ * based upon what OS is detected, and will derive
+ * a class from SocketEngine based upon what it finds.
+ * The derived classes file will also implement a
+ * classfactory, SocketEngineFactory, which will
+ * create a derived instance of SocketEngine using
+ * polymorphism so that the core and modules do not
+ * have to be aware of which SocketEngine derived
+ * class they are using.
+ */
+class CoreExport SocketEngine : public Extensible
+{
+protected:
+       /** Owner/Creator
+        */
+       InspIRCd* ServerInstance;
+       /** Handle to socket engine, where needed.
+        */
+       int EngineHandle;
+       /** Current number of descriptors in the engine
+        */
+       int CurrentSetSize;
+       /** Reference table, contains all current handlers
+        */
+       EventHandler* ref[MAX_DESCRIPTORS];
+public:
+
+       /** Constructor.
+        * The constructor transparently initializes
+        * the socket engine which the ircd is using.
+        * Please note that if there is a catastrophic
+        * failure (for example, you try and enable
+        * epoll on a 2.4 linux kernel) then this
+        * function may bail back to the shell.
+        * @param Instance The creator/owner of this object
+        */
+       SocketEngine(InspIRCd* Instance);
+
+       /** Destructor.
+        * The destructor transparently tidies up
+        * any resources used by the socket engine.
+        */
+       virtual ~SocketEngine();
+
+       /** Add an EventHandler object to the engine.
+        * Use AddFd to add a file descriptor to the
+        * engine and have the socket engine monitor
+        * it. You must provide an object derived from
+        * EventHandler which implements HandleEvent()
+        * and optionally Readable() and Writeable().
+        * @param eh An event handling object to add
+        */
+       virtual bool AddFd(EventHandler* eh);
+
+       /** If you call this function and pass it an
+        * event handler, that event handler will
+        * receive the next available write event,
+        * even if the socket is a readable socket only.
+        * Developers should avoid constantly keeping
+        * an eventhandler in the writeable state,
+        * as this will consume large amounts of
+        * CPU time.
+        * @param eh An event handler which wants to
+        * receive the next writeability event.
+        */
+       virtual void WantWrite(EventHandler* eh);
+
+       /** Returns the maximum number of file descriptors
+        * you may store in the socket engine at any one time.
+        * @return The maximum fd value
+        */
+       virtual int GetMaxFds();
+
+       /** Returns the number of file descriptor slots
+        * which are available for storing fds.
+        * @return The number of remaining fd's
+        */
+       virtual int GetRemainingFds();
+
+       /** Delete an event handler from the engine.
+        * This function call deletes an EventHandler
+        * from the engine, returning true if it succeeded
+        * and false if it failed. This does not free the
+        * EventHandler pointer using delete, if this is
+        * required you must do this yourself.
+        * Note on forcing deletes. DO NOT DO THIS! This is
+        * extremely dangerous and will most likely render the
+        * socketengine dead. This was added only for handling
+        * very rare cases where broken 3rd party libs destroys
+        * the OS socket beyond our control. If you can't explain
+        * in minute details why forcing is absolutely necessary
+        * then you don't need it. That was a NO!
+        * @param eh The event handler object to remove
+        * @param force *DANGEROUS* See method description!
+        * @return True if the event handler was removed
+        */
+       virtual bool DelFd(EventHandler* eh, bool force = false);
+
+       /** Returns true if a file descriptor exists in
+        * the socket engine's list.
+        * @param fd The event handler to look for
+        * @return True if this fd has an event handler
+        */
+       virtual bool HasFd(int fd);
+
+       /** Returns the EventHandler attached to a specific fd.
+        * If the fd isnt in the socketengine, returns NULL.
+        * @param fd The event handler to look for
+        * @return A pointer to the event handler, or NULL
+        */
+       virtual EventHandler* GetRef(int fd);
+
+       /** Waits for events and dispatches them to handlers.
+        * Please note that this doesnt wait long, only
+        * a couple of milliseconds. It returns the number of
+        * events which occured during this call.
+        * This method will dispatch events to their handlers
+        * by calling their EventHandler::HandleEvent()
+        * methods with the neccessary EventType value.
+        * @return The number of events which have occured.
+        */
+       virtual int DispatchEvents();
+
+       /** Returns the socket engines name.
+        * This returns the name of the engine for use
+        * in /VERSION responses.
+        * @return The socket engine name
+        */
+       virtual std::string GetName();
+};
+
+#endif
+
index ddb738fb93f3ecda583e6b3406b134930386f7fa..736a109eb177bdacf5541aedffdcecb929210b34 100644 (file)
@@ -1 +1,64 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __SOCKETENGINE_EPOLL__\r#define __SOCKETENGINE_EPOLL__\r\r#include <vector>\r#include <string>\r#include <map>\r#include "inspircd_config.h"\r#include "globals.h"\r#include "inspircd.h"\r#include "socketengine.h"\r#include <sys/epoll.h>\r#define EP_DELAY 5\r\rclass InspIRCd;\r\r/** A specialisation of the SocketEngine class, designed to use linux 2.6 epoll().\r */\rclass EPollEngine : public SocketEngine\r{\rprivate:\r /** These are used by epoll() to hold socket events\r     */\r    struct epoll_event events[MAX_DESCRIPTORS];\rpublic:\r    /** Create a new EPollEngine\r    * @param Instance The creator of this object\r   */\r    EPollEngine(InspIRCd* Instance);\r       /** Delete an EPollEngine\r       */\r    virtual ~EPollEngine();\r        virtual bool AddFd(EventHandler* eh);\r  virtual int GetMaxFds();\r       virtual int GetRemainingFds();\r virtual bool DelFd(EventHandler* eh, bool force = false);\r      virtual int DispatchEvents();\r  virtual std::string GetName();\r virtual void WantWrite(EventHandler* eh);\r};\r\r/** Creates a SocketEngine\r */\rclass SocketEngineFactory\r{\rpublic:\r       /** Create a new instance of SocketEngine based on EpollEngine\r  */\r    SocketEngine* Create(InspIRCd* Instance) { return new EPollEngine(Instance); }\r};\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __SOCKETENGINE_EPOLL__
+#define __SOCKETENGINE_EPOLL__
+
+#include <vector>
+#include <string>
+#include <map>
+#include "inspircd_config.h"
+#include "globals.h"
+#include "inspircd.h"
+#include "socketengine.h"
+#include <sys/epoll.h>
+#define EP_DELAY 5
+
+class InspIRCd;
+
+/** A specialisation of the SocketEngine class, designed to use linux 2.6 epoll().
+ */
+class EPollEngine : public SocketEngine
+{
+private:
+       /** These are used by epoll() to hold socket events
+        */
+       struct epoll_event events[MAX_DESCRIPTORS];
+public:
+       /** Create a new EPollEngine
+        * @param Instance The creator of this object
+        */
+       EPollEngine(InspIRCd* Instance);
+       /** Delete an EPollEngine
+        */
+       virtual ~EPollEngine();
+       virtual bool AddFd(EventHandler* eh);
+       virtual int GetMaxFds();
+       virtual int GetRemainingFds();
+       virtual bool DelFd(EventHandler* eh, bool force = false);
+       virtual int DispatchEvents();
+       virtual std::string GetName();
+       virtual void WantWrite(EventHandler* eh);
+};
+
+/** Creates a SocketEngine
+ */
+class SocketEngineFactory
+{
+public:
+       /** Create a new instance of SocketEngine based on EpollEngine
+        */
+       SocketEngine* Create(InspIRCd* Instance) { return new EPollEngine(Instance); }
+};
+
+#endif
index ac27c86e3e093d5482dcef2267c9f82a5aac90f1..f4825c6b46c7aeb5c29b9e7ff403eaa647f6f6cd 100644 (file)
@@ -1 +1,226 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __SOCKETENGINE_IOCP__\r#define __SOCKETENGINE_IOCP__\r\r#define READ_BUFFER_SIZE 600\r#define USING_IOCP 1\r\r#include "inspircd_config.h"\r#include "inspircd_win32wrapper.h"\r#include "globals.h"\r#include "inspircd.h"\r#include "socketengine.h"\r\r/** Socket overlapped event types\r */\renum SocketIOEvent\r{\r  /** Read ready */\r      SOCKET_IO_EVENT_READ_READY                      = 0,\r   /** Write ready */\r     SOCKET_IO_EVENT_WRITE_READY                     = 1,\r   /** Accept ready */\r    SOCKET_IO_EVENT_ACCEPT                          = 2,\r   /** Error occured */\r   SOCKET_IO_EVENT_ERROR                           = 3,\r   /** Number of events */\r        NUM_SOCKET_IO_EVENTS                            = 4,\r};\r\r/** Represents a windows overlapped IO event\r */\rclass Overlapped\r{\r public:\r  /** Overlap event */\r   OVERLAPPED m_overlap;\r  /** Type of event */\r   SocketIOEvent m_event;\r#ifdef WIN64\r    /** Parameters */\r      unsigned __int64 m_params;\r#else\r       /** Parameters */\r      unsigned long m_params;\r#endif\r /** Create an overlapped event\r  */\r    Overlapped(SocketIOEvent ev, int params) : m_event(ev), m_params(params)\r       {\r              memset(&m_overlap, 0, sizeof(OVERLAPPED));\r     }\r};\r\r/** Specific to UDP sockets with overlapped IO\r */\rstruct udp_overlap\r{\r  unsigned char udp_buffer[600];\r unsigned long udp_len;\r sockaddr udp_sockaddr[2];\r      unsigned long udp_sockaddr_len;\r};\r\r/** Specific to accepting sockets with overlapped IO\r */\rstruct accept_overlap\r{\r   int socket;\r    char buf[1024];\r};\r\r/** Implementation of SocketEngine that implements windows IO Completion Ports\r */\rclass IOCPEngine : public SocketEngine\r{\r        /** Creates a "fake" file descriptor for use with an IOCP socket.\r       * This is a little slow, but it isnt called too much. We'll fix it\r     * in a future release.\r         * @return -1 if there are no free slots, and an integer if it finds one.\r       */\r    __inline int GenerateFd(int RealFd)\r    {\r              int index_hash = RealFd % MAX_DESCRIPTORS;\r             if(ref[index_hash] == 0)\r                       return index_hash;\r             else\r           {\r                      register int i = 0;\r                    for(; i < MAX_DESCRIPTORS; ++i)\r                                if(ref[i] == 0)\r                                        return i;\r              }\r              return -1;\r     }\r      \r       /** Global I/O completion port that sockets attach to.\r  */\r    HANDLE m_completionPort;\r\r      /** This is kinda shitty... :/ for getting an address from a real fd. \r  */\r    map<int, EventHandler*> m_binding;\r\rpublic:\r    /** Creates an IOCP Socket Engine\r       * @param Instance The creator of this object\r   */\r    IOCPEngine(InspIRCd* Instance);\r\r       /** Deletes an IOCP socket engine and all the attached sockets\r  */\r    ~IOCPEngine();\r\r        /** Adds an event handler to the completion port, and sets up initial events.\r   * @param eh EventHandler to add\r        * @return True if success, false if no room\r    */\r    bool AddFd(EventHandler* eh);\r\r /** Gets the maximum number of file descriptors that this engine can handle.\r    * @return The number of file descriptors\r       */\r    __inline int GetMaxFds() { return MAX_DESCRIPTORS; }\r\r  /** Gets the number of free/remaining file descriptors under this engine.\r       * @return Remaining count\r      */\r    __inline int GetRemainingFds()\r {\r              register int count = 0;\r                register int i = 0;                     \r               for(; i < MAX_DESCRIPTORS; ++i)\r                        if(ref[i] == 0)\r                                ++count;\r               return count;\r  }\r\r     /** Removes a file descriptor from the set, preventing it from receiving any more events\r        * @return True if remove was successful, false otherwise\r       */\r    bool DelFd(EventHandler* eh, bool force = false);\r\r     /** Called every loop to handle input/output events for all sockets under this engine\r   * @return The number of "changed" sockets.\r     */\r    int DispatchEvents();\r\r /** Gets the name of this socket engine as a string.\r    * @return string of socket engine name\r         */\r    std::string GetName();\r\r        /** Queues a Write event on the specified event handler.\r        * @param eh EventHandler that needs data sent on\r       */\r    void WantWrite(EventHandler* eh);\r\r     /** Posts a completion event on the specified socket.\r   * @param eh EventHandler for message\r   * @param type Event Type\r       * @param param Event Parameter\r         * @return True if added, false if not\r  */\r    bool PostCompletionEvent(EventHandler* eh, SocketIOEvent type, int param);\r\r    /** Posts a read event on the specified socket\r  * @param eh EventHandler (socket)\r      */\r    void PostReadEvent(EventHandler* eh);\r\r /** Posts an accept event on the specified socket\r       * @param eh EventHandler (socket)\r      */\r    void PostAcceptEvent(EventHandler* eh);\r\r       /** Returns the EventHandler attached to a specific fd.\r         * If the fd isnt in the socketengine, returns NULL.\r    * @param fd The event handler to look for\r      * @return A pointer to the event handler, or NULL\r      */\r    EventHandler* GetRef(int fd);\r\r /** Returns true if a file descriptor exists in\r         * the socket engine's list.\r    * @param fd The event handler to look for\r      * @return True if this fd has an event handler\r         */\r    bool HasFd(int fd);\r\r   /** Returns the EventHandler attached to a specific fd.\r         * If the fd isnt in the socketengine, returns NULL.\r    * @param fd The event handler to look for\r      * @return A pointer to the event handler, or NULL\r      */\r    EventHandler* GetIntRef(int fd);\r\r      /** Holds the preallocated buffer passed to WSARecvFrom\r         * function. Yes, I know, it's a dirty hack.\r    */\r    udp_overlap * udp_ov;\r};\r\r/** Creates a SocketEngine\r */\rclass SocketEngineFactory\r{\rpublic:\r   /** Create a new instance of SocketEngine based on IOCPEngine\r   */\r    SocketEngine* Create(InspIRCd* Instance) { return new IOCPEngine(Instance); }\r};\r\r#endif\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __SOCKETENGINE_IOCP__
+#define __SOCKETENGINE_IOCP__
+
+#define READ_BUFFER_SIZE 600
+#define USING_IOCP 1
+
+#include "inspircd_config.h"
+#include "inspircd_win32wrapper.h"
+#include "globals.h"
+#include "inspircd.h"
+#include "socketengine.h"
+
+/** Socket overlapped event types
+ */
+enum SocketIOEvent
+{
+       /** Read ready */
+       SOCKET_IO_EVENT_READ_READY                      = 0,
+       /** Write ready */
+       SOCKET_IO_EVENT_WRITE_READY                     = 1,
+       /** Accept ready */
+       SOCKET_IO_EVENT_ACCEPT                          = 2,
+       /** Error occured */
+       SOCKET_IO_EVENT_ERROR                           = 3,
+       /** Number of events */
+       NUM_SOCKET_IO_EVENTS                            = 4,
+};
+
+/** Represents a windows overlapped IO event
+ */
+class Overlapped
+{
+ public:
+       /** Overlap event */
+       OVERLAPPED m_overlap;
+       /** Type of event */
+       SocketIOEvent m_event;
+#ifdef WIN64
+       /** Parameters */
+       unsigned __int64 m_params;
+#else
+       /** Parameters */
+       unsigned long m_params;
+#endif
+       /** Create an overlapped event
+        */
+       Overlapped(SocketIOEvent ev, int params) : m_event(ev), m_params(params)
+       {
+               memset(&m_overlap, 0, sizeof(OVERLAPPED));
+       }
+};
+
+/** Specific to UDP sockets with overlapped IO
+ */
+struct udp_overlap
+{
+       unsigned char udp_buffer[600];
+       unsigned long udp_len;
+       sockaddr udp_sockaddr[2];
+       unsigned long udp_sockaddr_len;
+};
+
+/** Specific to accepting sockets with overlapped IO
+ */
+struct accept_overlap
+{
+       int socket;
+       char buf[1024];
+};
+
+/** Implementation of SocketEngine that implements windows IO Completion Ports
+ */
+class IOCPEngine : public SocketEngine
+{
+       /** Creates a "fake" file descriptor for use with an IOCP socket.
+        * This is a little slow, but it isnt called too much. We'll fix it
+        * in a future release.
+        * @return -1 if there are no free slots, and an integer if it finds one.
+        */
+       __inline int GenerateFd(int RealFd)
+       {
+               int index_hash = RealFd % MAX_DESCRIPTORS;
+               if(ref[index_hash] == 0)
+                       return index_hash;
+               else
+               {
+                       register int i = 0;
+                       for(; i < MAX_DESCRIPTORS; ++i)
+                               if(ref[i] == 0)
+                                       return i;
+               }
+               return -1;
+       }
+       
+       /** Global I/O completion port that sockets attach to.
+        */
+       HANDLE m_completionPort;
+
+       /** This is kinda shitty... :/ for getting an address from a real fd. 
+        */
+       map<int, EventHandler*> m_binding;
+
+public:
+       /** Creates an IOCP Socket Engine
+        * @param Instance The creator of this object
+        */
+       IOCPEngine(InspIRCd* Instance);
+
+       /** Deletes an IOCP socket engine and all the attached sockets
+        */
+       ~IOCPEngine();
+
+       /** Adds an event handler to the completion port, and sets up initial events.
+        * @param eh EventHandler to add
+        * @return True if success, false if no room
+        */
+       bool AddFd(EventHandler* eh);
+
+       /** Gets the maximum number of file descriptors that this engine can handle.
+        * @return The number of file descriptors
+        */
+       __inline int GetMaxFds() { return MAX_DESCRIPTORS; }
+
+       /** Gets the number of free/remaining file descriptors under this engine.
+        * @return Remaining count
+        */
+       __inline int GetRemainingFds()
+       {
+               register int count = 0;
+               register int i = 0;                     
+               for(; i < MAX_DESCRIPTORS; ++i)
+                       if(ref[i] == 0)
+                               ++count;
+               return count;
+       }
+
+       /** Removes a file descriptor from the set, preventing it from receiving any more events
+        * @return True if remove was successful, false otherwise
+        */
+       bool DelFd(EventHandler* eh, bool force = false);
+
+       /** Called every loop to handle input/output events for all sockets under this engine
+        * @return The number of "changed" sockets.
+        */
+       int DispatchEvents();
+
+       /** Gets the name of this socket engine as a string.
+        * @return string of socket engine name
+        */
+       std::string GetName();
+
+       /** Queues a Write event on the specified event handler.
+        * @param eh EventHandler that needs data sent on
+        */
+       void WantWrite(EventHandler* eh);
+
+       /** Posts a completion event on the specified socket.
+        * @param eh EventHandler for message
+        * @param type Event Type
+        * @param param Event Parameter
+        * @return True if added, false if not
+        */
+       bool PostCompletionEvent(EventHandler* eh, SocketIOEvent type, int param);
+
+       /** Posts a read event on the specified socket
+        * @param eh EventHandler (socket)
+        */
+       void PostReadEvent(EventHandler* eh);
+
+       /** Posts an accept event on the specified socket
+        * @param eh EventHandler (socket)
+        */
+       void PostAcceptEvent(EventHandler* eh);
+
+       /** Returns the EventHandler attached to a specific fd.
+        * If the fd isnt in the socketengine, returns NULL.
+        * @param fd The event handler to look for
+        * @return A pointer to the event handler, or NULL
+        */
+       EventHandler* GetRef(int fd);
+
+       /** Returns true if a file descriptor exists in
+        * the socket engine's list.
+        * @param fd The event handler to look for
+        * @return True if this fd has an event handler
+        */
+       bool HasFd(int fd);
+
+       /** Returns the EventHandler attached to a specific fd.
+        * If the fd isnt in the socketengine, returns NULL.
+        * @param fd The event handler to look for
+        * @return A pointer to the event handler, or NULL
+        */
+       EventHandler* GetIntRef(int fd);
+
+       /** Holds the preallocated buffer passed to WSARecvFrom
+        * function. Yes, I know, it's a dirty hack.
+        */
+       udp_overlap * udp_ov;
+};
+
+/** Creates a SocketEngine
+ */
+class SocketEngineFactory
+{
+public:
+       /** Create a new instance of SocketEngine based on IOCPEngine
+        */
+       SocketEngine* Create(InspIRCd* Instance) { return new IOCPEngine(Instance); }
+};
+
+#endif
+
index b05d4052067a22379b097a6876dfe0894b7fdddb..e7413d4bb597dac53e18dfb1379e4c268a1d7036 100644 (file)
@@ -1 +1,68 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __SOCKETENGINE_KQUEUE__\r#define __SOCKETENGINE_KQUEUE__\r\r#include <vector>\r#include <string>\r#include <map>\r#include "inspircd_config.h"\r#include "globals.h"\r#include "inspircd.h"\r#include <sys/types.h>\r#include <sys/event.h>\r#include <sys/time.h>\r#include "socketengine.h"\r\rclass InspIRCd;\r\r/** A specialisation of the SocketEngine class, designed to use FreeBSD kqueue().\r */\rclass KQueueEngine : public SocketEngine\r{\rprivate:\r     /** These are used by kqueue() to hold socket events\r    */\r    struct kevent ke_list[MAX_DESCRIPTORS];\r        /** This is a specialised time value used by kqueue()\r   */\r    struct timespec ts;\rpublic:\r    /** Create a new KQueueEngine\r   * @param Instance The creator of this object\r   */\r    KQueueEngine(InspIRCd* Instance);\r      /** Delete a KQueueEngine\r       */\r    virtual ~KQueueEngine();\r       virtual bool AddFd(EventHandler* eh);\r  virtual int GetMaxFds();\r       virtual int GetRemainingFds();\r virtual bool DelFd(EventHandler* eh, bool force = false);\r      virtual int DispatchEvents();\r  virtual std::string GetName();\r virtual void WantWrite(EventHandler* eh);\r};\r\r/** Creates a SocketEngine\r */\rclass SocketEngineFactory\r{\r public:\r      /** Create a new instance of SocketEngine based on KQueueEngine\r         */\r    SocketEngine* Create(InspIRCd* Instance) { return new KQueueEngine(Instance); }\r};\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __SOCKETENGINE_KQUEUE__
+#define __SOCKETENGINE_KQUEUE__
+
+#include <vector>
+#include <string>
+#include <map>
+#include "inspircd_config.h"
+#include "globals.h"
+#include "inspircd.h"
+#include <sys/types.h>
+#include <sys/event.h>
+#include <sys/time.h>
+#include "socketengine.h"
+
+class InspIRCd;
+
+/** A specialisation of the SocketEngine class, designed to use FreeBSD kqueue().
+ */
+class KQueueEngine : public SocketEngine
+{
+private:
+       /** These are used by kqueue() to hold socket events
+        */
+       struct kevent ke_list[MAX_DESCRIPTORS];
+       /** This is a specialised time value used by kqueue()
+        */
+       struct timespec ts;
+public:
+       /** Create a new KQueueEngine
+        * @param Instance The creator of this object
+        */
+       KQueueEngine(InspIRCd* Instance);
+       /** Delete a KQueueEngine
+        */
+       virtual ~KQueueEngine();
+       virtual bool AddFd(EventHandler* eh);
+       virtual int GetMaxFds();
+       virtual int GetRemainingFds();
+       virtual bool DelFd(EventHandler* eh, bool force = false);
+       virtual int DispatchEvents();
+       virtual std::string GetName();
+       virtual void WantWrite(EventHandler* eh);
+};
+
+/** Creates a SocketEngine
+ */
+class SocketEngineFactory
+{
+ public:
+       /** Create a new instance of SocketEngine based on KQueueEngine
+        */
+       SocketEngine* Create(InspIRCd* Instance) { return new KQueueEngine(Instance); }
+};
+
+#endif
index 72b5da67139d60f8a6a690de39599a11791f8bc0..a5951a138b6dd70245a775943ce9318cca0f7457 100644 (file)
@@ -1 +1,68 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __SOCKETENGINE_PORTS__\r#define __SOCKETENGINE_PORTS__\r\r#ifndef __sun\r# error You need Solaris 10 or later to make use of this code.\r#endif\r\r#include <vector>\r#include <string>\r#include <map>\r#include "inspircd_config.h"\r#include "globals.h"\r#include "inspircd.h"\r#include "socketengine.h"\r#include <port.h>\r\rclass InspIRCd;\r\r/** A specialisation of the SocketEngine class, designed to use solaris 10 I/O completion ports\r */\rclass PortsEngine : public SocketEngine\r{\rprivate:\r       /** These are used by epoll() to hold socket events\r     */\r    port_event_t events[MAX_DESCRIPTORS];\rpublic:\r  /** Create a new PortsEngine\r    * @param Instance The creator of this object\r   */\r    PortsEngine(InspIRCd* Instance);\r       /** Delete a PortsEngine\r        */\r    virtual ~PortsEngine();\r        virtual bool AddFd(EventHandler* eh);\r  virtual int GetMaxFds();\r       virtual int GetRemainingFds();\r virtual bool DelFd(EventHandler* eh, bool force = false);\r      virtual int DispatchEvents();\r  virtual std::string GetName();\r virtual void WantWrite(EventHandler* eh);\r};\r\r/** Creates a SocketEngine\r */\rclass SocketEngineFactory\r{\rpublic:\r       /** Create a new instance of SocketEngine based on PortsEngine\r  */\r    SocketEngine* Create(InspIRCd* Instance) { return new PortsEngine(Instance); }\r};\r\r#endif\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __SOCKETENGINE_PORTS__
+#define __SOCKETENGINE_PORTS__
+
+#ifndef __sun
+# error You need Solaris 10 or later to make use of this code.
+#endif
+
+#include <vector>
+#include <string>
+#include <map>
+#include "inspircd_config.h"
+#include "globals.h"
+#include "inspircd.h"
+#include "socketengine.h"
+#include <port.h>
+
+class InspIRCd;
+
+/** A specialisation of the SocketEngine class, designed to use solaris 10 I/O completion ports
+ */
+class PortsEngine : public SocketEngine
+{
+private:
+       /** These are used by epoll() to hold socket events
+        */
+       port_event_t events[MAX_DESCRIPTORS];
+public:
+       /** Create a new PortsEngine
+        * @param Instance The creator of this object
+        */
+       PortsEngine(InspIRCd* Instance);
+       /** Delete a PortsEngine
+        */
+       virtual ~PortsEngine();
+       virtual bool AddFd(EventHandler* eh);
+       virtual int GetMaxFds();
+       virtual int GetRemainingFds();
+       virtual bool DelFd(EventHandler* eh, bool force = false);
+       virtual int DispatchEvents();
+       virtual std::string GetName();
+       virtual void WantWrite(EventHandler* eh);
+};
+
+/** Creates a SocketEngine
+ */
+class SocketEngineFactory
+{
+public:
+       /** Create a new instance of SocketEngine based on PortsEngine
+        */
+       SocketEngine* Create(InspIRCd* Instance) { return new PortsEngine(Instance); }
+};
+
+#endif
+
index 553acdea29317cb23f149c9af7f31e6da51dfcca..2126e8ec56053e8c33a21be7a2d7e56de5e7a6c6 100644 (file)
@@ -1 +1,69 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __SOCKETENGINE_SELECT__\r#define __SOCKETENGINE_SELECT__\r\r#include <vector>\r#include <string>\r#include <map>\r#include <sys/select.h>\r#include "inspircd_config.h"\r#include "globals.h"\r#include "inspircd.h"\r#include "socketengine.h"\r\rclass InspIRCd;\r\r/** A specialisation of the SocketEngine class, designed to use traditional select().\r */\rclass SelectEngine : public SocketEngine\r{\rprivate:\r     /** Because select() does not track an fd list for us between calls, we have one of our own\r     */\r    std::map<int,int> fds;\r /** List of writeable ones (WantWrite())\r        */\r    bool writeable[MAX_DESCRIPTORS];\r       /** The read set and write set, populated before each call to select().\r         */\r    fd_set wfdset, rfdset, errfdset;\rpublic:\r       /** Create a new SelectEngine\r   * @param Instance The creator of this object\r   */\r    SelectEngine(InspIRCd* Instance);\r      /** Delete a SelectEngine\r       */\r    virtual ~SelectEngine();\r       virtual bool AddFd(EventHandler* eh);\r  virtual int GetMaxFds();\r       virtual int GetRemainingFds();\r virtual bool DelFd(EventHandler* eh, bool force = false);\r      virtual int DispatchEvents();\r  virtual std::string GetName();\r virtual void WantWrite(EventHandler* eh);\r};\r\r/** Creates a SocketEngine\r */\rclass SocketEngineFactory\r{\rpublic:\r       /** Create a new instance of SocketEngine based on SelectEngine\r         */\r    SocketEngine* Create(InspIRCd* Instance) { return new SelectEngine(Instance); }\r};\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __SOCKETENGINE_SELECT__
+#define __SOCKETENGINE_SELECT__
+
+#include <vector>
+#include <string>
+#include <map>
+#include <sys/select.h>
+#include "inspircd_config.h"
+#include "globals.h"
+#include "inspircd.h"
+#include "socketengine.h"
+
+class InspIRCd;
+
+/** A specialisation of the SocketEngine class, designed to use traditional select().
+ */
+class SelectEngine : public SocketEngine
+{
+private:
+       /** Because select() does not track an fd list for us between calls, we have one of our own
+        */
+       std::map<int,int> fds;
+       /** List of writeable ones (WantWrite())
+        */
+       bool writeable[MAX_DESCRIPTORS];
+       /** The read set and write set, populated before each call to select().
+        */
+       fd_set wfdset, rfdset, errfdset;
+public:
+       /** Create a new SelectEngine
+        * @param Instance The creator of this object
+        */
+       SelectEngine(InspIRCd* Instance);
+       /** Delete a SelectEngine
+        */
+       virtual ~SelectEngine();
+       virtual bool AddFd(EventHandler* eh);
+       virtual int GetMaxFds();
+       virtual int GetRemainingFds();
+       virtual bool DelFd(EventHandler* eh, bool force = false);
+       virtual int DispatchEvents();
+       virtual std::string GetName();
+       virtual void WantWrite(EventHandler* eh);
+};
+
+/** Creates a SocketEngine
+ */
+class SocketEngineFactory
+{
+public:
+       /** Create a new instance of SocketEngine based on SelectEngine
+        */
+       SocketEngine* Create(InspIRCd* Instance) { return new SelectEngine(Instance); }
+};
+
+#endif
index ad4f5ef8760b0cfadb7dd7b66734a78f2ec45fc6..ef8b82e31f64d728d662c35769af20842e162a9a 100644 (file)
@@ -1 +1,156 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef INSPIRCD_TIMER_H\r#define INSPIRCD_TIMER_H\r\rclass InspIRCd;\r\r/** Timer class for one-second resolution timers\r * InspTimer provides a facility which allows module\r * developers to create one-shot timers. The timer\r * can be made to trigger at any time up to a one-second\r * resolution. To use InspTimer, inherit a class from\r * InspTimer, then insert your inherited class into the\r * queue using Server::AddTimer(). The Tick() method of\r * your object (which you should override) will be called\r * at the given time.\r */\rclass CoreExport InspTimer : public Extensible\r{\r private:\r        /** The triggering time\r         */\r    time_t trigger;\r        /** Number of seconds between triggers\r  */\r    long secs;\r     /** True if this is a repeating timer\r   */\r    bool repeat;\r public:\r  /** Default constructor, initializes the triggering time\r        * @param secs_from_now The number of seconds from now to trigger the timer\r     * @param now The time now\r      * @param repeating Repeat this timer every secs_from_now seconds if set to true\r        */\r    InspTimer(long secs_from_now,time_t now, bool repeating = false)\r       {\r              trigger = now + secs_from_now;\r         secs = secs_from_now;\r          repeat = repeating;\r    }\r\r     /** Default destructor, does nothing.\r   */\r    virtual ~InspTimer() { }\r\r      /** Retrieve the current triggering time\r        */\r    virtual time_t GetTimer()\r      {\r              return trigger;\r        }\r\r     /** Called when the timer ticks.\r        * You should override this method with some useful code to\r     * handle the tick event.\r       */\r    virtual void Tick(time_t TIME) = 0;\r\r   /** Returns true if this timer is set to repeat\r         */\r    bool GetRepeat()\r       {\r              return repeat;\r }\r\r     /** Returns the interval (number of seconds between ticks)\r      * of this timer object.\r        */\r    long GetSecs()\r {\r              return secs;\r   }\r\r     /** Cancels the repeat state of a repeating timer.\r      * If you call this method, then the next time your\r     * timer ticks, it will be removed immediately after.\r   * You should use this method call to remove a recurring\r        * timer if you wish to do so within the timer's Tick\r   * event, as calling TimerManager::DelTimer() from within\r       * the InspTimer::Tick() method is dangerous and may\r    * cause a segmentation fault. Calling CancelRepeat()\r   * is safe in this case.\r        */\r    void CancelRepeat()\r    {\r              repeat = false;\r        }\r};\r\r\r/** This class manages sets of InspTimers, and triggers them at their defined times.\r * This will ensure timers are not missed, as well as removing timers that have\r * expired and allowing the addition of new ones.\r */\rclass CoreExport TimerManager : public Extensible\r{\r protected:\r      /** A group of timers all set to trigger at the same time\r       */\r    typedef std::vector<InspTimer*> timergroup;\r    /** A map of timergroups, each group has a specific trigger time\r        */\r    typedef std::map<time_t, timergroup*> timerlist;\r       /** Set when ticking timers, to prevent deletion while iterating\r        */\r    bool CantDeleteHere;\r   /** Creating server instance\r    */\r    InspIRCd* ServerInstance;\r private:\r\r   /** The current timer set, a map of timergroups\r         */\r    timerlist Timers;\r\r public:\r    /** Constructor\r         */\r    TimerManager(InspIRCd* Instance);\r      /** Tick all pending InspTimers\r         * @param TIME the current system time\r  */\r    void TickTimers(time_t TIME);\r  /** Add an InspTimer\r    * @param T an InspTimer derived class to add\r   * @param secs_from_now You may set this to the number of seconds\r       * from the current time when the timer will tick, or you may just\r      * leave this unset and the values set by the InspTimers constructor\r    * will be used. This is used internally for re-triggering repeating\r    * timers.\r      */\r    void AddTimer(InspTimer* T, long secs_from_now = 0);\r   /** Delete an InspTimer\r         * @param T an InspTimer derived class to delete\r        */\r    void DelTimer(InspTimer* T);\r   /** Tick any timers that have been missed due to lag\r    * @param TIME the current system time\r  */\r    void TickMissedTimers(time_t TIME);\r};\r\r#endif\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef INSPIRCD_TIMER_H
+#define INSPIRCD_TIMER_H
+
+class InspIRCd;
+
+/** Timer class for one-second resolution timers
+ * InspTimer provides a facility which allows module
+ * developers to create one-shot timers. The timer
+ * can be made to trigger at any time up to a one-second
+ * resolution. To use InspTimer, inherit a class from
+ * InspTimer, then insert your inherited class into the
+ * queue using Server::AddTimer(). The Tick() method of
+ * your object (which you should override) will be called
+ * at the given time.
+ */
+class CoreExport InspTimer : public Extensible
+{
+ private:
+       /** The triggering time
+        */
+       time_t trigger;
+       /** Number of seconds between triggers
+        */
+       long secs;
+       /** True if this is a repeating timer
+        */
+       bool repeat;
+ public:
+       /** Default constructor, initializes the triggering time
+        * @param secs_from_now The number of seconds from now to trigger the timer
+        * @param now The time now
+        * @param repeating Repeat this timer every secs_from_now seconds if set to true
+        */
+       InspTimer(long secs_from_now,time_t now, bool repeating = false)
+       {
+               trigger = now + secs_from_now;
+               secs = secs_from_now;
+               repeat = repeating;
+       }
+
+       /** Default destructor, does nothing.
+        */
+       virtual ~InspTimer() { }
+
+       /** Retrieve the current triggering time
+        */
+       virtual time_t GetTimer()
+       {
+               return trigger;
+       }
+
+       /** Called when the timer ticks.
+        * You should override this method with some useful code to
+        * handle the tick event.
+        */
+       virtual void Tick(time_t TIME) = 0;
+
+       /** Returns true if this timer is set to repeat
+        */
+       bool GetRepeat()
+       {
+               return repeat;
+       }
+
+       /** Returns the interval (number of seconds between ticks)
+        * of this timer object.
+        */
+       long GetSecs()
+       {
+               return secs;
+       }
+
+       /** Cancels the repeat state of a repeating timer.
+        * If you call this method, then the next time your
+        * timer ticks, it will be removed immediately after.
+        * You should use this method call to remove a recurring
+        * timer if you wish to do so within the timer's Tick
+        * event, as calling TimerManager::DelTimer() from within
+        * the InspTimer::Tick() method is dangerous and may
+        * cause a segmentation fault. Calling CancelRepeat()
+        * is safe in this case.
+        */
+       void CancelRepeat()
+       {
+               repeat = false;
+       }
+};
+
+
+/** This class manages sets of InspTimers, and triggers them at their defined times.
+ * This will ensure timers are not missed, as well as removing timers that have
+ * expired and allowing the addition of new ones.
+ */
+class CoreExport TimerManager : public Extensible
+{
+ protected:
+       /** A group of timers all set to trigger at the same time
+        */
+       typedef std::vector<InspTimer*> timergroup;
+       /** A map of timergroups, each group has a specific trigger time
+        */
+       typedef std::map<time_t, timergroup*> timerlist;
+       /** Set when ticking timers, to prevent deletion while iterating
+        */
+       bool CantDeleteHere;
+       /** Creating server instance
+        */
+       InspIRCd* ServerInstance;
+ private:
+
+       /** The current timer set, a map of timergroups
+        */
+       timerlist Timers;
+
+ public:
+       /** Constructor
+        */
+       TimerManager(InspIRCd* Instance);
+       /** Tick all pending InspTimers
+        * @param TIME the current system time
+        */
+       void TickTimers(time_t TIME);
+       /** Add an InspTimer
+        * @param T an InspTimer derived class to add
+        * @param secs_from_now You may set this to the number of seconds
+        * from the current time when the timer will tick, or you may just
+        * leave this unset and the values set by the InspTimers constructor
+        * will be used. This is used internally for re-triggering repeating
+        * timers.
+        */
+       void AddTimer(InspTimer* T, long secs_from_now = 0);
+       /** Delete an InspTimer
+        * @param T an InspTimer derived class to delete
+        */
+       void DelTimer(InspTimer* T);
+       /** Tick any timers that have been missed due to lag
+        * @param TIME the current system time
+        */
+       void TickMissedTimers(time_t TIME);
+};
+
+#endif
+
index 0c9ee3ed1c0e4abb0c370f2acbdce11d3ba9d356..f101e161557a388edb3ab8aaba4a9cc54bdc974e 100644 (file)
@@ -1 +1,53 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __TYPEDEF_H__\r#define __TYPEDEF_H__\r\r#include <string>\r#include "inspircd_config.h"\r#include "hash_map.h"\r#include "users.h"\r#include "channels.h"\r#include "hashcomp.h"\r#include "inspstring.h"\r#include "ctables.h"\r#include "modules.h"\r#include "globals.h"\r\r#ifndef WIN32\r/** User hash (POSIX systems with GCC)\r */\rtypedef nspace::hash_map<std::string, userrec*, nspace::hash<string>, irc::StrHashComp> user_hash;\r/** Channel hash (POSIX systems with GCC)\r */\rtypedef nspace::hash_map<std::string, chanrec*, nspace::hash<string>, irc::StrHashComp> chan_hash;\r#else\r/** User hash (windows systems with visual studio)\r */\rtypedef nspace::hash_map<std::string, userrec*, nspace::hash_compare<string, less<string> > > user_hash;\r/** Channel hash (windows systems with visual studio)\r */\rtypedef nspace::hash_map<std::string, chanrec*, nspace::hash_compare<string, less<string> > > chan_hash;\r#endif\r\r/** Server name cache\r */\rtypedef std::vector<std::string*> servernamelist;\r\r/** A cached text file stored line by line.\r */\rtypedef std::deque<std::string> file_cache;\r\r#endif\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __TYPEDEF_H__
+#define __TYPEDEF_H__
+
+#include <string>
+#include "inspircd_config.h"
+#include "hash_map.h"
+#include "users.h"
+#include "channels.h"
+#include "hashcomp.h"
+#include "inspstring.h"
+#include "ctables.h"
+#include "modules.h"
+#include "globals.h"
+
+#ifndef WIN32
+/** User hash (POSIX systems with GCC)
+ */
+typedef nspace::hash_map<std::string, userrec*, nspace::hash<string>, irc::StrHashComp> user_hash;
+/** Channel hash (POSIX systems with GCC)
+ */
+typedef nspace::hash_map<std::string, chanrec*, nspace::hash<string>, irc::StrHashComp> chan_hash;
+#else
+/** User hash (windows systems with visual studio)
+ */
+typedef nspace::hash_map<std::string, userrec*, nspace::hash_compare<string, less<string> > > user_hash;
+/** Channel hash (windows systems with visual studio)
+ */
+typedef nspace::hash_map<std::string, chanrec*, nspace::hash_compare<string, less<string> > > chan_hash;
+#endif
+
+/** Server name cache
+ */
+typedef std::vector<std::string*> servernamelist;
+
+/** A cached text file stored line by line.
+ */
+typedef std::deque<std::string> file_cache;
+
+#endif
+
index 3b2ff13d6fc28775cfceddd24c49f7607b46547f..baf7367450f39e1ec7ee4ac7f4243dcd0db44e7b 100644 (file)
@@ -1 +1,474 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef INSPIRCD_LISTMODE_PROVIDER\r#define INSPIRCD_LISTMODE_PROVIDER\r\r#include <stdio.h>\r#include <string>\r#include <sstream>\r#include <vector>\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r#include "wildcard.h"\r#include "inspircd.h"\r\r/* Updated to use the <banlist> config tag if it exists\r * Written by Om <omster@gmail.com>, December 2005.\r * Based on code previously written by Om - April 2005\r * Updated to new API July 8th 2006 by Brain\r * Originally based on m_chanprotect and m_silence\r */\r\r/** Get the time as a string\r */\rinline std::string stringtime()\r{\r    std::ostringstream TIME;\r       TIME << time(NULL); \r   return TIME.str();\r}\r\r/** An item in a listmode's list\r */\rclass ListItem : public classbase\r{\rpublic:\r std::string nick;\r      irc::string mask;\r      std::string time;\r};\r\r/** The number of items a listmode's list may contain\r */\rclass ListLimit : public classbase\r{\rpublic:\r   std::string mask;\r      unsigned int limit;\r};\r\r/** Items stored in the channel's list\r */\rtypedef std::vector<ListItem> modelist;\r/** Max items per channel by name\r */\rtypedef std::vector<ListLimit> limitlist;\r\r/** A request used to check if a user is on a channel's list or not\r */\rclass ListModeRequest : public Request\r{\r public:\r  userrec* user;\r chanrec* chan;\r\r        /** Check if a user is on a channel's list.\r     * The Event::Send() event returns true if the user is on the channel's list.\r   * @param sender Sending module\r         * @param target Target module\r  * @param u User to check against\r       * @param c Channel to check against\r    */\r    ListModeRequest(Module* sender, Module* target, userrec* u, chanrec* c) : Request(sender, target, "LM_CHECKLIST"), user(u), chan(c)\r    {\r      }\r\r     /** Destructor\r  */\r    ~ListModeRequest()\r     {\r      }\r};\r\r/** The base class for list modes, should be inherited.\r */\rclass ListModeBase : public ModeHandler\r{\r protected:\r        /** Storage key\r         */\r    std::string infokey;\r   /** Numeric to use when outputting the list\r     */\r    std::string listnumeric;\r       /** Numeric to indicate end of list\r     */\r    std::string endoflistnumeric;\r  /** String to send for end of list\r      */\r    std::string endofliststring;\r   /** Automatically tidy up entries\r       */\r    bool tidy;\r     /** Config tag to check for max items per channel\r       */\r    std::string configtag;\r /** Limits on a per-channel basis read from the tag\r     * specified in ListModeBase::configtag\r         */\r    limitlist chanlimits;\r \r public:\r       /** Constructor.\r        * @param Instance The creator of this class\r    * @param modechar Mode character\r       * @param eolstr End of list string\r     * @pram lnum List numeric\r      * @param eolnum End of list numeric\r    * @param autotidy Automatically tidy list entries on add\r       * @param ctag Configuration tag to get limits from\r     */\r    ListModeBase(InspIRCd* Instance, char modechar, const std::string &eolstr, const std::string &lnum, const std::string &eolnum, bool autotidy, const std::string &ctag = "banlist")\r     : ModeHandler(Instance, modechar, 1, 1, true, MODETYPE_CHANNEL, false), listnumeric(lnum), endoflistnumeric(eolnum), endofliststring(eolstr), tidy(autotidy), configtag(ctag)\r  {\r              this->DoRehash();\r              infokey = "listbase_mode_" + std::string(1, mode) + "_list";\r   }\r\r     /** See mode.h \r         */\r    std::pair<bool,std::string> ModeSet(userrec* source, userrec* dest, chanrec* channel, const std::string &parameter)\r    {\r              modelist* el;\r          channel->GetExt(infokey, el);\r          if (el)\r                {\r                      for (modelist::iterator it = el->begin(); it != el->end(); it++)\r                       {\r                              if(parameter == it->mask)\r                              {\r                                      return std::make_pair(true, parameter);\r                                }\r                      }\r              }\r              return std::make_pair(false, parameter);\r       }\r\r     /** Display the list for this mode\r      * @param user The user to send the list to\r     * @param channel The channel the user is requesting the list for\r       */\r    virtual void DisplayList(userrec* user, chanrec* channel)\r      {\r              modelist* el;\r          channel->GetExt(infokey, el);\r          if (el)\r                {\r                      for (modelist::reverse_iterator it = el->rbegin(); it != el->rend(); ++it)\r                     {\r                              user->WriteServ("%s %s %s %s %s %s", listnumeric.c_str(), user->nick, channel->name, it->mask.c_str(), it->nick.c_str(), it->time.c_str());\r                    }\r              }\r              user->WriteServ("%s %s %s :%s", endoflistnumeric.c_str(), user->nick, channel->name, endofliststring.c_str());\r }\r\r     /** Remove all instances of the mode from a channel.\r    * See mode.h\r   * @param channel The channel to remove all instances of the mode from\r  */\r    virtual void RemoveMode(chanrec* channel)\r      {\r              modelist* el;\r          channel->GetExt(infokey, el);\r          if (el)\r                {\r                      irc::modestacker modestack(false);\r                     std::deque<std::string> stackresult;\r                   const char* mode_junk[MAXMODES+2];\r                     mode_junk[0] = channel->name;\r                  userrec* n = new userrec(ServerInstance);\r                      n->SetFd(FD_MAGIC_NUMBER);\r                     for (modelist::iterator it = el->begin(); it != el->end(); it++)\r                       {\r                              modestack.Push(this->GetModeChar(), assign(it->mask));\r                 }\r                      while (modestack.GetStackedLine(stackresult))\r                  {\r                              for (size_t j = 0; j < stackresult.size(); j++)\r                                {\r                                      mode_junk[j+1] = stackresult[j].c_str();\r                               }\r                              ServerInstance->SendMode(mode_junk, stackresult.size() + 1, n);         \r                       }\r\r                     delete n;\r              }\r      }\r\r     /** See mode.h\r  */\r    virtual void RemoveMode(userrec* user)\r {\r              /* Listmodes dont get set on users */\r  }\r\r     /** Perform a rehash of this mode's configuration data\r  */\r    virtual void DoRehash()\r        {\r              ConfigReader Conf(ServerInstance);\r\r            chanlimits.clear();\r\r           for (int i = 0; i < Conf.Enumerate(configtag); i++)\r            {\r                      // For each <banlist> tag\r                      ListLimit limit;\r                       limit.mask = Conf.ReadValue(configtag, "chan", i);\r                     limit.limit = Conf.ReadInteger(configtag, "limit", i, true);\r\r                  if (limit.mask.size() && limit.limit > 0)\r                              chanlimits.push_back(limit);\r           }\r              if (chanlimits.size() == 0)\r            {\r                      ListLimit limit;\r                       limit.mask = "*";\r                      limit.limit = 64;\r                      chanlimits.push_back(limit);\r           }\r      }\r\r     /** Populate the Implements list with the correct events for a List Mode\r        */\r    virtual void DoImplements(char* List)\r  {\r              List[I_OnChannelDelete] = List[I_OnSyncChannel] = List[I_OnCleanup] = List[I_OnRehash] = 1;\r    }\r\r     /** Handle the list mode.\r       * See mode.h\r   */\r    virtual ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)\r {\r              // Try and grab the list\r               modelist* el;\r          channel->GetExt(infokey, el);\r\r         if (adding)\r            {\r                      // If there was no list\r                        if (!el)\r                       {\r                              // Make one\r                            el = new modelist;\r                             channel->Extend(infokey, el);\r                  }\r\r                     // Clean the mask up\r                   if (this->tidy)\r                                ModeParser::CleanMask(parameter);\r\r                     // Check if the item already exists in the list\r                        for (modelist::iterator it = el->begin(); it != el->end(); it++)\r                       {\r                              if (parameter == it->mask)\r                             {\r                                      /* Give a subclass a chance to error about this */\r                                     TellAlreadyOnList(source, channel, parameter);\r                                 \r                                       // it does, deny the change\r                                    return MODEACTION_DENY;\r                                }\r                      }\r\r                     unsigned int maxsize = 0;\r\r                     for (limitlist::iterator it = chanlimits.begin(); it != chanlimits.end(); it++)\r                        {\r                              if (match(channel->name, it->mask.c_str()))\r                            {\r                                      // We have a pattern matching the channel...\r                                   maxsize = el->size();\r                                  if (maxsize < it->limit)\r                                       {\r                                              /* Ok, it *could* be allowed, now give someone subclassing us\r                                           * a chance to validate the parameter.\r                                          * The param is passed by reference, so they can both modify it\r                                                 * and tell us if we allow it or not.\r                                           *\r                                              * eg, the subclass could:\r                                              * 1) allow\r                                             * 2) 'fix' parameter and then allow\r                                            * 3) deny\r                                              */\r                                            if (ValidateParam(source, channel, parameter))\r                                         {\r                                                      // And now add the mask onto the list...\r                                                       ListItem e;\r                                                    e.mask = assign(parameter);\r                                                    e.nick = source->nick;\r                                                 e.time = stringtime();\r\r                                                        el->push_back(e);\r                                                      return MODEACTION_ALLOW;\r                                               }\r                                              else\r                                           {\r                                                      /* If they deny it they have the job of giving an error message */\r                                                     return MODEACTION_DENY;\r                                                }\r                                      }\r                              }\r                      }\r\r                     /* List is full, give subclass a chance to send a custom message */\r                    if (!TellListTooLong(source, channel, parameter))\r                      {\r                              source->WriteServ("478 %s %s %s :Channel ban/ignore list is full", source->nick, channel->name, parameter.c_str());\r                    }\r                      \r                       parameter = "";\r                        return MODEACTION_DENY; \r               }\r              else\r           {\r                      // We're taking the mode off\r                   if (el)\r                        {\r                              for (modelist::iterator it = el->begin(); it != el->end(); it++)\r                               {\r                                      if (parameter == it->mask)\r                                     {\r                                              el->erase(it);\r                                         if (el->size() == 0)\r                                           {\r                                                      channel->Shrink(infokey);\r                                                      delete el;\r                                             }\r                                              return MODEACTION_ALLOW;\r                                       }\r                              }\r                              /* Tried to remove something that wasn't set */\r                                TellNotSet(source, channel, parameter);\r                                parameter = "";\r                                return MODEACTION_DENY;\r                        }\r                      else\r                   {\r                              /* Hmm, taking an exception off a non-existant list, DIE */\r                            TellNotSet(source, channel, parameter);\r                                parameter = "";\r                                return MODEACTION_DENY;\r                        }\r              }\r              return MODEACTION_DENY;\r        }\r\r     /** Get Extensible key for this mode\r    */\r    virtual std::string& GetInfoKey()\r      {\r              return infokey;\r        }\r\r     /** Handle channel deletion.\r    * See modules.h.\r       * @param chan Channel being deleted\r    */\r    virtual void DoChannelDelete(chanrec* chan)\r    {\r              modelist* list;\r                chan->GetExt(infokey, list);\r\r          if (list)\r              {\r                      chan->Shrink(infokey);\r                 delete list;\r           }\r      }\r\r     /** Syncronize channel item list with another server.\r   * See modules.h\r        * @param chan Channel to syncronize\r    * @param proto Protocol module pointer\r         * @param opaque Opaque connection handle\r       */\r    virtual void DoSyncChannel(chanrec* chan, Module* proto, void* opaque)\r {\r              modelist* list;\r                chan->GetExt(infokey, list);\r           irc::modestacker modestack(true);\r              std::deque<std::string> stackresult;\r           if (list)\r              {\r                      for (modelist::iterator it = list->begin(); it != list->end(); it++)\r                   {\r                              modestack.Push(std::string(1, mode)[0], assign(it->mask));\r                     }\r              }\r              while (modestack.GetStackedLine(stackresult))\r          {\r                      irc::stringjoiner mode_join(" ", stackresult, 0, stackresult.size() - 1);\r                      std::string line = mode_join.GetJoined();\r                      proto->ProtoSendMode(opaque, TYPE_CHANNEL, chan, line);\r                }\r      }\r\r     /** Clean up module on unload\r   * @param target_type Type of target to clean\r   * @param item Item to clean\r    */\r    virtual void DoCleanup(int target_type, void* item)\r    {\r      }\r      \r       /** Validate parameters.\r        * Overridden by implementing module.\r   * @param source Source user adding the parameter\r       * @param channel Channel the parameter is being added to\r       * @param parameter The actual parameter being added\r    * @return true if the parameter is valid\r       */\r    virtual bool ValidateParam(userrec* source, chanrec* channel, std::string &parameter)\r  {\r              return true;\r   }\r      \r       /** Tell the user the list is too long.\r         * Overridden by implementing module.\r   * @param source Source user adding the parameter\r       * @param channel Channel the parameter is being added to\r       * @param parameter The actual parameter being added\r    * @return Ignored\r      */\r    virtual bool TellListTooLong(userrec* source, chanrec* channel, std::string &parameter)\r        {\r              return false;\r  }\r      \r       /** Tell the user an item is already on the list.\r       * Overridden by implementing module.\r   * @param source Source user adding the parameter\r       * @param channel Channel the parameter is being added to\r       * @param parameter The actual parameter being added\r    */\r    virtual void TellAlreadyOnList(userrec* source, chanrec* channel, std::string &parameter)\r      {\r      }\r      \r       /** Tell the user that the parameter is not in the list.\r        * Overridden by implementing module.\r   * @param source Source user removing the parameter\r     * @param channel Channel the parameter is being removed from\r   * @param parameter The actual parameter being removed\r  */\r    virtual void TellNotSet(userrec* source, chanrec* channel, std::string &parameter)\r     {\r      }\r};\r\r#endif\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef INSPIRCD_LISTMODE_PROVIDER
+#define INSPIRCD_LISTMODE_PROVIDER
+
+#include <stdio.h>
+#include <string>
+#include <sstream>
+#include <vector>
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+#include "wildcard.h"
+#include "inspircd.h"
+
+/* Updated to use the <banlist> config tag if it exists
+ * Written by Om <omster@gmail.com>, December 2005.
+ * Based on code previously written by Om - April 2005
+ * Updated to new API July 8th 2006 by Brain
+ * Originally based on m_chanprotect and m_silence
+ */
+
+/** Get the time as a string
+ */
+inline std::string stringtime()
+{
+       std::ostringstream TIME;
+       TIME << time(NULL); 
+       return TIME.str();
+}
+
+/** An item in a listmode's list
+ */
+class ListItem : public classbase
+{
+public:
+       std::string nick;
+       irc::string mask;
+       std::string time;
+};
+
+/** The number of items a listmode's list may contain
+ */
+class ListLimit : public classbase
+{
+public:
+       std::string mask;
+       unsigned int limit;
+};
+
+/** Items stored in the channel's list
+ */
+typedef std::vector<ListItem> modelist;
+/** Max items per channel by name
+ */
+typedef std::vector<ListLimit> limitlist;
+
+/** A request used to check if a user is on a channel's list or not
+ */
+class ListModeRequest : public Request
+{
+ public:
+       userrec* user;
+       chanrec* chan;
+
+       /** Check if a user is on a channel's list.
+        * The Event::Send() event returns true if the user is on the channel's list.
+        * @param sender Sending module
+        * @param target Target module
+        * @param u User to check against
+        * @param c Channel to check against
+        */
+       ListModeRequest(Module* sender, Module* target, userrec* u, chanrec* c) : Request(sender, target, "LM_CHECKLIST"), user(u), chan(c)
+       {
+       }
+
+       /** Destructor
+        */
+       ~ListModeRequest()
+       {
+       }
+};
+
+/** The base class for list modes, should be inherited.
+ */
+class ListModeBase : public ModeHandler
+{
+ protected:
+       /** Storage key
+        */
+       std::string infokey;
+       /** Numeric to use when outputting the list
+        */
+       std::string listnumeric;
+       /** Numeric to indicate end of list
+        */
+       std::string endoflistnumeric;
+       /** String to send for end of list
+        */
+       std::string endofliststring;
+       /** Automatically tidy up entries
+        */
+       bool tidy;
+       /** Config tag to check for max items per channel
+        */
+       std::string configtag;
+       /** Limits on a per-channel basis read from the tag
+        * specified in ListModeBase::configtag
+        */
+       limitlist chanlimits;
+ public:
+       /** Constructor.
+        * @param Instance The creator of this class
+        * @param modechar Mode character
+        * @param eolstr End of list string
+        * @pram lnum List numeric
+        * @param eolnum End of list numeric
+        * @param autotidy Automatically tidy list entries on add
+        * @param ctag Configuration tag to get limits from
+        */
+       ListModeBase(InspIRCd* Instance, char modechar, const std::string &eolstr, const std::string &lnum, const std::string &eolnum, bool autotidy, const std::string &ctag = "banlist")
+       : ModeHandler(Instance, modechar, 1, 1, true, MODETYPE_CHANNEL, false), listnumeric(lnum), endoflistnumeric(eolnum), endofliststring(eolstr), tidy(autotidy), configtag(ctag)
+       {
+               this->DoRehash();
+               infokey = "listbase_mode_" + std::string(1, mode) + "_list";
+       }
+
+       /** See mode.h 
+        */
+       std::pair<bool,std::string> ModeSet(userrec* source, userrec* dest, chanrec* channel, const std::string &parameter)
+       {
+               modelist* el;
+               channel->GetExt(infokey, el);
+               if (el)
+               {
+                       for (modelist::iterator it = el->begin(); it != el->end(); it++)
+                       {
+                               if(parameter == it->mask)
+                               {
+                                       return std::make_pair(true, parameter);
+                               }
+                       }
+               }
+               return std::make_pair(false, parameter);
+       }
+
+       /** Display the list for this mode
+        * @param user The user to send the list to
+        * @param channel The channel the user is requesting the list for
+        */
+       virtual void DisplayList(userrec* user, chanrec* channel)
+       {
+               modelist* el;
+               channel->GetExt(infokey, el);
+               if (el)
+               {
+                       for (modelist::reverse_iterator it = el->rbegin(); it != el->rend(); ++it)
+                       {
+                               user->WriteServ("%s %s %s %s %s %s", listnumeric.c_str(), user->nick, channel->name, it->mask.c_str(), it->nick.c_str(), it->time.c_str());
+                       }
+               }
+               user->WriteServ("%s %s %s :%s", endoflistnumeric.c_str(), user->nick, channel->name, endofliststring.c_str());
+       }
+
+       /** Remove all instances of the mode from a channel.
+        * See mode.h
+        * @param channel The channel to remove all instances of the mode from
+        */
+       virtual void RemoveMode(chanrec* channel)
+       {
+               modelist* el;
+               channel->GetExt(infokey, el);
+               if (el)
+               {
+                       irc::modestacker modestack(false);
+                       std::deque<std::string> stackresult;
+                       const char* mode_junk[MAXMODES+2];
+                       mode_junk[0] = channel->name;
+                       userrec* n = new userrec(ServerInstance);
+                       n->SetFd(FD_MAGIC_NUMBER);
+                       for (modelist::iterator it = el->begin(); it != el->end(); it++)
+                       {
+                               modestack.Push(this->GetModeChar(), assign(it->mask));
+                       }
+                       while (modestack.GetStackedLine(stackresult))
+                       {
+                               for (size_t j = 0; j < stackresult.size(); j++)
+                               {
+                                       mode_junk[j+1] = stackresult[j].c_str();
+                               }
+                               ServerInstance->SendMode(mode_junk, stackresult.size() + 1, n);         
+                       }
+
+                       delete n;
+               }
+       }
+
+       /** See mode.h
+        */
+       virtual void RemoveMode(userrec* user)
+       {
+               /* Listmodes dont get set on users */
+       }
+
+       /** Perform a rehash of this mode's configuration data
+        */
+       virtual void DoRehash()
+       {
+               ConfigReader Conf(ServerInstance);
+
+               chanlimits.clear();
+
+               for (int i = 0; i < Conf.Enumerate(configtag); i++)
+               {
+                       // For each <banlist> tag
+                       ListLimit limit;
+                       limit.mask = Conf.ReadValue(configtag, "chan", i);
+                       limit.limit = Conf.ReadInteger(configtag, "limit", i, true);
+
+                       if (limit.mask.size() && limit.limit > 0)
+                               chanlimits.push_back(limit);
+               }
+               if (chanlimits.size() == 0)
+               {
+                       ListLimit limit;
+                       limit.mask = "*";
+                       limit.limit = 64;
+                       chanlimits.push_back(limit);
+               }
+       }
+
+       /** Populate the Implements list with the correct events for a List Mode
+        */
+       virtual void DoImplements(char* List)
+       {
+               List[I_OnChannelDelete] = List[I_OnSyncChannel] = List[I_OnCleanup] = List[I_OnRehash] = 1;
+       }
+
+       /** Handle the list mode.
+        * See mode.h
+        */
+       virtual ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)
+       {
+               // Try and grab the list
+               modelist* el;
+               channel->GetExt(infokey, el);
+
+               if (adding)
+               {
+                       // If there was no list
+                       if (!el)
+                       {
+                               // Make one
+                               el = new modelist;
+                               channel->Extend(infokey, el);
+                       }
+
+                       // Clean the mask up
+                       if (this->tidy)
+                               ModeParser::CleanMask(parameter);
+
+                       // Check if the item already exists in the list
+                       for (modelist::iterator it = el->begin(); it != el->end(); it++)
+                       {
+                               if (parameter == it->mask)
+                               {
+                                       /* Give a subclass a chance to error about this */
+                                       TellAlreadyOnList(source, channel, parameter);
+                                       
+                                       // it does, deny the change
+                                       return MODEACTION_DENY;
+                               }
+                       }
+
+                       unsigned int maxsize = 0;
+
+                       for (limitlist::iterator it = chanlimits.begin(); it != chanlimits.end(); it++)
+                       {
+                               if (match(channel->name, it->mask.c_str()))
+                               {
+                                       // We have a pattern matching the channel...
+                                       maxsize = el->size();
+                                       if (maxsize < it->limit)
+                                       {
+                                               /* Ok, it *could* be allowed, now give someone subclassing us
+                                                * a chance to validate the parameter.
+                                                * The param is passed by reference, so they can both modify it
+                                                * and tell us if we allow it or not.
+                                                *
+                                                * eg, the subclass could:
+                                                * 1) allow
+                                                * 2) 'fix' parameter and then allow
+                                                * 3) deny
+                                                */
+                                               if (ValidateParam(source, channel, parameter))
+                                               {
+                                                       // And now add the mask onto the list...
+                                                       ListItem e;
+                                                       e.mask = assign(parameter);
+                                                       e.nick = source->nick;
+                                                       e.time = stringtime();
+
+                                                       el->push_back(e);
+                                                       return MODEACTION_ALLOW;
+                                               }
+                                               else
+                                               {
+                                                       /* If they deny it they have the job of giving an error message */
+                                                       return MODEACTION_DENY;
+                                               }
+                                       }
+                               }
+                       }
+
+                       /* List is full, give subclass a chance to send a custom message */
+                       if (!TellListTooLong(source, channel, parameter))
+                       {
+                               source->WriteServ("478 %s %s %s :Channel ban/ignore list is full", source->nick, channel->name, parameter.c_str());
+                       }
+                       
+                       parameter = "";
+                       return MODEACTION_DENY; 
+               }
+               else
+               {
+                       // We're taking the mode off
+                       if (el)
+                       {
+                               for (modelist::iterator it = el->begin(); it != el->end(); it++)
+                               {
+                                       if (parameter == it->mask)
+                                       {
+                                               el->erase(it);
+                                               if (el->size() == 0)
+                                               {
+                                                       channel->Shrink(infokey);
+                                                       delete el;
+                                               }
+                                               return MODEACTION_ALLOW;
+                                       }
+                               }
+                               /* Tried to remove something that wasn't set */
+                               TellNotSet(source, channel, parameter);
+                               parameter = "";
+                               return MODEACTION_DENY;
+                       }
+                       else
+                       {
+                               /* Hmm, taking an exception off a non-existant list, DIE */
+                               TellNotSet(source, channel, parameter);
+                               parameter = "";
+                               return MODEACTION_DENY;
+                       }
+               }
+               return MODEACTION_DENY;
+       }
+
+       /** Get Extensible key for this mode
+        */
+       virtual std::string& GetInfoKey()
+       {
+               return infokey;
+       }
+
+       /** Handle channel deletion.
+        * See modules.h.
+        * @param chan Channel being deleted
+        */
+       virtual void DoChannelDelete(chanrec* chan)
+       {
+               modelist* list;
+               chan->GetExt(infokey, list);
+
+               if (list)
+               {
+                       chan->Shrink(infokey);
+                       delete list;
+               }
+       }
+
+       /** Syncronize channel item list with another server.
+        * See modules.h
+        * @param chan Channel to syncronize
+        * @param proto Protocol module pointer
+        * @param opaque Opaque connection handle
+        */
+       virtual void DoSyncChannel(chanrec* chan, Module* proto, void* opaque)
+       {
+               modelist* list;
+               chan->GetExt(infokey, list);
+               irc::modestacker modestack(true);
+               std::deque<std::string> stackresult;
+               if (list)
+               {
+                       for (modelist::iterator it = list->begin(); it != list->end(); it++)
+                       {
+                               modestack.Push(std::string(1, mode)[0], assign(it->mask));
+                       }
+               }
+               while (modestack.GetStackedLine(stackresult))
+               {
+                       irc::stringjoiner mode_join(" ", stackresult, 0, stackresult.size() - 1);
+                       std::string line = mode_join.GetJoined();
+                       proto->ProtoSendMode(opaque, TYPE_CHANNEL, chan, line);
+               }
+       }
+
+       /** Clean up module on unload
+        * @param target_type Type of target to clean
+        * @param item Item to clean
+        */
+       virtual void DoCleanup(int target_type, void* item)
+       {
+       }
+       
+       /** Validate parameters.
+        * Overridden by implementing module.
+        * @param source Source user adding the parameter
+        * @param channel Channel the parameter is being added to
+        * @param parameter The actual parameter being added
+        * @return true if the parameter is valid
+        */
+       virtual bool ValidateParam(userrec* source, chanrec* channel, std::string &parameter)
+       {
+               return true;
+       }
+       
+       /** Tell the user the list is too long.
+        * Overridden by implementing module.
+        * @param source Source user adding the parameter
+        * @param channel Channel the parameter is being added to
+        * @param parameter The actual parameter being added
+        * @return Ignored
+        */
+       virtual bool TellListTooLong(userrec* source, chanrec* channel, std::string &parameter)
+       {
+               return false;
+       }
+       
+       /** Tell the user an item is already on the list.
+        * Overridden by implementing module.
+        * @param source Source user adding the parameter
+        * @param channel Channel the parameter is being added to
+        * @param parameter The actual parameter being added
+        */
+       virtual void TellAlreadyOnList(userrec* source, chanrec* channel, std::string &parameter)
+       {
+       }
+       
+       /** Tell the user that the parameter is not in the list.
+        * Overridden by implementing module.
+        * @param source Source user removing the parameter
+        * @param channel Channel the parameter is being removed from
+        * @param parameter The actual parameter being removed
+        */
+       virtual void TellNotSet(userrec* source, chanrec* channel, std::string &parameter)
+       {
+       }
+};
+
+#endif
+
index 7420cc42f2aacff04bfd91e9af19fb5b3566a16d..0443b24d23493a9e6cef827fe5aa278042956ec7 100644 (file)
@@ -1 +1,1031 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __USERS_H__\r#define __USERS_H__\r\r#include <string>\r#include "inspircd_config.h"\r#include "socket.h"\r#include "channels.h"\r#include "inspstring.h"\r#include "connection.h"\r#include "hashcomp.h"\r#include "dns.h"\r\r/** Channel status for a user\r */\renum ChanStatus {\r     /** Op */\r      STATUS_OP     = 4,\r     /** Halfop */\r  STATUS_HOP    = 2,\r     /** Voice */\r   STATUS_VOICE  = 1,\r     /** None */\r    STATUS_NORMAL = 0\r};\r\r/** connect class types\r */\renum ClassTypes {\r    /** connect:allow */\r   CC_ALLOW = 0,\r  /** connect:deny */\r    CC_DENY  = 1\r};\r\r/** RFC1459 channel modes\r */\renum UserModes {\r        /** +s: Server notices */\r      UM_SERVERNOTICE = 's' - 65,\r    /** +w: WALLOPS */\r     UM_WALLOPS = 'w' - 65,\r /** +i: Invisible */\r   UM_INVISIBLE = 'i' - 65,\r       /** +o: Operator */\r    UM_OPERATOR = 'o' - 65,\r        /** +n: Server notice mask */\r  UM_SNOMASK = 'n' - 65\r};\r\r/** Registration state of a user, e.g.\r * have they sent USER, NICK, PASS yet?\r */\renum RegistrationState {\r\r#ifndef WIN32   // Burlex: This is already defined in win32, luckily it is still 0.\r     REG_NONE = 0,           /* Has sent nothing */\r#endif\r\r REG_USER = 1,           /* Has sent USER */\r    REG_NICK = 2,           /* Has sent NICK */\r    REG_NICKUSER = 3,       /* Bitwise combination of REG_NICK and REG_USER */\r     REG_ALL = 7             /* REG_NICKUSER plus next bit along */\r};\r\r/* Required forward declaration */\rclass InspIRCd;\r\r/** Derived from Resolver, and performs user forward/reverse lookups.\r */\rclass CoreExport UserResolver : public Resolver\r{\r private:\r   /** User this class is 'attached' to.\r   */\r    userrec* bound_user;\r   /** File descriptor teh lookup is bound to\r      */\r    int bound_fd;\r  /** True if the lookup is forward, false if is a reverse lookup\r         */\r    bool fwd;\r public:\r     /** Create a resolver.\r  * @param Instance The creating instance\r        * @param user The user to begin lookup on\r      * @param to_resolve The IP or host to resolve\r  * @param qt The query type\r     * @param cache Modified by the constructor if the result was cached\r    */\r    UserResolver(InspIRCd* Instance, userrec* user, std::string to_resolve, QueryType qt, bool &cache);\r\r   /** Called on successful lookup\r         * @param result Result string\r  * @param ttl Time to live for result\r   * @param cached True if the result was found in the cache\r      */\r    void OnLookupComplete(const std::string &result, unsigned int ttl, bool cached);\r\r      /** Called on failed lookup\r     * @param e Error code\r  * @param errormessage Error message string\r     */\r    void OnError(ResolverError e, const std::string &errormessage);\r};\r\r\r/** Holds information relevent to &lt;connect allow&gt; and &lt;connect deny&gt; tags in the config file.\r */\rclass CoreExport ConnectClass : public classbase\r{\r private:\r        /** Type of line, either CC_ALLOW or CC_DENY\r    */\r    char type;\r     /** Max time to register the connection in seconds\r      */\r    unsigned int registration_timeout;\r     /** Number of lines in buffer before excess flood is triggered\r  */\r    unsigned int flood;\r    /** Host mask for this line\r     */\r    std::string host;\r      /** Number of seconds between pings for this line\r       */\r    unsigned int pingtime;\r /** (Optional) Password for this line\r   */\r    std::string pass;\r\r     /** Threshold value for flood disconnect\r        */\r    unsigned int threshold;\r\r       /** Maximum size of sendq for users in this class (bytes)\r       */\r    unsigned long sendqmax;\r\r       /** Maximum size of recvq for users in this class (bytes)\r       */\r    unsigned long recvqmax;\r\r       /** Local max when connecting by this connection class\r  */\r    unsigned long maxlocal;\r\r       /** Global max when connecting by this connection class\r         */\r    unsigned long maxglobal;\r       /** Port number this connect class applies to\r   */\r    int port;\r\rpublic:\r\r    /** Create a new connect class with no settings.\r        */\r    ConnectClass() : type(CC_DENY), registration_timeout(0), flood(0), host(""), pingtime(0), pass(""),\r                    threshold(0), sendqmax(0), recvqmax(0), maxlocal(0), maxglobal(0) { }\r\r /** Create a new connect class to ALLOW connections.\r    * @param timeout The registration timeout\r      * @param fld The flood value\r   * @param hst The IP mask to allow\r      * @param ping The ping frequency\r       * @param pas The password to be used\r   * @param thres The flooding threshold\r  * @param sendq The maximum sendq value\r         * @param recvq The maximum recvq value\r         * @param maxl The maximum local sessions\r       * @param maxg The maximum global sessions\r      */\r    ConnectClass(unsigned int timeout, unsigned int fld, const std::string &hst, unsigned int ping,\r                        const std::string &pas, unsigned int thres, unsigned long sendq, unsigned long recvq,\r                  unsigned long maxl, unsigned long maxg, int p = 0) :\r                   type(CC_ALLOW), registration_timeout(timeout), flood(fld), host(hst), pingtime(ping), pass(pas),\r                       threshold(thres), sendqmax(sendq), recvqmax(recvq), maxlocal(maxl), maxglobal(maxg), port(p) { }\r\r      /** Create a new connect class to DENY  connections\r     * @param hst The IP mask to deny\r       */\r    ConnectClass(const std::string &hst) : type(CC_DENY), registration_timeout(0), flood(0), host(hst), pingtime(0),\r                       pass(""), threshold(0), sendqmax(0), recvqmax(0), maxlocal(0), maxglobal(0), port(0) { }\r\r      /** Returns the type, CC_ALLOW or CC_DENY\r       */\r    char GetType()\r {\r              return (type == CC_ALLOW ? CC_ALLOW : CC_DENY);\r        }\r\r     /** Returns the registration timeout\r    */\r    unsigned int GetRegTimeout()\r   {\r              return (registration_timeout ? registration_timeout : 90);\r     }\r\r     /** Returns the flood limit\r     */\r    unsigned int GetFlood()\r        {\r              return (threshold ? flood : 999);\r      }\r\r     /** Returns the allowed or denied IP mask\r       */\r    const std::string& GetHost()\r   {\r              return host;\r   }\r\r     int GetPort()\r  {\r              return port;\r   }\r\r     /** Returns the ping frequency\r  */\r    unsigned int GetPingTime()\r     {\r              return (pingtime ? pingtime : 120);\r    }\r\r     /** Returns the password or an empty string\r     */\r    const std::string& GetPass()\r   {\r              return pass;\r   }\r\r     /** Returns the flood threshold value\r   */\r    unsigned int GetThreshold()\r    {\r              return (threshold ? threshold : 1);\r    }\r\r     /** Returns the maximum sendq value\r     */\r    unsigned long GetSendqMax()\r    {\r              return (sendqmax ? sendqmax : 262114);\r }\r\r     /** Returns the maximum recvq value\r     */\r    unsigned long GetRecvqMax()\r    {\r              return (recvqmax ? recvqmax : 4096);\r   }\r\r     /** Returusn the maximum number of local sessions\r       */\r    unsigned long GetMaxLocal()\r    {\r              return maxlocal;\r       }\r\r     /** Returns the maximum number of global sessions\r       */\r    unsigned long GetMaxGlobal()\r   {\r              return maxglobal;\r      }\r};\r\r/** Holds a complete list of all channels to which a user has been invited and has not yet joined.\r */\rtypedef std::vector<irc::string> InvitedList;\r\r/** Holds a complete list of all allow and deny tags from the configuration file (connection classes)\r */\rtypedef std::vector<ConnectClass> ClassVector;\r\r/** Typedef for the list of user-channel records for a user\r */\rtypedef std::map<chanrec*, char> UserChanList;\r\r/** Shorthand for an iterator into a UserChanList\r */\rtypedef UserChanList::iterator UCListIter;\r\r/* Required forward declaration\r */\rclass userrec;\r\r/** Visibility data for a user.\r * If a user has a non-null instance of this class in their userrec,\r * then it is used to determine if this user is visible to other users\r * or not.\r */\rclass CoreExport VisData\r{\r public:\r     /** Create a visdata\r    */\r    VisData();\r     /** Destroy a visdata\r   */\r    virtual ~VisData();\r    /** Is this user visible to some other user?\r    * @param user The other user to compare to\r     * @return true True if the user is visible to the other user, false if not\r     */\r    virtual bool VisibleTo(userrec* user);\r};\r\r/** Holds all information about a user\r * This class stores all information about a user connected to the irc server. Everything about a\r * connection is stored here primarily, from the user's socket ID (file descriptor) through to the\r * user's nickname and hostname. Use the FindNick method of the InspIRCd class to locate a specific user\r * by nickname, or the FindDescriptor method of the InspIRCd class to find a specific user by their\r * file descriptor value.\r */\rclass CoreExport userrec : public connection\r{\r private:\r     /** Pointer to creator.\r         * This is required to make use of core functions\r       * from within the userrec class.\r       */\r    InspIRCd* ServerInstance;\r\r     /** A list of channels the user has a pending invite to.\r        * Upon INVITE channels are added, and upon JOIN, the\r   * channels are removed from this list.\r         */\r    InvitedList invites;\r\r  /** Number of channels this user is currently on\r        */\r    unsigned int ChannelCount;\r\r    /** Cached nick!ident@host value using the real hostname\r        */\r    char* cached_fullhost;\r\r        /** Cached nick!ident@ip value using the real IP address\r        */\r    char* cached_hostip;\r\r  /** Cached nick!ident@host value using the masked hostname\r      */\r    char* cached_makehost;\r\r        /** Cached nick!ident@realhost value using the real hostname\r    */\r    char* cached_fullrealhost;\r\r    /** When we erase the user (in the destructor),\r         * we call this method to subtract one from all\r         * mode characters this user is making use of.\r  */\r    void DecrementModes();\r\r        /** Oper-only quit message for this user if non-null\r    */\r    char* operquit;\r\r public:\r      /** Resolvers for looking up this users IP address\r      * This will occur if and when res_reverse completes.\r   * When this class completes its lookup, userrec::dns_done\r      * will be set from false to true.\r      */\r    UserResolver* res_forward;\r\r    /** Resolvers for looking up this users hostname\r        * This is instantiated by userrec::StartDNSLookup(),\r   * and on success, instantiates userrec::res_reverse.\r   */\r    UserResolver* res_reverse;\r\r    /** User visibility state, see definition of VisData.\r   */\r    VisData* Visibility;\r\r  /** Stored reverse lookup from res_forward\r      */\r    std::string stored_host;\r\r      /** Starts a DNS lookup of the user's IP.\r       * This will cause two UserResolver classes to be instantiated.\r         * When complete, these objects set userrec::dns_done to true.\r  */\r    void StartDNSLookup();\r\r        /** The users nickname.\r         * An invalid nickname indicates an unregistered connection prior to the NICK command.\r  * Use InspIRCd::IsNick() to validate nicknames.\r        */\r    char nick[NICKMAX];\r\r   /** The users ident reply.\r      * Two characters are added to the user-defined limit to compensate for the tilde etc.\r  */\r    char ident[IDENTMAX+2];\r\r       /** The host displayed to non-opers (used for cloaking etc).\r    * This usually matches the value of userrec::host.\r     */\r    char dhost[65];\r\r       /** The users full name (GECOS).\r        */\r    char fullname[MAXGECOS+1];\r\r    /** The user's mode list.\r       * This is NOT a null terminated string! In the 1.1 version of InspIRCd\r         * this is an array of values in a similar way to channel modes.\r        * A value of 1 in field (modeletter-65) indicates that the mode is\r     * set, for example, to work out if mode +s is set, we  check the field\r         * userrec::modes['s'-65] != 0.\r         * The following RFC characters o, w, s, i have constants defined via an\r        * enum, such as UM_SERVERNOTICE and UM_OPETATOR.\r       */\r    char modes[64];\r\r       /** What snomasks are set on this user.\r         * This functions the same as the above modes.\r  */\r    char snomasks[64];\r\r    /** Channels this user is on, and the permissions they have there\r       */\r    UserChanList chans;\r\r   /** The server the user is connected to.\r        */\r    const char* server;\r\r   /** The user's away message.\r    * If this string is empty, the user is not marked as away.\r     */\r    char awaymsg[MAXAWAY+1];\r\r      /** Number of lines the user can place into the buffer\r  * (up to the global NetBufferSize bytes) before they\r   * are disconnected for excess flood\r    */\r    int flood;\r\r    /** Timestamp of current time + connection class timeout.\r       * This user must send USER/NICK before this timestamp is\r       * reached or they will be disconnected.\r        */\r    time_t timeout;\r\r       /** The oper type they logged in as, if they are an oper.\r       * This is used to check permissions in operclasses, so that\r    * we can say 'yay' or 'nay' to any commands they issue.\r        * The value of this is the value of a valid 'type name=' tag.\r  */\r    char oper[NICKMAX];\r\r   /** True when DNS lookups are completed.\r        * The UserResolver classes res_forward and res_reverse will\r    * set this value once they complete.\r   */\r    bool dns_done;\r\r        /** Number of seconds between PINGs for this user (set from &lt;connect:allow&gt; tag\r   */\r    unsigned int pingmax;\r\r /** Password specified by the user when they registered.\r        * This is stored even if the <connect> block doesnt need a password, so that\r   * modules may check it.\r        */\r    char password[64];\r\r    /** User's receive queue.\r       * Lines from the IRCd awaiting processing are stored here.\r     * Upgraded april 2005, old system a bit hairy.\r         */\r    std::string recvq;\r\r    /** User's send queue.\r  * Lines waiting to be sent are stored here until their buffer is flushed.\r      */\r    std::string sendq;\r\r    /** Flood counters - lines received\r     */\r    int lines_in;\r\r /** Flood counters - time lines_in is due to be reset\r   */\r    time_t reset_due;\r\r     /** Flood counters - Highest value lines_in may reach before the user gets disconnected\r         */\r    long threshold;\r\r       /** If this is set to true, then all read operations for the user\r       * are dropped into the bit-bucket.\r     * This is used by the global CullList, but please note that setting this value\r         * alone will NOT cause the user to quit. This means it can be used seperately,\r         * for example by shun modules etc.\r     */\r    bool muted;\r\r   /** IPV4 or IPV6 ip address. Use SetSockAddr to set this and GetProtocolFamily/\r         * GetIPString/GetPort to obtain its values.\r    */\r    sockaddr* ip;\r\r /** Initialize the clients sockaddr\r     * @param protocol_family The protocol family of the IP address, AF_INET or AF_INET6\r    * @param ip A human-readable IP address for this user matching the protcol_family\r      * @param port The port number of this user or zero for a remote user\r   */\r    void SetSockAddr(int protocol_family, const char* ip, int port);\r\r      /** Get port number from sockaddr\r       * @return The port number of this user.\r        */\r    int GetPort();\r\r        /** Get protocol family from sockaddr\r   * @return The protocol family of this user, either AF_INET or AF_INET6\r         */\r    int GetProtocolFamily();\r\r      /** Get IP string from sockaddr, using static internal buffer\r   * @return The IP string\r        */\r    const char* GetIPString();\r\r    /** Get IP string from sockaddr, using caller-specified buffer\r  * @param buf A buffer to use\r   * @return The IP string\r        */\r    const char* GetIPString(char* buf);\r\r   /* Write error string\r   */\r    std::string WriteError;\r\r       /** Maximum size this user's sendq can become.\r  * Copied from the connect class on connect.\r    */\r    long sendqmax;\r\r        /** Maximum size this user's recvq can become.\r  * Copied from the connect class on connect.\r    */\r    long recvqmax;\r\r        /** This is true if the user matched an exception when they connected to the ircd.\r      * It isnt valid after this point, and you should not attempt to do anything with it\r    * after this point, because the eline might be removed at a later time, and/or no\r      * longer be applicable to this user. It is only used to save doing the eline lookup\r    * twice (instead we do it once and set this value).\r    */\r    bool exempt;\r\r  /** Default constructor\r         * @throw Nothing at present\r    */\r    userrec(InspIRCd* Instance);\r\r  /** Returns the full displayed host of the user\r         * This member function returns the hostname of the user as seen by other users\r         * on the server, in nick!ident&at;host form.\r   * @return The full masked host of the user\r     */\r    virtual char* GetFullHost();\r\r  /** Returns the full real host of the user\r      * This member function returns the hostname of the user as seen by other users\r         * on the server, in nick!ident&at;host form. If any form of hostname cloaking is in operation,\r         * e.g. through a module, then this method will ignore it and return the true hostname.\r         * @return The full real host of the user\r       */\r    virtual char* GetFullRealHost();\r\r      /** This clears any cached results that are used for GetFullRealHost() etc.\r     * The results of these calls are cached as generating them can be generally expensive.\r         */\r    void InvalidateCache();\r\r       /** Create a displayable mode string for this users snomasks\r    * @return The notice mask character sequence\r   */\r    const char* FormatNoticeMasks();\r\r      /** Process a snomask modifier string, e.g. +abc-de\r     * @param sm A sequence of notice mask characters\r       * @return The cleaned mode sequence which can be output,\r       * e.g. in the above example if masks c and e are not\r   * valid, this function will return +ab-d\r       */\r    std::string ProcessNoticeMasks(const char *sm);\r\r       /** Returns true if a notice mask is set\r        * @param sm A notice mask character to check\r   * @return True if the notice mask is set\r       */\r    bool IsNoticeMaskSet(unsigned char sm);\r\r       /** Changed a specific notice mask value\r        * @param sm The server notice mask to change\r   * @param value An on/off value for this mask\r   */\r    void SetNoticeMask(unsigned char sm, bool value);\r\r     /** Create a displayable mode string for this users umodes\r      * @param The mode string\r       */\r    const char* FormatModes();\r\r    /** Returns true if a specific mode is set\r      * @param m The user mode\r       * @return True if the mode is set\r      */\r    bool IsModeSet(unsigned char m);\r\r      /** Set a specific usermode to on or off\r        * @param m The user mode\r       * @param value On or off setting of the mode\r   */\r    void SetMode(unsigned char m, bool value);\r\r    /** Returns true if a user is invited to a channel.\r     * @param channel A channel name to look up\r     * @return True if the user is invited to the given channel\r     */\r    virtual bool IsInvited(const irc::string &channel);\r\r   /** Adds a channel to a users invite list (invites them to a channel)\r   * @param channel A channel name to add\r         */\r    virtual void InviteTo(const irc::string &channel);\r\r    /** Removes a channel from a users invite list.\r         * This member function is called on successfully joining an invite only channel\r        * to which the user has previously been invited, to clear the invitation.\r      * @param channel The channel to remove the invite to\r   */\r    virtual void RemoveInvite(const irc::string &channel);\r\r        /** Returns true or false for if a user can execute a privilaged oper command.\r  * This is done by looking up their oper type from userrec::oper, then referencing\r      * this to their oper classes and checking the commands they can execute.\r       * @param command A command (should be all CAPS)\r        * @return True if this user can execute the command\r    */\r    bool HasPermission(const std::string &command);\r\r       /** Calls read() to read some data for this user using their fd.\r        * @param buffer The buffer to read into\r        * @param size The size of data to read\r         * @return The number of bytes read, or -1 if an error occured.\r         */\r    int ReadData(void* buffer, size_t size);\r\r      /** This method adds data to the read buffer of the user.\r       * The buffer can grow to any size within limits of the available memory,\r       * managed by the size of a std::string, however if any individual line in\r      * the buffer grows over 600 bytes in length (which is 88 chars over the\r        * RFC-specified limit per line) then the method will return false and the\r      * text will not be inserted.\r   * @param a The string to add to the users read buffer\r  * @return True if the string was successfully added to the read buffer\r         */\r    bool AddBuffer(std::string a);\r\r        /** This method returns true if the buffer contains at least one carriage return\r        * character (e.g. one complete line may be read)\r       * @return True if there is at least one complete line in the users buffer\r      */\r    bool BufferIsReady();\r\r /** This function clears the entire buffer by setting it to an empty string.\r    */\r    void ClearBuffer();\r\r   /** This method returns the first available string at the tail end of the buffer\r        * and advances the tail end of the buffer past the string. This means it is\r    * a one way operation in a similar way to strtok(), and multiple calls return\r  * multiple lines if they are available. The results of this function if there\r  * are no lines to be read are unknown, always use BufferIsReady() to check if\r  * it is ok to read the buffer before calling GetBuffer().\r      * @return The string at the tail end of this users buffer\r      */\r    std::string GetBuffer();\r\r      /** Sets the write error for a connection. This is done because the actual disconnect\r   * of a client may occur at an inopportune time such as half way through /LIST output.\r  * The WriteErrors of clients are checked at a more ideal time (in the mainloop) and\r    * errored clients purged.\r      * @param error The error string to set.\r        */\r    void SetWriteError(const std::string &error);\r\r /** Returns the write error which last occured on this connection or an empty string\r    * if none occured.\r     * @return The error string which has occured for this user\r     */\r    const char* GetWriteError();\r\r  /** Adds to the user's write buffer.\r    * You may add any amount of text up to this users sendq value, if you exceed the\r       * sendq value, SetWriteError() will be called to set the users error string to\r         * "SendQ exceeded", and further buffer adds will be dropped.\r   * @param data The data to add to the write buffer\r      */\r    void AddWriteBuf(const std::string &data);\r\r    /** Flushes as much of the user's buffer to the file descriptor as possible.\r    * This function may not always flush the entire buffer, rather instead as much of it\r   * as it possibly can. If the send() call fails to send the entire buffer, the buffer\r   * position is advanced forwards and the rest of the data sent at the next call to\r      * this method.\r         */\r    void FlushWriteBuf();\r\r /** Returns the list of channels this user has been invited to but has not yet joined.\r  * @return A list of channels the user is invited to\r    */\r    InvitedList* GetInviteList();\r\r /** Creates a wildcard host.\r    * Takes a buffer to use and fills the given buffer with the host in the format *!*@hostname\r    * @return The wildcarded hostname in *!*@host form\r     */\r    char* MakeWildHost();\r\r /** Creates a usermask with real host.\r  * Takes a buffer to use and fills the given buffer with the hostmask in the format user@host\r   * @return the usermask in the format user@host\r         */\r    char* MakeHost();\r\r     /** Creates a usermask with real ip.\r    * Takes a buffer to use and fills the given buffer with the ipmask in the format user@ip\r       * @return the usermask in the format user@ip\r   */\r    char* MakeHostIP();\r\r   /** Shuts down and closes the user's socket\r     * This will not cause the user to be deleted. Use InspIRCd::QuitUser for this,\r         * which will call CloseSocket() for you.\r       */\r    void CloseSocket();\r\r   /** Disconnect a user gracefully\r        * @param user The user to remove\r       * @param r The quit reason to show to normal users\r     * @param oreason The quit reason to show to opers\r      * @return Although this function has no return type, on exit the user provided will no longer exist.\r   */\r    static void QuitUser(InspIRCd* Instance, userrec *user, const std::string &r, const char* oreason = "");\r\r      /** Add the user to WHOWAS system\r       */\r    void AddToWhoWas();\r\r   /** Oper up the user using the given opertype.\r  * This will also give the +o usermode.\r         * @param opertype The oper type to oper as\r     */\r    void Oper(const std::string &opertype);\r\r       /** Call this method to find the matching <connect> for a user, and to check them against it.\r   */\r    void CheckClass();\r\r    /** Use this method to fully connect a user.\r    * This will send the message of the day, check G/K/E lines, etc.\r       */\r    void FullConnect();\r\r   /** Change this users hash key to a new string.\r         * You should not call this function directly. It is used by the core\r   * to update the users hash entry on a nickchange.\r      * @param New new user_hash key\r         * @return Pointer to userrec in hash (usually 'this')\r  */\r    userrec* UpdateNickHash(const char* New);\r\r     /** Force a nickname change.\r    * If the nickname change fails (for example, because the nick in question\r      * already exists) this function will return false, and you must then either\r    * output an error message, or quit the user for nickname collision.\r    * @param newnick The nickname to change to\r     * @return True if the nickchange was successful.\r       */\r    bool ForceNickChange(const char* newnick);\r\r    /** Add a client to the system.\r         * This will create a new userrec, insert it into the user_hash,\r        * initialize it as not yet registered, and add it to the socket engine.\r        * @param Instance a pointer to the server instance\r     * @param socket The socket id (file descriptor) this user is on\r        * @param port The port number this user connected on\r   * @param iscached This variable is reserved for future use\r     * @param ip The IP address of the user\r         * @return This function has no return value, but a call to AddClient may remove the user.\r      */\r    static void AddClient(InspIRCd* Instance, int socket, int port, bool iscached, int socketfamily, sockaddr* ip);\r\r       /** Oper down.\r  * This will clear the +o usermode and unset the user's oper type\r       */\r    void UnOper();\r\r        /** Return the number of global clones of this user\r     * @return The global clone count of this user\r  */\r    unsigned long GlobalCloneCount();\r\r     /** Return the number of local clones of this user\r      * @return The local clone count of this user\r   */\r    unsigned long LocalCloneCount();\r\r      /** Remove all clone counts from the user, you should\r   * use this if you change the user's IP address in\r      * userrec::ip after they have registered.\r      */\r    void RemoveCloneCounts();\r\r     /** Write text to this user, appending CR/LF.\r   * @param text A std::string to send to the user\r        */\r    void Write(std::string text);\r\r /** Write text to this user, appending CR/LF.\r   * @param text The format string for text to send to the user\r   * @param ... POD-type format arguments\r         */\r    void Write(const char *text, ...);\r\r    /** Write text to this user, appending CR/LF and prepending :server.name\r        * @param text A std::string to send to the user\r        */\r    void WriteServ(const std::string& text);\r\r      /** Write text to this user, appending CR/LF and prepending :server.name\r        * @param text The format string for text to send to the user\r   * @param ... POD-type format arguments\r         */\r    void WriteServ(const char* text, ...);\r\r        /** Write text to this user, appending CR/LF and prepending :nick!user@host of the user provided in the first parameter.\r        * @param user The user to prepend the :nick!user@host of\r       * @param text A std::string to send to the user\r        */\r    void WriteFrom(userrec *user, const std::string &text);\r\r       /** Write text to this user, appending CR/LF and prepending :nick!user@host of the user provided in the first parameter.\r        * @param user The user to prepend the :nick!user@host of\r       * @param text The format string for text to send to the user\r   * @param ... POD-type format arguments\r         */\r    void WriteFrom(userrec *user, const char* text, ...);\r\r /** Write text to the user provided in the first parameter, appending CR/LF, and prepending THIS user's :nick!user@host.\r        * @param dest The user to route the message to\r         * @param text A std::string to send to the user\r        */\r    void WriteTo(userrec *dest, const std::string &data);\r\r /** Write text to the user provided in the first parameter, appending CR/LF, and prepending THIS user's :nick!user@host.\r        * @param dest The user to route the message to\r         * @param text The format string for text to send to the user\r   * @param ... POD-type format arguments\r         */\r    void WriteTo(userrec *dest, const char *data, ...);\r\r   /** Write to all users that can see this user (including this user in the list), appending CR/LF\r        * @param text A std::string to send to the users\r       */\r    void WriteCommon(const std::string &text);\r\r    /** Write to all users that can see this user (including this user in the list), appending CR/LF\r        * @param text The format string for text to send to the users\r  * @param ... POD-type format arguments\r         */\r    void WriteCommon(const char* text, ...);\r\r      /** Write to all users that can see this user (not including this user in the list), appending CR/LF\r    * @param text The format string for text to send to the users\r  * @param ... POD-type format arguments\r         */\r    void WriteCommonExcept(const char* text, ...);\r\r        /** Write to all users that can see this user (not including this user in the list), appending CR/LF\r    * @param text A std::string to send to the users\r       */\r    void WriteCommonExcept(const std::string &text);\r\r      /** Write a quit message to all common users, as in userrec::WriteCommonExcept but with a specific\r      * quit message for opers only.\r         * @param normal_text Normal user quit message\r  * @param oper_text Oper only quit message\r      */\r    void WriteCommonQuit(const std::string &normal_text, const std::string &oper_text);\r\r   /** Write a WALLOPS message from this user to all local opers.\r  * If this user is not opered, the function will return without doing anything.\r         * @param text The format string to send in the WALLOPS message\r         * @param ... Format arguments\r  */\r    void WriteWallOps(const char* text, ...);\r\r     /** Write a WALLOPS message from this user to all local opers.\r  * If this user is not opered, the function will return without doing anything.\r         * @param text The text to send in the WALLOPS message\r  */\r    void WriteWallOps(const std::string &text);\r\r   /** Return true if the user shares at least one channel with another user\r       * @param other The other user to compare the channel list against\r      * @return True if the given user shares at least one channel with this user\r    */\r    bool SharesChannelWith(userrec *other);\r\r       /** Change the displayed host of a user.\r        * ALWAYS use this function, rather than writing userrec::dhost directly,\r       * as this triggers module events allowing the change to be syncronized to\r      * remote servers. This will also emulate a QUIT and rejoin (where configured)\r  * before setting their host field.\r     * @param host The new hostname to set\r  * @return True if the change succeeded, false if it didn't\r     */\r    bool ChangeDisplayedHost(const char* host);\r\r   /** Change the ident (username) of a user.\r      * ALWAYS use this function, rather than writing userrec::ident directly,\r       * as this correctly causes the user to seem to quit (where configured)\r         * before setting their ident field.\r    * @param host The new ident to set\r     * @return True if the change succeeded, false if it didn't\r     */\r    bool ChangeIdent(const char* newident);\r\r       /** Change a users realname field.\r      * ALWAYS use this function, rather than writing userrec::fullname directly,\r    * as this triggers module events allowing the change to be syncronized to\r      * remote servers.\r      * @param gecos The user's new realname\r         * @return True if the change succeeded, false if otherwise\r     */\r    bool ChangeName(const char* gecos);\r\r   /** Send a command to all local users from this user\r    * The command given must be able to send text with the\r         * first parameter as a servermask (e.g. $*), so basically\r      * you should use PRIVMSG or NOTICE.\r    * @param command the command to send\r   * @param text The text format string to send\r   * @param ... Format arguments\r  */\r    void SendAll(const char* command, char* text, ...);\r\r   /** Compile a channel list for this user, and send it to the user 'source'\r      * Used internally by WHOIS\r     * @param The user to send the channel list to if it is not too long\r    * @return This user's channel list\r     */\r    std::string ChannelList(userrec* source);\r\r     /** Split the channel list in cl which came from dest, and spool it to this user\r        * Used internally by WHOIS\r     * @param dest The user the original channel list came from\r     * @param cl The  channel list as a string obtained from userrec::ChannelList()\r         */\r    void SplitChanList(userrec* dest, const std::string &cl);\r\r     /** Remove this user from all channels they are on, and delete any that are now empty.\r  * This is used by QUIT, and will not send part messages!\r       */\r    void PurgeEmptyChannels();\r\r    /** Get the connect class which matches this user's host or IP address\r  * @return A reference to this user's connect class\r     */\r    ConnectClass* GetClass();\r\r     /** Show the message of the day to this user\r    */\r    void ShowMOTD();\r\r      /** Show the server RULES file to this user\r     */\r    void ShowRULES();\r\r     /** Set oper-specific quit message shown to opers only when the user quits\r      * (overrides any sent by QuitUser)\r     */\r    void SetOperQuit(const std::string &oquit);\r\r   /** Get oper-specific quit message shown only to opers when the user quits.\r     * (overrides any sent by QuitUser)\r     */\r    const char* GetOperQuit();\r\r    /** Handle socket event.\r        * From EventHandler class.\r     * @param et Event type\r         * @param errornum Error number for EVENT_ERROR events\r  */\r    void HandleEvent(EventType et, int errornum = 0);\r\r     /** Default destructor\r  */\r    virtual ~userrec();\r};\r\r/* Configuration callbacks */\rclass ServerConfig;\r\r#endif\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __USERS_H__
+#define __USERS_H__
+
+#include <string>
+#include "inspircd_config.h"
+#include "socket.h"
+#include "channels.h"
+#include "inspstring.h"
+#include "connection.h"
+#include "hashcomp.h"
+#include "dns.h"
+
+/** Channel status for a user
+ */
+enum ChanStatus {
+       /** Op */
+       STATUS_OP     = 4,
+       /** Halfop */
+       STATUS_HOP    = 2,
+       /** Voice */
+       STATUS_VOICE  = 1,
+       /** None */
+       STATUS_NORMAL = 0
+};
+
+/** connect class types
+ */
+enum ClassTypes {
+       /** connect:allow */
+       CC_ALLOW = 0,
+       /** connect:deny */
+       CC_DENY  = 1
+};
+
+/** RFC1459 channel modes
+ */
+enum UserModes {
+       /** +s: Server notices */
+       UM_SERVERNOTICE = 's' - 65,
+       /** +w: WALLOPS */
+       UM_WALLOPS = 'w' - 65,
+       /** +i: Invisible */
+       UM_INVISIBLE = 'i' - 65,
+       /** +o: Operator */
+       UM_OPERATOR = 'o' - 65,
+       /** +n: Server notice mask */
+       UM_SNOMASK = 'n' - 65
+};
+
+/** Registration state of a user, e.g.
+ * have they sent USER, NICK, PASS yet?
+ */
+enum RegistrationState {
+
+#ifndef WIN32   // Burlex: This is already defined in win32, luckily it is still 0.
+       REG_NONE = 0,           /* Has sent nothing */
+#endif
+
+       REG_USER = 1,           /* Has sent USER */
+       REG_NICK = 2,           /* Has sent NICK */
+       REG_NICKUSER = 3,       /* Bitwise combination of REG_NICK and REG_USER */
+       REG_ALL = 7             /* REG_NICKUSER plus next bit along */
+};
+
+/* Required forward declaration */
+class InspIRCd;
+
+/** Derived from Resolver, and performs user forward/reverse lookups.
+ */
+class CoreExport UserResolver : public Resolver
+{
+ private:
+       /** User this class is 'attached' to.
+        */
+       userrec* bound_user;
+       /** File descriptor teh lookup is bound to
+        */
+       int bound_fd;
+       /** True if the lookup is forward, false if is a reverse lookup
+        */
+       bool fwd;
+ public:
+       /** Create a resolver.
+        * @param Instance The creating instance
+        * @param user The user to begin lookup on
+        * @param to_resolve The IP or host to resolve
+        * @param qt The query type
+        * @param cache Modified by the constructor if the result was cached
+        */
+       UserResolver(InspIRCd* Instance, userrec* user, std::string to_resolve, QueryType qt, bool &cache);
+
+       /** Called on successful lookup
+        * @param result Result string
+        * @param ttl Time to live for result
+        * @param cached True if the result was found in the cache
+        */
+       void OnLookupComplete(const std::string &result, unsigned int ttl, bool cached);
+
+       /** Called on failed lookup
+        * @param e Error code
+        * @param errormessage Error message string
+        */
+       void OnError(ResolverError e, const std::string &errormessage);
+};
+
+
+/** Holds information relevent to &lt;connect allow&gt; and &lt;connect deny&gt; tags in the config file.
+ */
+class CoreExport ConnectClass : public classbase
+{
+ private:
+       /** Type of line, either CC_ALLOW or CC_DENY
+        */
+       char type;
+       /** Max time to register the connection in seconds
+        */
+       unsigned int registration_timeout;
+       /** Number of lines in buffer before excess flood is triggered
+        */
+       unsigned int flood;
+       /** Host mask for this line
+        */
+       std::string host;
+       /** Number of seconds between pings for this line
+        */
+       unsigned int pingtime;
+       /** (Optional) Password for this line
+        */
+       std::string pass;
+
+       /** Threshold value for flood disconnect
+        */
+       unsigned int threshold;
+
+       /** Maximum size of sendq for users in this class (bytes)
+        */
+       unsigned long sendqmax;
+
+       /** Maximum size of recvq for users in this class (bytes)
+        */
+       unsigned long recvqmax;
+
+       /** Local max when connecting by this connection class
+        */
+       unsigned long maxlocal;
+
+       /** Global max when connecting by this connection class
+        */
+       unsigned long maxglobal;
+       /** Port number this connect class applies to
+        */
+       int port;
+
+public:
+
+       /** Create a new connect class with no settings.
+        */
+       ConnectClass() : type(CC_DENY), registration_timeout(0), flood(0), host(""), pingtime(0), pass(""),
+                       threshold(0), sendqmax(0), recvqmax(0), maxlocal(0), maxglobal(0) { }
+
+       /** Create a new connect class to ALLOW connections.
+        * @param timeout The registration timeout
+        * @param fld The flood value
+        * @param hst The IP mask to allow
+        * @param ping The ping frequency
+        * @param pas The password to be used
+        * @param thres The flooding threshold
+        * @param sendq The maximum sendq value
+        * @param recvq The maximum recvq value
+        * @param maxl The maximum local sessions
+        * @param maxg The maximum global sessions
+        */
+       ConnectClass(unsigned int timeout, unsigned int fld, const std::string &hst, unsigned int ping,
+                       const std::string &pas, unsigned int thres, unsigned long sendq, unsigned long recvq,
+                       unsigned long maxl, unsigned long maxg, int p = 0) :
+                       type(CC_ALLOW), registration_timeout(timeout), flood(fld), host(hst), pingtime(ping), pass(pas),
+                       threshold(thres), sendqmax(sendq), recvqmax(recvq), maxlocal(maxl), maxglobal(maxg), port(p) { }
+
+       /** Create a new connect class to DENY  connections
+        * @param hst The IP mask to deny
+        */
+       ConnectClass(const std::string &hst) : type(CC_DENY), registration_timeout(0), flood(0), host(hst), pingtime(0),
+                       pass(""), threshold(0), sendqmax(0), recvqmax(0), maxlocal(0), maxglobal(0), port(0) { }
+
+       /** Returns the type, CC_ALLOW or CC_DENY
+        */
+       char GetType()
+       {
+               return (type == CC_ALLOW ? CC_ALLOW : CC_DENY);
+       }
+
+       /** Returns the registration timeout
+        */
+       unsigned int GetRegTimeout()
+       {
+               return (registration_timeout ? registration_timeout : 90);
+       }
+
+       /** Returns the flood limit
+        */
+       unsigned int GetFlood()
+       {
+               return (threshold ? flood : 999);
+       }
+
+       /** Returns the allowed or denied IP mask
+        */
+       const std::string& GetHost()
+       {
+               return host;
+       }
+
+       int GetPort()
+       {
+               return port;
+       }
+
+       /** Returns the ping frequency
+        */
+       unsigned int GetPingTime()
+       {
+               return (pingtime ? pingtime : 120);
+       }
+
+       /** Returns the password or an empty string
+        */
+       const std::string& GetPass()
+       {
+               return pass;
+       }
+
+       /** Returns the flood threshold value
+        */
+       unsigned int GetThreshold()
+       {
+               return (threshold ? threshold : 1);
+       }
+
+       /** Returns the maximum sendq value
+        */
+       unsigned long GetSendqMax()
+       {
+               return (sendqmax ? sendqmax : 262114);
+       }
+
+       /** Returns the maximum recvq value
+        */
+       unsigned long GetRecvqMax()
+       {
+               return (recvqmax ? recvqmax : 4096);
+       }
+
+       /** Returusn the maximum number of local sessions
+        */
+       unsigned long GetMaxLocal()
+       {
+               return maxlocal;
+       }
+
+       /** Returns the maximum number of global sessions
+        */
+       unsigned long GetMaxGlobal()
+       {
+               return maxglobal;
+       }
+};
+
+/** Holds a complete list of all channels to which a user has been invited and has not yet joined.
+ */
+typedef std::vector<irc::string> InvitedList;
+
+/** Holds a complete list of all allow and deny tags from the configuration file (connection classes)
+ */
+typedef std::vector<ConnectClass> ClassVector;
+
+/** Typedef for the list of user-channel records for a user
+ */
+typedef std::map<chanrec*, char> UserChanList;
+
+/** Shorthand for an iterator into a UserChanList
+ */
+typedef UserChanList::iterator UCListIter;
+
+/* Required forward declaration
+ */
+class userrec;
+
+/** Visibility data for a user.
+ * If a user has a non-null instance of this class in their userrec,
+ * then it is used to determine if this user is visible to other users
+ * or not.
+ */
+class CoreExport VisData
+{
+ public:
+       /** Create a visdata
+        */
+       VisData();
+       /** Destroy a visdata
+        */
+       virtual ~VisData();
+       /** Is this user visible to some other user?
+        * @param user The other user to compare to
+        * @return true True if the user is visible to the other user, false if not
+        */
+       virtual bool VisibleTo(userrec* user);
+};
+
+/** Holds all information about a user
+ * This class stores all information about a user connected to the irc server. Everything about a
+ * connection is stored here primarily, from the user's socket ID (file descriptor) through to the
+ * user's nickname and hostname. Use the FindNick method of the InspIRCd class to locate a specific user
+ * by nickname, or the FindDescriptor method of the InspIRCd class to find a specific user by their
+ * file descriptor value.
+ */
+class CoreExport userrec : public connection
+{
+ private:
+       /** Pointer to creator.
+        * This is required to make use of core functions
+        * from within the userrec class.
+        */
+       InspIRCd* ServerInstance;
+
+       /** A list of channels the user has a pending invite to.
+        * Upon INVITE channels are added, and upon JOIN, the
+        * channels are removed from this list.
+        */
+       InvitedList invites;
+
+       /** Number of channels this user is currently on
+        */
+       unsigned int ChannelCount;
+
+       /** Cached nick!ident@host value using the real hostname
+        */
+       char* cached_fullhost;
+
+       /** Cached nick!ident@ip value using the real IP address
+        */
+       char* cached_hostip;
+
+       /** Cached nick!ident@host value using the masked hostname
+        */
+       char* cached_makehost;
+
+       /** Cached nick!ident@realhost value using the real hostname
+        */
+       char* cached_fullrealhost;
+
+       /** When we erase the user (in the destructor),
+        * we call this method to subtract one from all
+        * mode characters this user is making use of.
+        */
+       void DecrementModes();
+
+       /** Oper-only quit message for this user if non-null
+        */
+       char* operquit;
+
+ public:
+       /** Resolvers for looking up this users IP address
+        * This will occur if and when res_reverse completes.
+        * When this class completes its lookup, userrec::dns_done
+        * will be set from false to true.
+        */
+       UserResolver* res_forward;
+
+       /** Resolvers for looking up this users hostname
+        * This is instantiated by userrec::StartDNSLookup(),
+        * and on success, instantiates userrec::res_reverse.
+        */
+       UserResolver* res_reverse;
+
+       /** User visibility state, see definition of VisData.
+        */
+       VisData* Visibility;
+
+       /** Stored reverse lookup from res_forward
+        */
+       std::string stored_host;
+
+       /** Starts a DNS lookup of the user's IP.
+        * This will cause two UserResolver classes to be instantiated.
+        * When complete, these objects set userrec::dns_done to true.
+        */
+       void StartDNSLookup();
+
+       /** The users nickname.
+        * An invalid nickname indicates an unregistered connection prior to the NICK command.
+        * Use InspIRCd::IsNick() to validate nicknames.
+        */
+       char nick[NICKMAX];
+
+       /** The users ident reply.
+        * Two characters are added to the user-defined limit to compensate for the tilde etc.
+        */
+       char ident[IDENTMAX+2];
+
+       /** The host displayed to non-opers (used for cloaking etc).
+        * This usually matches the value of userrec::host.
+        */
+       char dhost[65];
+
+       /** The users full name (GECOS).
+        */
+       char fullname[MAXGECOS+1];
+
+       /** The user's mode list.
+        * This is NOT a null terminated string! In the 1.1 version of InspIRCd
+        * this is an array of values in a similar way to channel modes.
+        * A value of 1 in field (modeletter-65) indicates that the mode is
+        * set, for example, to work out if mode +s is set, we  check the field
+        * userrec::modes['s'-65] != 0.
+        * The following RFC characters o, w, s, i have constants defined via an
+        * enum, such as UM_SERVERNOTICE and UM_OPETATOR.
+        */
+       char modes[64];
+
+       /** What snomasks are set on this user.
+        * This functions the same as the above modes.
+        */
+       char snomasks[64];
+
+       /** Channels this user is on, and the permissions they have there
+        */
+       UserChanList chans;
+
+       /** The server the user is connected to.
+        */
+       const char* server;
+
+       /** The user's away message.
+        * If this string is empty, the user is not marked as away.
+        */
+       char awaymsg[MAXAWAY+1];
+
+       /** Number of lines the user can place into the buffer
+        * (up to the global NetBufferSize bytes) before they
+        * are disconnected for excess flood
+        */
+       int flood;
+
+       /** Timestamp of current time + connection class timeout.
+        * This user must send USER/NICK before this timestamp is
+        * reached or they will be disconnected.
+        */
+       time_t timeout;
+
+       /** The oper type they logged in as, if they are an oper.
+        * This is used to check permissions in operclasses, so that
+        * we can say 'yay' or 'nay' to any commands they issue.
+        * The value of this is the value of a valid 'type name=' tag.
+        */
+       char oper[NICKMAX];
+
+       /** True when DNS lookups are completed.
+        * The UserResolver classes res_forward and res_reverse will
+        * set this value once they complete.
+        */
+       bool dns_done;
+
+       /** Number of seconds between PINGs for this user (set from &lt;connect:allow&gt; tag
+        */
+       unsigned int pingmax;
+
+       /** Password specified by the user when they registered.
+        * This is stored even if the <connect> block doesnt need a password, so that
+        * modules may check it.
+        */
+       char password[64];
+
+       /** User's receive queue.
+        * Lines from the IRCd awaiting processing are stored here.
+        * Upgraded april 2005, old system a bit hairy.
+        */
+       std::string recvq;
+
+       /** User's send queue.
+        * Lines waiting to be sent are stored here until their buffer is flushed.
+        */
+       std::string sendq;
+
+       /** Flood counters - lines received
+        */
+       int lines_in;
+
+       /** Flood counters - time lines_in is due to be reset
+        */
+       time_t reset_due;
+
+       /** Flood counters - Highest value lines_in may reach before the user gets disconnected
+        */
+       long threshold;
+
+       /** If this is set to true, then all read operations for the user
+        * are dropped into the bit-bucket.
+        * This is used by the global CullList, but please note that setting this value
+        * alone will NOT cause the user to quit. This means it can be used seperately,
+        * for example by shun modules etc.
+        */
+       bool muted;
+
+       /** IPV4 or IPV6 ip address. Use SetSockAddr to set this and GetProtocolFamily/
+        * GetIPString/GetPort to obtain its values.
+        */
+       sockaddr* ip;
+
+       /** Initialize the clients sockaddr
+        * @param protocol_family The protocol family of the IP address, AF_INET or AF_INET6
+        * @param ip A human-readable IP address for this user matching the protcol_family
+        * @param port The port number of this user or zero for a remote user
+        */
+       void SetSockAddr(int protocol_family, const char* ip, int port);
+
+       /** Get port number from sockaddr
+        * @return The port number of this user.
+        */
+       int GetPort();
+
+       /** Get protocol family from sockaddr
+        * @return The protocol family of this user, either AF_INET or AF_INET6
+        */
+       int GetProtocolFamily();
+
+       /** Get IP string from sockaddr, using static internal buffer
+        * @return The IP string
+        */
+       const char* GetIPString();
+
+       /** Get IP string from sockaddr, using caller-specified buffer
+        * @param buf A buffer to use
+        * @return The IP string
+        */
+       const char* GetIPString(char* buf);
+
+       /* Write error string
+        */
+       std::string WriteError;
+
+       /** Maximum size this user's sendq can become.
+        * Copied from the connect class on connect.
+        */
+       long sendqmax;
+
+       /** Maximum size this user's recvq can become.
+        * Copied from the connect class on connect.
+        */
+       long recvqmax;
+
+       /** This is true if the user matched an exception when they connected to the ircd.
+        * It isnt valid after this point, and you should not attempt to do anything with it
+        * after this point, because the eline might be removed at a later time, and/or no
+        * longer be applicable to this user. It is only used to save doing the eline lookup
+        * twice (instead we do it once and set this value).
+        */
+       bool exempt;
+
+       /** Default constructor
+        * @throw Nothing at present
+        */
+       userrec(InspIRCd* Instance);
+
+       /** Returns the full displayed host of the user
+        * This member function returns the hostname of the user as seen by other users
+        * on the server, in nick!ident&at;host form.
+        * @return The full masked host of the user
+        */
+       virtual char* GetFullHost();
+
+       /** Returns the full real host of the user
+        * This member function returns the hostname of the user as seen by other users
+        * on the server, in nick!ident&at;host form. If any form of hostname cloaking is in operation,
+        * e.g. through a module, then this method will ignore it and return the true hostname.
+        * @return The full real host of the user
+        */
+       virtual char* GetFullRealHost();
+
+       /** This clears any cached results that are used for GetFullRealHost() etc.
+        * The results of these calls are cached as generating them can be generally expensive.
+        */
+       void InvalidateCache();
+
+       /** Create a displayable mode string for this users snomasks
+        * @return The notice mask character sequence
+        */
+       const char* FormatNoticeMasks();
+
+       /** Process a snomask modifier string, e.g. +abc-de
+        * @param sm A sequence of notice mask characters
+        * @return The cleaned mode sequence which can be output,
+        * e.g. in the above example if masks c and e are not
+        * valid, this function will return +ab-d
+        */
+       std::string ProcessNoticeMasks(const char *sm);
+
+       /** Returns true if a notice mask is set
+        * @param sm A notice mask character to check
+        * @return True if the notice mask is set
+        */
+       bool IsNoticeMaskSet(unsigned char sm);
+
+       /** Changed a specific notice mask value
+        * @param sm The server notice mask to change
+        * @param value An on/off value for this mask
+        */
+       void SetNoticeMask(unsigned char sm, bool value);
+
+       /** Create a displayable mode string for this users umodes
+        * @param The mode string
+        */
+       const char* FormatModes();
+
+       /** Returns true if a specific mode is set
+        * @param m The user mode
+        * @return True if the mode is set
+        */
+       bool IsModeSet(unsigned char m);
+
+       /** Set a specific usermode to on or off
+        * @param m The user mode
+        * @param value On or off setting of the mode
+        */
+       void SetMode(unsigned char m, bool value);
+
+       /** Returns true if a user is invited to a channel.
+        * @param channel A channel name to look up
+        * @return True if the user is invited to the given channel
+        */
+       virtual bool IsInvited(const irc::string &channel);
+
+       /** Adds a channel to a users invite list (invites them to a channel)
+        * @param channel A channel name to add
+        */
+       virtual void InviteTo(const irc::string &channel);
+
+       /** Removes a channel from a users invite list.
+        * This member function is called on successfully joining an invite only channel
+        * to which the user has previously been invited, to clear the invitation.
+        * @param channel The channel to remove the invite to
+        */
+       virtual void RemoveInvite(const irc::string &channel);
+
+       /** Returns true or false for if a user can execute a privilaged oper command.
+        * This is done by looking up their oper type from userrec::oper, then referencing
+        * this to their oper classes and checking the commands they can execute.
+        * @param command A command (should be all CAPS)
+        * @return True if this user can execute the command
+        */
+       bool HasPermission(const std::string &command);
+
+       /** Calls read() to read some data for this user using their fd.
+        * @param buffer The buffer to read into
+        * @param size The size of data to read
+        * @return The number of bytes read, or -1 if an error occured.
+        */
+       int ReadData(void* buffer, size_t size);
+
+       /** This method adds data to the read buffer of the user.
+        * The buffer can grow to any size within limits of the available memory,
+        * managed by the size of a std::string, however if any individual line in
+        * the buffer grows over 600 bytes in length (which is 88 chars over the
+        * RFC-specified limit per line) then the method will return false and the
+        * text will not be inserted.
+        * @param a The string to add to the users read buffer
+        * @return True if the string was successfully added to the read buffer
+        */
+       bool AddBuffer(std::string a);
+
+       /** This method returns true if the buffer contains at least one carriage return
+        * character (e.g. one complete line may be read)
+        * @return True if there is at least one complete line in the users buffer
+        */
+       bool BufferIsReady();
+
+       /** This function clears the entire buffer by setting it to an empty string.
+        */
+       void ClearBuffer();
+
+       /** This method returns the first available string at the tail end of the buffer
+        * and advances the tail end of the buffer past the string. This means it is
+        * a one way operation in a similar way to strtok(), and multiple calls return
+        * multiple lines if they are available. The results of this function if there
+        * are no lines to be read are unknown, always use BufferIsReady() to check if
+        * it is ok to read the buffer before calling GetBuffer().
+        * @return The string at the tail end of this users buffer
+        */
+       std::string GetBuffer();
+
+       /** Sets the write error for a connection. This is done because the actual disconnect
+        * of a client may occur at an inopportune time such as half way through /LIST output.
+        * The WriteErrors of clients are checked at a more ideal time (in the mainloop) and
+        * errored clients purged.
+        * @param error The error string to set.
+        */
+       void SetWriteError(const std::string &error);
+
+       /** Returns the write error which last occured on this connection or an empty string
+        * if none occured.
+        * @return The error string which has occured for this user
+        */
+       const char* GetWriteError();
+
+       /** Adds to the user's write buffer.
+        * You may add any amount of text up to this users sendq value, if you exceed the
+        * sendq value, SetWriteError() will be called to set the users error string to
+        * "SendQ exceeded", and further buffer adds will be dropped.
+        * @param data The data to add to the write buffer
+        */
+       void AddWriteBuf(const std::string &data);
+
+       /** Flushes as much of the user's buffer to the file descriptor as possible.
+        * This function may not always flush the entire buffer, rather instead as much of it
+        * as it possibly can. If the send() call fails to send the entire buffer, the buffer
+        * position is advanced forwards and the rest of the data sent at the next call to
+        * this method.
+        */
+       void FlushWriteBuf();
+
+       /** Returns the list of channels this user has been invited to but has not yet joined.
+        * @return A list of channels the user is invited to
+        */
+       InvitedList* GetInviteList();
+
+       /** Creates a wildcard host.
+        * Takes a buffer to use and fills the given buffer with the host in the format *!*@hostname
+        * @return The wildcarded hostname in *!*@host form
+        */
+       char* MakeWildHost();
+
+       /** Creates a usermask with real host.
+        * Takes a buffer to use and fills the given buffer with the hostmask in the format user@host
+        * @return the usermask in the format user@host
+        */
+       char* MakeHost();
+
+       /** Creates a usermask with real ip.
+        * Takes a buffer to use and fills the given buffer with the ipmask in the format user@ip
+        * @return the usermask in the format user@ip
+        */
+       char* MakeHostIP();
+
+       /** Shuts down and closes the user's socket
+        * This will not cause the user to be deleted. Use InspIRCd::QuitUser for this,
+        * which will call CloseSocket() for you.
+        */
+       void CloseSocket();
+
+       /** Disconnect a user gracefully
+        * @param user The user to remove
+        * @param r The quit reason to show to normal users
+        * @param oreason The quit reason to show to opers
+        * @return Although this function has no return type, on exit the user provided will no longer exist.
+        */
+       static void QuitUser(InspIRCd* Instance, userrec *user, const std::string &r, const char* oreason = "");
+
+       /** Add the user to WHOWAS system
+        */
+       void AddToWhoWas();
+
+       /** Oper up the user using the given opertype.
+        * This will also give the +o usermode.
+        * @param opertype The oper type to oper as
+        */
+       void Oper(const std::string &opertype);
+
+       /** Call this method to find the matching <connect> for a user, and to check them against it.
+        */
+       void CheckClass();
+
+       /** Use this method to fully connect a user.
+        * This will send the message of the day, check G/K/E lines, etc.
+        */
+       void FullConnect();
+
+       /** Change this users hash key to a new string.
+        * You should not call this function directly. It is used by the core
+        * to update the users hash entry on a nickchange.
+        * @param New new user_hash key
+        * @return Pointer to userrec in hash (usually 'this')
+        */
+       userrec* UpdateNickHash(const char* New);
+
+       /** Force a nickname change.
+        * If the nickname change fails (for example, because the nick in question
+        * already exists) this function will return false, and you must then either
+        * output an error message, or quit the user for nickname collision.
+        * @param newnick The nickname to change to
+        * @return True if the nickchange was successful.
+        */
+       bool ForceNickChange(const char* newnick);
+
+       /** Add a client to the system.
+        * This will create a new userrec, insert it into the user_hash,
+        * initialize it as not yet registered, and add it to the socket engine.
+        * @param Instance a pointer to the server instance
+        * @param socket The socket id (file descriptor) this user is on
+        * @param port The port number this user connected on
+        * @param iscached This variable is reserved for future use
+        * @param ip The IP address of the user
+        * @return This function has no return value, but a call to AddClient may remove the user.
+        */
+       static void AddClient(InspIRCd* Instance, int socket, int port, bool iscached, int socketfamily, sockaddr* ip);
+
+       /** Oper down.
+        * This will clear the +o usermode and unset the user's oper type
+        */
+       void UnOper();
+
+       /** Return the number of global clones of this user
+        * @return The global clone count of this user
+        */
+       unsigned long GlobalCloneCount();
+
+       /** Return the number of local clones of this user
+        * @return The local clone count of this user
+        */
+       unsigned long LocalCloneCount();
+
+       /** Remove all clone counts from the user, you should
+        * use this if you change the user's IP address in
+        * userrec::ip after they have registered.
+        */
+       void RemoveCloneCounts();
+
+       /** Write text to this user, appending CR/LF.
+        * @param text A std::string to send to the user
+        */
+       void Write(std::string text);
+
+       /** Write text to this user, appending CR/LF.
+        * @param text The format string for text to send to the user
+        * @param ... POD-type format arguments
+        */
+       void Write(const char *text, ...);
+
+       /** Write text to this user, appending CR/LF and prepending :server.name
+        * @param text A std::string to send to the user
+        */
+       void WriteServ(const std::string& text);
+
+       /** Write text to this user, appending CR/LF and prepending :server.name
+        * @param text The format string for text to send to the user
+        * @param ... POD-type format arguments
+        */
+       void WriteServ(const char* text, ...);
+
+       /** Write text to this user, appending CR/LF and prepending :nick!user@host of the user provided in the first parameter.
+        * @param user The user to prepend the :nick!user@host of
+        * @param text A std::string to send to the user
+        */
+       void WriteFrom(userrec *user, const std::string &text);
+
+       /** Write text to this user, appending CR/LF and prepending :nick!user@host of the user provided in the first parameter.
+        * @param user The user to prepend the :nick!user@host of
+        * @param text The format string for text to send to the user
+        * @param ... POD-type format arguments
+        */
+       void WriteFrom(userrec *user, const char* text, ...);
+
+       /** Write text to the user provided in the first parameter, appending CR/LF, and prepending THIS user's :nick!user@host.
+        * @param dest The user to route the message to
+        * @param text A std::string to send to the user
+        */
+       void WriteTo(userrec *dest, const std::string &data);
+
+       /** Write text to the user provided in the first parameter, appending CR/LF, and prepending THIS user's :nick!user@host.
+        * @param dest The user to route the message to
+        * @param text The format string for text to send to the user
+        * @param ... POD-type format arguments
+        */
+       void WriteTo(userrec *dest, const char *data, ...);
+
+       /** Write to all users that can see this user (including this user in the list), appending CR/LF
+        * @param text A std::string to send to the users
+        */
+       void WriteCommon(const std::string &text);
+
+       /** Write to all users that can see this user (including this user in the list), appending CR/LF
+        * @param text The format string for text to send to the users
+        * @param ... POD-type format arguments
+        */
+       void WriteCommon(const char* text, ...);
+
+       /** Write to all users that can see this user (not including this user in the list), appending CR/LF
+        * @param text The format string for text to send to the users
+        * @param ... POD-type format arguments
+        */
+       void WriteCommonExcept(const char* text, ...);
+
+       /** Write to all users that can see this user (not including this user in the list), appending CR/LF
+        * @param text A std::string to send to the users
+        */
+       void WriteCommonExcept(const std::string &text);
+
+       /** Write a quit message to all common users, as in userrec::WriteCommonExcept but with a specific
+        * quit message for opers only.
+        * @param normal_text Normal user quit message
+        * @param oper_text Oper only quit message
+        */
+       void WriteCommonQuit(const std::string &normal_text, const std::string &oper_text);
+
+       /** Write a WALLOPS message from this user to all local opers.
+        * If this user is not opered, the function will return without doing anything.
+        * @param text The format string to send in the WALLOPS message
+        * @param ... Format arguments
+        */
+       void WriteWallOps(const char* text, ...);
+
+       /** Write a WALLOPS message from this user to all local opers.
+        * If this user is not opered, the function will return without doing anything.
+        * @param text The text to send in the WALLOPS message
+        */
+       void WriteWallOps(const std::string &text);
+
+       /** Return true if the user shares at least one channel with another user
+        * @param other The other user to compare the channel list against
+        * @return True if the given user shares at least one channel with this user
+        */
+       bool SharesChannelWith(userrec *other);
+
+       /** Change the displayed host of a user.
+        * ALWAYS use this function, rather than writing userrec::dhost directly,
+        * as this triggers module events allowing the change to be syncronized to
+        * remote servers. This will also emulate a QUIT and rejoin (where configured)
+        * before setting their host field.
+        * @param host The new hostname to set
+        * @return True if the change succeeded, false if it didn't
+        */
+       bool ChangeDisplayedHost(const char* host);
+
+       /** Change the ident (username) of a user.
+        * ALWAYS use this function, rather than writing userrec::ident directly,
+        * as this correctly causes the user to seem to quit (where configured)
+        * before setting their ident field.
+        * @param host The new ident to set
+        * @return True if the change succeeded, false if it didn't
+        */
+       bool ChangeIdent(const char* newident);
+
+       /** Change a users realname field.
+        * ALWAYS use this function, rather than writing userrec::fullname directly,
+        * as this triggers module events allowing the change to be syncronized to
+        * remote servers.
+        * @param gecos The user's new realname
+        * @return True if the change succeeded, false if otherwise
+        */
+       bool ChangeName(const char* gecos);
+
+       /** Send a command to all local users from this user
+        * The command given must be able to send text with the
+        * first parameter as a servermask (e.g. $*), so basically
+        * you should use PRIVMSG or NOTICE.
+        * @param command the command to send
+        * @param text The text format string to send
+        * @param ... Format arguments
+        */
+       void SendAll(const char* command, char* text, ...);
+
+       /** Compile a channel list for this user, and send it to the user 'source'
+        * Used internally by WHOIS
+        * @param The user to send the channel list to if it is not too long
+        * @return This user's channel list
+        */
+       std::string ChannelList(userrec* source);
+
+       /** Split the channel list in cl which came from dest, and spool it to this user
+        * Used internally by WHOIS
+        * @param dest The user the original channel list came from
+        * @param cl The  channel list as a string obtained from userrec::ChannelList()
+        */
+       void SplitChanList(userrec* dest, const std::string &cl);
+
+       /** Remove this user from all channels they are on, and delete any that are now empty.
+        * This is used by QUIT, and will not send part messages!
+        */
+       void PurgeEmptyChannels();
+
+       /** Get the connect class which matches this user's host or IP address
+        * @return A reference to this user's connect class
+        */
+       ConnectClass* GetClass();
+
+       /** Show the message of the day to this user
+        */
+       void ShowMOTD();
+
+       /** Show the server RULES file to this user
+        */
+       void ShowRULES();
+
+       /** Set oper-specific quit message shown to opers only when the user quits
+        * (overrides any sent by QuitUser)
+        */
+       void SetOperQuit(const std::string &oquit);
+
+       /** Get oper-specific quit message shown only to opers when the user quits.
+        * (overrides any sent by QuitUser)
+        */
+       const char* GetOperQuit();
+
+       /** Handle socket event.
+        * From EventHandler class.
+        * @param et Event type
+        * @param errornum Error number for EVENT_ERROR events
+        */
+       void HandleEvent(EventType et, int errornum = 0);
+
+       /** Default destructor
+        */
+       virtual ~userrec();
+};
+
+/* Configuration callbacks */
+class ServerConfig;
+
+#endif
+
index c58d4bfc10a94797bda912476c0261703759074e..259d86184cc86ba8e736dcbb79dcc2211c17c9a6 100644 (file)
@@ -1 +1,45 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd_config.h"\r\r/** Match a string against a mask.\r * @param str The string to check\r * @param mask the mask to check against\r * @return true if the strings match\r */\rCoreExport bool match(const char *str, const char *mask);\r/** Match a string against a mask, and define wether or not to use CIDR rules\r * @param str The string to check\r * @param mask the mask to check against\r * @param use_cidr_match True if CIDR matching rules should be applied first\r * @return true if the strings match\r */\rCoreExport bool match(const char *str, const char *mask, bool use_cidr_match);\r/** Match a string against a mask, defining wether case sensitivity applies.\r * @param str The string to check\r * @param mask the mask to check against\r * @param case_sensitive True if the match is case sensitive\r * @return True if the strings match\r */\rCoreExport bool match(bool case_sensitive, const char *str, const char *mask);\r/** Match a string against a mask, defining wether case sensitivity applies,\r * and defining wether or not to use CIDR rules first.\r * @param case_sensitive True if the match is case sensitive\r * @param str The string to check\r * @param mask the mask to check against\r * @param use_cidr_match True if CIDR matching rules should be applied first\r * @return true if the strings match\r */\rCoreExport bool match(bool case_sensitive, const char *str, const char *mask, bool use_cidr_match);\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd_config.h"
+
+/** Match a string against a mask.
+ * @param str The string to check
+ * @param mask the mask to check against
+ * @return true if the strings match
+ */
+CoreExport bool match(const char *str, const char *mask);
+/** Match a string against a mask, and define wether or not to use CIDR rules
+ * @param str The string to check
+ * @param mask the mask to check against
+ * @param use_cidr_match True if CIDR matching rules should be applied first
+ * @return true if the strings match
+ */
+CoreExport bool match(const char *str, const char *mask, bool use_cidr_match);
+/** Match a string against a mask, defining wether case sensitivity applies.
+ * @param str The string to check
+ * @param mask the mask to check against
+ * @param case_sensitive True if the match is case sensitive
+ * @return True if the strings match
+ */
+CoreExport bool match(bool case_sensitive, const char *str, const char *mask);
+/** Match a string against a mask, defining wether case sensitivity applies,
+ * and defining wether or not to use CIDR rules first.
+ * @param case_sensitive True if the match is case sensitive
+ * @param str The string to check
+ * @param mask the mask to check against
+ * @param use_cidr_match True if CIDR matching rules should be applied first
+ * @return true if the strings match
+ */
+CoreExport bool match(bool case_sensitive, const char *str, const char *mask, bool use_cidr_match);
+
index 5695c3788eef209ceadcdf785670661728244312..bb59a97355bd2acea87cc74fe3d38680ccd5450d 100644 (file)
@@ -1 +1,530 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *        the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __XLINE_H\r#define __XLINE_H\r\r// include the common header files\r\r#include <string>\r#include <deque>\r#include <vector>\r#include "users.h"\r#include "channels.h"\r\rconst int APPLY_GLINES         = 1;\rconst int APPLY_KLINES             = 2;\rconst int APPLY_QLINES             = 4;\rconst int APPLY_ZLINES             = 8;\rconst int APPLY_PERM_ONLY  = 16;\rconst int APPLY_ALL               = APPLY_GLINES | APPLY_KLINES | APPLY_QLINES | APPLY_ZLINES;\r\r/** XLine is the base class for ban lines such as G lines and K lines.\r */\rclass CoreExport XLine : public classbase\r{\r  public:\r\r        /** Create an XLine.\r    * @param s_time The set time\r   * @param d The duration of the xline\r   * @param src The sender of the xline\r   * @param re The reason of the xline\r    */\r    XLine(time_t s_time, long d, const char* src, const char* re)\r          : set_time(s_time), duration(d)\r        {\r              source = strdup(src);\r          reason = strdup(re);\r           expiry = set_time + duration;\r  }\r\r     /** Destructor\r  */\r    virtual ~XLine()\r       {\r              free(reason);\r          free(source);\r  }\r      /** The time the line was added.\r        */\r    time_t set_time;\r       \r       /** The duration of the ban, or 0 if permenant\r  */\r    long duration;\r \r       /** Source of the ban. This can be a servername or an oper nickname\r     */\r    char* source;\r  \r       /** Reason for the ban\r  */\r    char* reason;\r\r /** Expiry time\r         */\r    time_t expiry;\r};\r\r/** KLine class\r */\rclass CoreExport KLine : public XLine\r{\r  public:\r       /** Create a K-Line.\r    * @param s_time The set time\r   * @param d The duration of the xline\r   * @param src The sender of the xline\r   * @param re The reason of the xline\r    * @param ident Ident to match\r  * @param host Host to match\r    */\r    KLine(time_t s_time, long d, const char* src, const char* re, const char* ident, const char* host) : XLine(s_time, d, src, re)\r {\r              identmask = strdup(ident);\r             hostmask = strdup(host);\r       }\r\r     /** Destructor\r  */\r    ~KLine()\r       {\r              free(identmask);\r               free(hostmask);\r        }\r\r     /** Ident mask\r  */\r    char* identmask;\r       /** Host mask\r   */\r    char* hostmask;\r};\r\r/** GLine class\r */\rclass CoreExport GLine : public XLine\r{\r  public:\r      /** Create a G-Line.\r    * @param s_time The set time\r   * @param d The duration of the xline\r   * @param src The sender of the xline\r   * @param re The reason of the xline\r    * @param ident Ident to match\r  * @param host Host to match\r    */\r    GLine(time_t s_time, long d, const char* src, const char* re, const char* ident, const char* host) : XLine(s_time, d, src, re)\r {\r              identmask = strdup(ident);\r             hostmask = strdup(host);\r       }\r\r     /** Destructor\r  */\r    ~GLine()\r       {\r              free(identmask);\r               free(hostmask);\r        }\r\r     /** Ident mask\r  */\r    char* identmask;\r       /** Host mask\r   */\r    char* hostmask;\r};\r\r/** ELine class\r */\rclass CoreExport ELine : public XLine\r{\r  public:\r      /** Create an E-Line.\r   * @param s_time The set time\r   * @param d The duration of the xline\r   * @param src The sender of the xline\r   * @param re The reason of the xline\r    * @param ident Ident to match\r  * @param host Host to match\r    */\r    ELine(time_t s_time, long d, const char* src, const char* re, const char* ident, const char* host) : XLine(s_time, d, src, re)\r {\r              identmask = strdup(ident);\r             hostmask = strdup(host);\r       }\r\r     ~ELine()\r       {\r              free(identmask);\r               free(hostmask);\r        }\r\r     /** Ident mask\r  */\r    char* identmask;\r       /** Host mask\r   */\r    char* hostmask;\r};\r\r/** ZLine class\r */\rclass CoreExport ZLine : public XLine\r{\r  public:\r      /** Create a Z-Line.\r    * @param s_time The set time\r   * @param d The duration of the xline\r   * @param src The sender of the xline\r   * @param re The reason of the xline\r    * @param ip IP to match\r        */\r    ZLine(time_t s_time, long d, const char* src, const char* re, const char* ip) : XLine(s_time, d, src, re)\r      {\r              ipaddr = strdup(ip);\r   }\r\r     /** Destructor\r  */\r    ~ZLine()\r       {\r              free(ipaddr);\r  }\r\r     /** IP mask\r     */\r    char* ipaddr;\r};\r\r/** QLine class\r */\rclass CoreExport QLine : public XLine\r{\r  public:\r        /** Create a G-Line.\r    * @param s_time The set time\r   * @param d The duration of the xline\r   * @param src The sender of the xline\r   * @param re The reason of the xline\r    * @param nickname Nickname to match\r    */\r    QLine(time_t s_time, long d, const char* src, const char* re, const char* nickname) : XLine(s_time, d, src, re)\r        {\r              nick = strdup(nickname);\r       }\r\r     /** Destructor\r  */\r    ~QLine()\r       {\r              free(nick);\r    }\r\r     /** Nickname mask\r       */\r    char* nick;\r};\r\r/* Required forward declarations\r */\rclass ServerConfig;\rclass InspIRCd;\r\r/** Initialize x line\r */\rbool InitXLine(ServerConfig* conf, const char* tag);\r\r/** Done adding zlines from the config\r */\rbool DoneZLine(ServerConfig* conf, const char* tag);\r/** Done adding qlines from the config\r */\rbool DoneQLine(ServerConfig* conf, const char* tag);\r/** Done adding klines from the config\r */\rbool DoneKLine(ServerConfig* conf, const char* tag);\r/** Done adding elines from the config\r */\rbool DoneELine(ServerConfig* conf, const char* tag);\r\r/** Add a config-defined zline\r */\rbool DoZLine(ServerConfig* conf, const char* tag, char** entries, ValueList &values, int* types);\r/** Add a config-defined qline\r */\rbool DoQLine(ServerConfig* conf, const char* tag, char** entries, ValueList &values, int* types);\r/** Add a config-defined kline\r */\rbool DoKLine(ServerConfig* conf, const char* tag, char** entries, ValueList &values, int* types);\r/** Add a config-defined eline\r */\rbool DoELine(ServerConfig* conf, const char* tag, char** entries, ValueList &values, int* types);\r\r/** Contains an ident and host split into two strings\r */\rtypedef std::pair<std::string, std::string> IdentHostPair;\r\r/** XLineManager is a class used to manage glines, klines, elines, zlines and qlines.\r */\rclass CoreExport XLineManager\r{\r protected:\r    /** The owner/creator of this class\r     */\r    InspIRCd* ServerInstance;\r\r     /** This functor is used by the std::sort() function to keep glines in order\r    */\r    static bool GSortComparison ( const GLine* one, const GLine* two );\r\r   /** This functor is used by the std::sort() function to keep elines in order\r    */\r    static bool ESortComparison ( const ELine* one, const ELine* two );\r\r   /** This functor is used by the std::sort() function to keep zlines in order\r    */\r    static bool ZSortComparison ( const ZLine* one, const ZLine* two );\r\r   /** This functor is used by the std::sort() function to keep klines in order\r    */\r    static bool KSortComparison ( const KLine* one, const KLine* two );\r\r   /** This functor is used by the std::sort() function to keep qlines in order\r    */\r    static bool QSortComparison ( const QLine* one, const QLine* two );\r public:\r   /* Lists for temporary lines with an expiry time */\r\r   /** Temporary KLines */\r        std::vector<KLine*> klines;\r\r   /** Temporary Glines */\r        std::vector<GLine*> glines;\r\r   /** Temporary Zlines */\r        std::vector<ZLine*> zlines;\r\r   /** Temporary QLines */\r        std::vector<QLine*> qlines;\r\r   /** Temporary ELines */\r        std::vector<ELine*> elines;\r\r   /* Seperate lists for perm XLines that isnt checked by expiry functions */\r\r    /** Permenant KLines */\r        std::vector<KLine*> pklines;\r\r  /** Permenant GLines */\r        std::vector<GLine*> pglines;\r\r  /** Permenant ZLines */\r        std::vector<ZLine*> pzlines;\r\r  /** Permenant QLines */\r        std::vector<QLine*> pqlines;\r\r  /** Permenant ELines */\r        std::vector<ELine*> pelines;\r   \r       /** Constructor\r         * @param Instance A pointer to the creator object\r      */\r    XLineManager(InspIRCd* Instance);\r\r     /** Split an ident and host into two seperate strings.\r  * This allows for faster matching.\r     */\r    IdentHostPair IdentSplit(const std::string &ident_and_host);\r\r  /** Add a new GLine\r     * @param duration The duration of the line\r     * @param source The source of the line\r         * @param reason The reason for the line\r        * @param hostmask The hostmask\r         * @return True if the line was added successfully\r      */\r    bool add_gline(long duration, const char* source, const char* reason, const char* hostmask);\r\r  /** Add a new QLine\r     * @param duration The duration of the line\r     * @param source The source of the line\r         * @param reason The reason for the line\r        * @param nickname The nickmask\r         * @return True if the line was added successfully\r      */\r    bool add_qline(long duration, const char* source, const char* reason, const char* nickname);\r\r  /** Add a new ZLine\r     * @param duration The duration of the line\r     * @param source The source of the line\r         * @param reason The reason for the line\r        * @param ipaddr The IP mask\r    * @return True if the line was added successfully\r      */\r    bool add_zline(long duration, const char* source, const char* reason, const char* ipaddr);\r\r    /** Add a new KLine\r     * @param duration The duration of the line\r     * @param source The source of the line\r         * @param reason The reason for the line\r        * @param hostmask The hostmask\r         * @return True if the line was added successfully\r      */\r    bool add_kline(long duration, const char* source, const char* reason, const char* hostmask);\r\r  /** Add a new ELine\r     * @param duration The duration of the line\r     * @param source The source of the line\r         * @param reason The reason for the line\r        * @param hostmask The hostmask\r         * @return True if the line was added successfully\r      */\r    bool add_eline(long duration, const char* source, const char* reason, const char* hostmask);\r\r  /** Delete a GLine\r      * @param hostmask The host to remove\r   * @param simulate If this is true, don't actually remove the line, just return\r         * @return True if the line was deleted successfully\r    */\r    bool del_gline(const char* hostmask, bool simulate = false);\r\r  /** Delete a QLine\r      * @param nickname The nick to remove\r   * @param simulate If this is true, don't actually remove the line, just return\r         * @return True if the line was deleted successfully\r    */\r    bool del_qline(const char* nickname, bool simulate = false);\r\r  /** Delete a ZLine\r      * @param ipaddr The IP to remove\r       * @param simulate If this is true, don't actually remove the line, just return\r         * @return True if the line was deleted successfully\r    */\r    bool del_zline(const char* ipaddr, bool simulate = false);\r\r    /** Delete a KLine\r      * @param hostmask The host to remove\r   * @param simulate If this is true, don't actually remove the line, just return\r         * @return True if the line was deleted successfully\r    */\r    bool del_kline(const char* hostmask, bool simulate = false);\r\r  /** Delete a ELine\r      * @param hostmask The host to remove\r   * @param simulate If this is true, don't actually remove the line, just return\r         * @return True if the line was deleted successfully\r    */\r    bool del_eline(const char* hostmask, bool simulate = false);\r\r  /** Check if a nickname matches a QLine\r         * @return nick The nick to check against\r       * @return The reason for the line if there is a match, or NULL if there is no match\r    */\r    QLine* matches_qline(const char* nick, bool permonly = false);\r\r        /** Check if a hostname matches a GLine\r         * @param user The user to check against\r        * @return The reason for the line if there is a match, or NULL if there is no match\r    */\r    GLine* matches_gline(userrec* user, bool permonly = false);\r\r   /** Check if a IP matches a ZLine\r       * @param ipaddr The IP to check against\r        * @return The reason for the line if there is a match, or NULL if there is no match\r    */\r    ZLine* matches_zline(const char* ipaddr, bool permonly = false);\r\r      /** Check if a hostname matches a KLine\r         * @param user The user to check against\r        * @return The reason for the line if there is a match, or NULL if there is no match\r    */\r    KLine* matches_kline(userrec* user, bool permonly = false);\r\r   /** Check if a hostname matches a ELine\r         * @param user The user to check against\r        * @return The reason for the line if there is a match, or NULL if there is no match\r    */\r    ELine* matches_exception(userrec* user, bool permonly = false);\r\r       /** Expire any pending non-permenant lines\r      */\r    void expire_lines();\r\r  /** Apply any new lines\r         * @param What The types of lines to apply, from the set\r        * APPLY_GLINES | APPLY_KLINES | APPLY_QLINES | APPLY_ZLINES | APPLY_ALL\r        * | APPLY_LOCAL_ONLY\r   */\r    void apply_lines(const int What);\r\r     /** Handle /STATS K\r     * @param user The username making the query\r    * @param results The string_list to receive the results\r        */\r    void stats_k(userrec* user, string_list &results);\r\r    /** Handle /STATS G\r     * @param user The username making the query\r    * @param results The string_list to receive the results\r        */\r    void stats_g(userrec* user, string_list &results);\r\r    /** Handle /STATS Q\r     * @param user The username making the query\r    * @param results The string_list to receive the results\r        */\r    void stats_q(userrec* user, string_list &results);\r\r    /** Handle /STATS Z\r     * @param user The username making the query\r    * @param results The string_list to receive the results\r        */\r    void stats_z(userrec* user, string_list &results);\r\r    /** Handle /STATS E\r     * @param user The username making the query\r    * @param results The string_list to receive the results\r        */\r    void stats_e(userrec* user, string_list &results);\r\r    /** Change creation time of a GLine\r     * @param host The hostname to change\r   * @param create_Time The new creation time\r     */\r    void gline_set_creation_time(const char* host, time_t create_time);\r\r   /** Change creation time of a QLine\r     * @param nick The nickmask to change\r   * @param create_Time The new creation time\r     */\r    void qline_set_creation_time(const char* nick, time_t create_time);\r\r   /** Change creation time of a ZLine\r     * @param ip The ipmask to change\r       * @param create_Time The new creation time\r     */\r    void zline_set_creation_time(const char* ip, time_t create_time);\r\r     /** Change creation time of a ELine\r     * @param host The hostname to change\r   * @param create_Time The new creation time\r     */\r    void eline_set_creation_time(const char* host, time_t create_time);\r};\r\r#endif\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *         the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __XLINE_H
+#define __XLINE_H
+
+// include the common header files
+
+#include <string>
+#include <deque>
+#include <vector>
+#include "users.h"
+#include "channels.h"
+
+const int APPLY_GLINES         = 1;
+const int APPLY_KLINES         = 2;
+const int APPLY_QLINES         = 4;
+const int APPLY_ZLINES         = 8;
+const int APPLY_PERM_ONLY      = 16;
+const int APPLY_ALL            = APPLY_GLINES | APPLY_KLINES | APPLY_QLINES | APPLY_ZLINES;
+
+/** XLine is the base class for ban lines such as G lines and K lines.
+ */
+class CoreExport XLine : public classbase
+{
+  public:
+
+       /** Create an XLine.
+        * @param s_time The set time
+        * @param d The duration of the xline
+        * @param src The sender of the xline
+        * @param re The reason of the xline
+        */
+       XLine(time_t s_time, long d, const char* src, const char* re)
+               : set_time(s_time), duration(d)
+       {
+               source = strdup(src);
+               reason = strdup(re);
+               expiry = set_time + duration;
+       }
+
+       /** Destructor
+        */
+       virtual ~XLine()
+       {
+               free(reason);
+               free(source);
+       }
+       /** The time the line was added.
+        */
+       time_t set_time;
+       
+       /** The duration of the ban, or 0 if permenant
+        */
+       long duration;
+       
+       /** Source of the ban. This can be a servername or an oper nickname
+        */
+       char* source;
+       
+       /** Reason for the ban
+        */
+       char* reason;
+
+       /** Expiry time
+        */
+       time_t expiry;
+};
+
+/** KLine class
+ */
+class CoreExport KLine : public XLine
+{
+  public:
+       /** Create a K-Line.
+        * @param s_time The set time
+        * @param d The duration of the xline
+        * @param src The sender of the xline
+        * @param re The reason of the xline
+        * @param ident Ident to match
+        * @param host Host to match
+        */
+       KLine(time_t s_time, long d, const char* src, const char* re, const char* ident, const char* host) : XLine(s_time, d, src, re)
+       {
+               identmask = strdup(ident);
+               hostmask = strdup(host);
+       }
+
+       /** Destructor
+        */
+       ~KLine()
+       {
+               free(identmask);
+               free(hostmask);
+       }
+
+       /** Ident mask
+        */
+       char* identmask;
+       /** Host mask
+        */
+       char* hostmask;
+};
+
+/** GLine class
+ */
+class CoreExport GLine : public XLine
+{
+  public:
+       /** Create a G-Line.
+        * @param s_time The set time
+        * @param d The duration of the xline
+        * @param src The sender of the xline
+        * @param re The reason of the xline
+        * @param ident Ident to match
+        * @param host Host to match
+        */
+       GLine(time_t s_time, long d, const char* src, const char* re, const char* ident, const char* host) : XLine(s_time, d, src, re)
+       {
+               identmask = strdup(ident);
+               hostmask = strdup(host);
+       }
+
+       /** Destructor
+        */
+       ~GLine()
+       {
+               free(identmask);
+               free(hostmask);
+       }
+
+       /** Ident mask
+        */
+       char* identmask;
+       /** Host mask
+        */
+       char* hostmask;
+};
+
+/** ELine class
+ */
+class CoreExport ELine : public XLine
+{
+  public:
+       /** Create an E-Line.
+        * @param s_time The set time
+        * @param d The duration of the xline
+        * @param src The sender of the xline
+        * @param re The reason of the xline
+        * @param ident Ident to match
+        * @param host Host to match
+        */
+       ELine(time_t s_time, long d, const char* src, const char* re, const char* ident, const char* host) : XLine(s_time, d, src, re)
+       {
+               identmask = strdup(ident);
+               hostmask = strdup(host);
+       }
+
+       ~ELine()
+       {
+               free(identmask);
+               free(hostmask);
+       }
+
+       /** Ident mask
+        */
+       char* identmask;
+       /** Host mask
+        */
+       char* hostmask;
+};
+
+/** ZLine class
+ */
+class CoreExport ZLine : public XLine
+{
+  public:
+       /** Create a Z-Line.
+        * @param s_time The set time
+        * @param d The duration of the xline
+        * @param src The sender of the xline
+        * @param re The reason of the xline
+        * @param ip IP to match
+        */
+       ZLine(time_t s_time, long d, const char* src, const char* re, const char* ip) : XLine(s_time, d, src, re)
+       {
+               ipaddr = strdup(ip);
+       }
+
+       /** Destructor
+        */
+       ~ZLine()
+       {
+               free(ipaddr);
+       }
+
+       /** IP mask
+        */
+       char* ipaddr;
+};
+
+/** QLine class
+ */
+class CoreExport QLine : public XLine
+{
+  public:
+       /** Create a G-Line.
+        * @param s_time The set time
+        * @param d The duration of the xline
+        * @param src The sender of the xline
+        * @param re The reason of the xline
+        * @param nickname Nickname to match
+        */
+       QLine(time_t s_time, long d, const char* src, const char* re, const char* nickname) : XLine(s_time, d, src, re)
+       {
+               nick = strdup(nickname);
+       }
+
+       /** Destructor
+        */
+       ~QLine()
+       {
+               free(nick);
+       }
+
+       /** Nickname mask
+        */
+       char* nick;
+};
+
+/* Required forward declarations
+ */
+class ServerConfig;
+class InspIRCd;
+
+/** Initialize x line
+ */
+bool InitXLine(ServerConfig* conf, const char* tag);
+
+/** Done adding zlines from the config
+ */
+bool DoneZLine(ServerConfig* conf, const char* tag);
+/** Done adding qlines from the config
+ */
+bool DoneQLine(ServerConfig* conf, const char* tag);
+/** Done adding klines from the config
+ */
+bool DoneKLine(ServerConfig* conf, const char* tag);
+/** Done adding elines from the config
+ */
+bool DoneELine(ServerConfig* conf, const char* tag);
+
+/** Add a config-defined zline
+ */
+bool DoZLine(ServerConfig* conf, const char* tag, char** entries, ValueList &values, int* types);
+/** Add a config-defined qline
+ */
+bool DoQLine(ServerConfig* conf, const char* tag, char** entries, ValueList &values, int* types);
+/** Add a config-defined kline
+ */
+bool DoKLine(ServerConfig* conf, const char* tag, char** entries, ValueList &values, int* types);
+/** Add a config-defined eline
+ */
+bool DoELine(ServerConfig* conf, const char* tag, char** entries, ValueList &values, int* types);
+
+/** Contains an ident and host split into two strings
+ */
+typedef std::pair<std::string, std::string> IdentHostPair;
+
+/** XLineManager is a class used to manage glines, klines, elines, zlines and qlines.
+ */
+class CoreExport XLineManager
+{
+ protected:
+       /** The owner/creator of this class
+        */
+       InspIRCd* ServerInstance;
+
+       /** This functor is used by the std::sort() function to keep glines in order
+        */
+       static bool GSortComparison ( const GLine* one, const GLine* two );
+
+       /** This functor is used by the std::sort() function to keep elines in order
+        */
+       static bool ESortComparison ( const ELine* one, const ELine* two );
+
+       /** This functor is used by the std::sort() function to keep zlines in order
+        */
+       static bool ZSortComparison ( const ZLine* one, const ZLine* two );
+
+       /** This functor is used by the std::sort() function to keep klines in order
+        */
+       static bool KSortComparison ( const KLine* one, const KLine* two );
+
+       /** This functor is used by the std::sort() function to keep qlines in order
+        */
+       static bool QSortComparison ( const QLine* one, const QLine* two );
+ public:
+       /* Lists for temporary lines with an expiry time */
+
+       /** Temporary KLines */
+       std::vector<KLine*> klines;
+
+       /** Temporary Glines */
+       std::vector<GLine*> glines;
+
+       /** Temporary Zlines */
+       std::vector<ZLine*> zlines;
+
+       /** Temporary QLines */
+       std::vector<QLine*> qlines;
+
+       /** Temporary ELines */
+       std::vector<ELine*> elines;
+
+       /* Seperate lists for perm XLines that isnt checked by expiry functions */
+
+       /** Permenant KLines */
+       std::vector<KLine*> pklines;
+
+       /** Permenant GLines */
+       std::vector<GLine*> pglines;
+
+       /** Permenant ZLines */
+       std::vector<ZLine*> pzlines;
+
+       /** Permenant QLines */
+       std::vector<QLine*> pqlines;
+
+       /** Permenant ELines */
+       std::vector<ELine*> pelines;
+       
+       /** Constructor
+        * @param Instance A pointer to the creator object
+        */
+       XLineManager(InspIRCd* Instance);
+
+       /** Split an ident and host into two seperate strings.
+        * This allows for faster matching.
+        */
+       IdentHostPair IdentSplit(const std::string &ident_and_host);
+
+       /** Add a new GLine
+        * @param duration The duration of the line
+        * @param source The source of the line
+        * @param reason The reason for the line
+        * @param hostmask The hostmask
+        * @return True if the line was added successfully
+        */
+       bool add_gline(long duration, const char* source, const char* reason, const char* hostmask);
+
+       /** Add a new QLine
+        * @param duration The duration of the line
+        * @param source The source of the line
+        * @param reason The reason for the line
+        * @param nickname The nickmask
+        * @return True if the line was added successfully
+        */
+       bool add_qline(long duration, const char* source, const char* reason, const char* nickname);
+
+       /** Add a new ZLine
+        * @param duration The duration of the line
+        * @param source The source of the line
+        * @param reason The reason for the line
+        * @param ipaddr The IP mask
+        * @return True if the line was added successfully
+        */
+       bool add_zline(long duration, const char* source, const char* reason, const char* ipaddr);
+
+       /** Add a new KLine
+        * @param duration The duration of the line
+        * @param source The source of the line
+        * @param reason The reason for the line
+        * @param hostmask The hostmask
+        * @return True if the line was added successfully
+        */
+       bool add_kline(long duration, const char* source, const char* reason, const char* hostmask);
+
+       /** Add a new ELine
+        * @param duration The duration of the line
+        * @param source The source of the line
+        * @param reason The reason for the line
+        * @param hostmask The hostmask
+        * @return True if the line was added successfully
+        */
+       bool add_eline(long duration, const char* source, const char* reason, const char* hostmask);
+
+       /** Delete a GLine
+        * @param hostmask The host to remove
+        * @param simulate If this is true, don't actually remove the line, just return
+        * @return True if the line was deleted successfully
+        */
+       bool del_gline(const char* hostmask, bool simulate = false);
+
+       /** Delete a QLine
+        * @param nickname The nick to remove
+        * @param simulate If this is true, don't actually remove the line, just return
+        * @return True if the line was deleted successfully
+        */
+       bool del_qline(const char* nickname, bool simulate = false);
+
+       /** Delete a ZLine
+        * @param ipaddr The IP to remove
+        * @param simulate If this is true, don't actually remove the line, just return
+        * @return True if the line was deleted successfully
+        */
+       bool del_zline(const char* ipaddr, bool simulate = false);
+
+       /** Delete a KLine
+        * @param hostmask The host to remove
+        * @param simulate If this is true, don't actually remove the line, just return
+        * @return True if the line was deleted successfully
+        */
+       bool del_kline(const char* hostmask, bool simulate = false);
+
+       /** Delete a ELine
+        * @param hostmask The host to remove
+        * @param simulate If this is true, don't actually remove the line, just return
+        * @return True if the line was deleted successfully
+        */
+       bool del_eline(const char* hostmask, bool simulate = false);
+
+       /** Check if a nickname matches a QLine
+        * @return nick The nick to check against
+        * @return The reason for the line if there is a match, or NULL if there is no match
+        */
+       QLine* matches_qline(const char* nick, bool permonly = false);
+
+       /** Check if a hostname matches a GLine
+        * @param user The user to check against
+        * @return The reason for the line if there is a match, or NULL if there is no match
+        */
+       GLine* matches_gline(userrec* user, bool permonly = false);
+
+       /** Check if a IP matches a ZLine
+        * @param ipaddr The IP to check against
+        * @return The reason for the line if there is a match, or NULL if there is no match
+        */
+       ZLine* matches_zline(const char* ipaddr, bool permonly = false);
+
+       /** Check if a hostname matches a KLine
+        * @param user The user to check against
+        * @return The reason for the line if there is a match, or NULL if there is no match
+        */
+       KLine* matches_kline(userrec* user, bool permonly = false);
+
+       /** Check if a hostname matches a ELine
+        * @param user The user to check against
+        * @return The reason for the line if there is a match, or NULL if there is no match
+        */
+       ELine* matches_exception(userrec* user, bool permonly = false);
+
+       /** Expire any pending non-permenant lines
+        */
+       void expire_lines();
+
+       /** Apply any new lines
+        * @param What The types of lines to apply, from the set
+        * APPLY_GLINES | APPLY_KLINES | APPLY_QLINES | APPLY_ZLINES | APPLY_ALL
+        * | APPLY_LOCAL_ONLY
+        */
+       void apply_lines(const int What);
+
+       /** Handle /STATS K
+        * @param user The username making the query
+        * @param results The string_list to receive the results
+        */
+       void stats_k(userrec* user, string_list &results);
+
+       /** Handle /STATS G
+        * @param user The username making the query
+        * @param results The string_list to receive the results
+        */
+       void stats_g(userrec* user, string_list &results);
+
+       /** Handle /STATS Q
+        * @param user The username making the query
+        * @param results The string_list to receive the results
+        */
+       void stats_q(userrec* user, string_list &results);
+
+       /** Handle /STATS Z
+        * @param user The username making the query
+        * @param results The string_list to receive the results
+        */
+       void stats_z(userrec* user, string_list &results);
+
+       /** Handle /STATS E
+        * @param user The username making the query
+        * @param results The string_list to receive the results
+        */
+       void stats_e(userrec* user, string_list &results);
+
+       /** Change creation time of a GLine
+        * @param host The hostname to change
+        * @param create_Time The new creation time
+        */
+       void gline_set_creation_time(const char* host, time_t create_time);
+
+       /** Change creation time of a QLine
+        * @param nick The nickmask to change
+        * @param create_Time The new creation time
+        */
+       void qline_set_creation_time(const char* nick, time_t create_time);
+
+       /** Change creation time of a ZLine
+        * @param ip The ipmask to change
+        * @param create_Time The new creation time
+        */
+       void zline_set_creation_time(const char* ip, time_t create_time);
+
+       /** Change creation time of a ELine
+        * @param host The hostname to change
+        * @param create_Time The new creation time
+        */
+       void eline_set_creation_time(const char* host, time_t create_time);
+};
+
+#endif
+
index 3e1a38333b75a5cfcb323a22b4a06915cc2a7fb0..b384ac10911f17ac5518df0b49fb842a9876aa76 100644 (file)
@@ -1 +1,282 @@
-#\r# Copyright 2002-2007 The ChatSpike Development Team\r# <brain@chatspike.net>\r# <Craig@chatspike.net>\r#\r# Licensed under GPL, please see the COPYING file\r# for more information\r#\r\rpackage make::configure;\ruse Exporter 'import';\ruse POSIX;\ruse make::utilities;\r@EXPORT = qw(promptnumeric dumphash is_dir getmodules getrevision getcompilerflags getlinkerflags getdependencies resolve_directory yesno showhelp promptstring_s);\r\rmy $no_svn = 0;\r\rsub yesno {\r        my ($flag,$prompt) = @_;\r       print "$prompt [\033[1;32m$main::config{$flag}\033[0m] -> ";\r   chomp($tmp = <STDIN>);\r if ($tmp eq "") { $tmp = $main::config{$flag} }\r        if (($tmp eq "") || ($tmp =~ /^y/i))\r   {\r              $main::config{$flag} = "y";\r    }\r      else\r   {\r              $main::config{$flag} = "n";\r    }\r      return;\r}\r\rsub resolve_directory\r{\r     my $ret = $_[0];\r       eval\r   {\r              use File::Spec;\r                $ret = File::Spec->rel2abs($_[0]);\r     };\r     return $ret;\r}\r\rsub getrevision {\r      if ($no_svn)\r   {\r              return "0";\r    }\r      my $data = `svn info`;\r if ($data eq "")\r       {\r              $no_svn = 1;\r           $rev = "0";\r            return $rev;\r   }\r      $data =~ /Revision: (\d+)/;\r    my $rev = $1;\r  if (!defined($rev))\r    {\r              $rev = "0";\r    }\r      return $rev;\r}\r\rsub getcompilerflags {\r my ($file) = @_;\r       open(FLAGS, $file);\r    while (<FLAGS>) {\r              if ($_ =~ /^\/\* \$CompileFlags: (.+) \*\/$/) {\r                        close(FLAGS);\r                  return translate_functions($1,$file);\r          }\r      }\r      close(FLAGS);\r  return undef;\r}\r\rsub getlinkerflags {\r  my ($file) = @_;\r       open(FLAGS, $file);\r    while (<FLAGS>) {\r              if ($_ =~ /^\/\* \$LinkerFlags: (.+) \*\/$/) {\r                 close(FLAGS);\r                  return translate_functions($1,$file);\r          }\r      }\r      close(FLAGS);\r  return undef;\r}\r\rsub getdependencies {\r my ($file) = @_;\r       open(FLAGS, $file);\r    while (<FLAGS>) {\r              if ($_ =~ /^\/\* \$ModDep: (.+) \*\/$/) {\r                      close(FLAGS);\r                  return translate_functions($1,$file);\r          }\r      }\r      close(FLAGS);\r  return undef;\r}\r\r\rsub getmodules\r{\r     my $i = 0;\r     print "Detecting modules ";\r    opendir(DIRHANDLE, "src/modules");\r     foreach $name (sort readdir(DIRHANDLE))\r        {\r              if ($name =~ /^m_(.+)\.cpp$/)\r          {\r                      $mod = $1;\r                     if ($mod !~ /_static$/)\r                        {\r                              $main::modlist[$i++] = $mod;\r                           print ".";\r                     }\r              }\r      }\r      closedir(DIRHANDLE);\r   print "\nOk, $i modules.\n";\r}\r\rsub promptnumeric($$)\r{\r        my $continue = 0;\r      my ($prompt, $configitem) = @_;\r        while (!$continue)\r     {\r              print "Please enter the maximum $prompt?\n";\r           print "[\033[1;32m$main::config{$configitem}\033[0m] -> ";\r             chomp($var = <STDIN>);\r         if ($var eq "")\r                {\r                      $var = $main::config{$configitem};\r             }\r              if ($var =~ /^\d+$/) {\r                 # We don't care what the number is, set it and be on our way.\r                  $main::config{$configitem} = $var;\r                     $continue = 1;\r                 print "\n";\r            } else {\r                       print "You must enter a number in this field. Please try again.\n\n";\r          }\r      }\r}\r\rsub promptstring_s($$)\r{\r  my ($prompt,$default) = @_;\r    my $var;\r       print "$prompt\n";\r     print "[\033[1;32m$default\033[0m] -> ";\r       chomp($var = <STDIN>);\r $var = $default if $var eq "";\r print "\n";\r    return $var;\r}\r\rsub dumphash()\r{\r       print "\n\033[1;32mPre-build configuration is complete!\033[0m\n\n";\r   print "\033[0mBase install path:\033[1;32m\t\t$main::config{BASE_DIR}\033[0m\n";\r       print "\033[0mConfig path:\033[1;32m\t\t\t$main::config{CONFIG_DIR}\033[0m\n";\r print "\033[0mModule path:\033[1;32m\t\t\t$main::config{MODULE_DIR}\033[0m\n";\r print "\033[0mLibrary path:\033[1;32m\t\t\t$main::config{LIBRARY_DIR}\033[0m\n";\r       print "\033[0mMax connections:\033[1;32m\t\t$main::config{MAX_CLIENT}\033[0m\n";\r       print "\033[0mMax nickname length:\033[1;32m\t\t$main::config{NICK_LENGT}\033[0m\n";\r   print "\033[0mMax channel length:\033[1;32m\t\t$main::config{CHAN_LENGT}\033[0m\n";\r    print "\033[0mMax mode length:\033[1;32m\t\t$main::config{MAXI_MODES}\033[0m\n";\r       print "\033[0mMax ident length:\033[1;32m\t\t$main::config{MAX_IDENT}\033[0m\n";\r       print "\033[0mMax quit length:\033[1;32m\t\t$main::config{MAX_QUIT}\033[0m\n";\r print "\033[0mMax topic length:\033[1;32m\t\t$main::config{MAX_TOPIC}\033[0m\n";\r       print "\033[0mMax kick length:\033[1;32m\t\t$main::config{MAX_KICK}\033[0m\n";\r print "\033[0mMax name length:\033[1;32m\t\t$main::config{MAX_GECOS}\033[0m\n";\r        print "\033[0mMax away length:\033[1;32m\t\t$main::config{MAX_AWAY}\033[0m\n";\r print "\033[0mGCC Version Found:\033[1;32m\t\t$main::config{GCCVER}.x\033[0m\n";\r       print "\033[0mCompiler program:\033[1;32m\t\t$main::config{CC}\033[0m\n";\r      print "\033[0mStatic modules:\033[1;32m\t\t\t$main::config{STATIC_LINK}\033[0m\n";\r     print "\033[0mIPv6 Support:\033[1;32m\t\t\t$main::config{IPV6}\033[0m\n";\r      print "\033[0mIPv6 to IPv4 Links:\033[1;32m\t\t$main::config{SUPPORT_IP6LINKS}\033[0m\n";\r      print "\033[0mGnuTLS Support:\033[1;32m\t\t\t$main::config{USE_GNUTLS}\033[0m\n";\r      print "\033[0mOpenSSL Support:\033[1;32m\t\t$main::config{USE_OPENSSL}\033[0m\n\n";\r}\r\rsub is_dir\r{\r    my ($path) = @_;\r       if (chdir($path))\r      {\r              chdir($main::this);\r            return 1;\r      }\r      else\r   {\r              # Just in case..\r               chdir($main::this);\r            return 0;\r      }\r}\r\rsub showhelp\r{\r    chomp($PWD = `pwd`);\r   print "Usage: configure [options]\r\r*** NOTE: NON-INTERACTIVE CONFIGURE IS *NOT* SUPPORTED BY THE ***\r*** INSPIRCD DEVELOPMENT TEAM. DO NOT ASK FOR HELP REGARDING  ***\r***     NON-INTERACTIVE CONFIGURE ON THE FORUMS OR ON IRC!    ***\r\rOptions: [defaults in brackets after descriptions]\r\rWhen no options are specified, interactive\rconfiguration is started and you must specify\rany required values manually. If one or more\roptions are specified, non-interactive configuration\ris started, and any omitted values are defaulted.\r\rArguments with a single \"-\" symbol, as in\rInspIRCd 1.0.x, are also allowed.\r\r  --disable-interactive        Sets no options intself, but\r                               will disable any interactive prompting.\r  --update                     Update makefiles and dependencies\r  --modupdate                  Detect new modules and write makefiles\r  --svnupdate {--rebuild}      Update working copy via subversion\r                                {and optionally rebuild if --rebuild\r                                 is also specified}\r  --clean                      Remove .config.cache file and go interactive\r  --enable-gnutls              Enable GnuTLS module [no]\r  --enable-openssl             Enable OpenSSL module [no]\r  --with-nick-length=[n]       Specify max. nick length [32]\r  --with-channel-length=[n]    Specify max. channel length [64]\r  --with-max-clients=[n]       Specify maximum number of users\r                               which may connect locally\r  --enable-optimization=[n]    Optimize using -O[n] gcc flag\r  --enable-epoll               Enable epoll() where supported [set]\r  --enable-kqueue              Enable kqueue() where supported [set]\r  --disable-epoll              Do not enable epoll(), fall back\r                               to select() [not set]\r  --disable-kqueue             Do not enable kqueue(), fall back\r                               to select() [not set]\r  --enable-ipv6                Build ipv6 native InspIRCd [no]\r  --enable-remote-ipv6         Build with ipv6 support for remote\r                               servers on the network [yes]\r  --disable-remote-ipv6        Do not allow remote ipv6 servers [not set]\r  --with-cc=[filename]         Use an alternative g++ binary to\r                               build InspIRCd [g++]\r  --with-ident-length=[n]      Specify max length of ident [12]\r  --with-quit-length=[n]       Specify max length of quit [200]\r  --with-topic-length=[n]      Specify max length of topic [350]\r  --with-kick-length=[n]       Specify max length of kick [200]\r  --with-gecos-length=[n]      Specify max length of gecos [150]\r  --with-away-length=[n]       Specify max length of away [150]\r  --with-max-modes=[n]         Specify max modes per line which\r                               have parameters [20]\r  --with-maxbuf=[n]            Change the per message buffer size [512]\r                               DO NOT ALTER THIS OPTION WITHOUT GOOD REASON\r                               AS IT *WILL* BREAK CLIENTS!!!\r  --prefix=[directory]         Base directory to install into (if defined,\r                               can automatically define config, module, bin\r                         and library dirs as subdirectories of prefix)\r                               [$PWD]\r  --config-dir=[directory]     Config file directory for config and SSL certs\r                               [$PWD/conf]\r  --module-dir=[directory]     Modules directory for loadable modules\r                               [$PWD/modules]\r  --binary-dir=[directory]     Binaries directory for core binary\r                               [$PWD/bin]\r  --library-dir=[directory]    Library directory for core libraries\r                               [$PWD/lib]\r  --help                       Show this help text and exit\r\r";\r      exit(0);\r}\r\r1;\r\r
\ No newline at end of file
+#
+# Copyright 2002-2007 The ChatSpike Development Team
+# <brain@chatspike.net>
+# <Craig@chatspike.net>
+#
+# Licensed under GPL, please see the COPYING file
+# for more information
+#
+
+package make::configure;
+use Exporter 'import';
+use POSIX;
+use make::utilities;
+@EXPORT = qw(promptnumeric dumphash is_dir getmodules getrevision getcompilerflags getlinkerflags getdependencies resolve_directory yesno showhelp promptstring_s);
+
+my $no_svn = 0;
+
+sub yesno {
+       my ($flag,$prompt) = @_;
+       print "$prompt [\033[1;32m$main::config{$flag}\033[0m] -> ";
+       chomp($tmp = <STDIN>);
+       if ($tmp eq "") { $tmp = $main::config{$flag} }
+       if (($tmp eq "") || ($tmp =~ /^y/i))
+       {
+               $main::config{$flag} = "y";
+       }
+       else
+       {
+               $main::config{$flag} = "n";
+       }
+       return;
+}
+
+sub resolve_directory
+{
+       my $ret = $_[0];
+       eval
+       {
+               use File::Spec;
+               $ret = File::Spec->rel2abs($_[0]);
+       };
+       return $ret;
+}
+
+sub getrevision {
+       if ($no_svn)
+       {
+               return "0";
+       }
+       my $data = `svn info`;
+       if ($data eq "")
+       {
+               $no_svn = 1;
+               $rev = "0";
+               return $rev;
+       }
+       $data =~ /Revision: (\d+)/;
+       my $rev = $1;
+       if (!defined($rev))
+       {
+               $rev = "0";
+       }
+       return $rev;
+}
+
+sub getcompilerflags {
+       my ($file) = @_;
+       open(FLAGS, $file);
+       while (<FLAGS>) {
+               if ($_ =~ /^\/\* \$CompileFlags: (.+) \*\/$/) {
+                       close(FLAGS);
+                       return translate_functions($1,$file);
+               }
+       }
+       close(FLAGS);
+       return undef;
+}
+
+sub getlinkerflags {
+       my ($file) = @_;
+       open(FLAGS, $file);
+       while (<FLAGS>) {
+               if ($_ =~ /^\/\* \$LinkerFlags: (.+) \*\/$/) {
+                       close(FLAGS);
+                       return translate_functions($1,$file);
+               }
+       }
+       close(FLAGS);
+       return undef;
+}
+
+sub getdependencies {
+       my ($file) = @_;
+       open(FLAGS, $file);
+       while (<FLAGS>) {
+               if ($_ =~ /^\/\* \$ModDep: (.+) \*\/$/) {
+                       close(FLAGS);
+                       return translate_functions($1,$file);
+               }
+       }
+       close(FLAGS);
+       return undef;
+}
+
+
+sub getmodules
+{
+       my $i = 0;
+       print "Detecting modules ";
+       opendir(DIRHANDLE, "src/modules");
+       foreach $name (sort readdir(DIRHANDLE))
+       {
+               if ($name =~ /^m_(.+)\.cpp$/)
+               {
+                       $mod = $1;
+                       if ($mod !~ /_static$/)
+                       {
+                               $main::modlist[$i++] = $mod;
+                               print ".";
+                       }
+               }
+       }
+       closedir(DIRHANDLE);
+       print "\nOk, $i modules.\n";
+}
+
+sub promptnumeric($$)
+{
+       my $continue = 0;
+       my ($prompt, $configitem) = @_;
+       while (!$continue)
+       {
+               print "Please enter the maximum $prompt?\n";
+               print "[\033[1;32m$main::config{$configitem}\033[0m] -> ";
+               chomp($var = <STDIN>);
+               if ($var eq "")
+               {
+                       $var = $main::config{$configitem};
+               }
+               if ($var =~ /^\d+$/) {
+                       # We don't care what the number is, set it and be on our way.
+                       $main::config{$configitem} = $var;
+                       $continue = 1;
+                       print "\n";
+               } else {
+                       print "You must enter a number in this field. Please try again.\n\n";
+               }
+       }
+}
+
+sub promptstring_s($$)
+{
+       my ($prompt,$default) = @_;
+       my $var;
+       print "$prompt\n";
+       print "[\033[1;32m$default\033[0m] -> ";
+       chomp($var = <STDIN>);
+       $var = $default if $var eq "";
+       print "\n";
+       return $var;
+}
+
+sub dumphash()
+{
+       print "\n\033[1;32mPre-build configuration is complete!\033[0m\n\n";
+       print "\033[0mBase install path:\033[1;32m\t\t$main::config{BASE_DIR}\033[0m\n";
+       print "\033[0mConfig path:\033[1;32m\t\t\t$main::config{CONFIG_DIR}\033[0m\n";
+       print "\033[0mModule path:\033[1;32m\t\t\t$main::config{MODULE_DIR}\033[0m\n";
+       print "\033[0mLibrary path:\033[1;32m\t\t\t$main::config{LIBRARY_DIR}\033[0m\n";
+       print "\033[0mMax connections:\033[1;32m\t\t$main::config{MAX_CLIENT}\033[0m\n";
+       print "\033[0mMax nickname length:\033[1;32m\t\t$main::config{NICK_LENGT}\033[0m\n";
+       print "\033[0mMax channel length:\033[1;32m\t\t$main::config{CHAN_LENGT}\033[0m\n";
+       print "\033[0mMax mode length:\033[1;32m\t\t$main::config{MAXI_MODES}\033[0m\n";
+       print "\033[0mMax ident length:\033[1;32m\t\t$main::config{MAX_IDENT}\033[0m\n";
+       print "\033[0mMax quit length:\033[1;32m\t\t$main::config{MAX_QUIT}\033[0m\n";
+       print "\033[0mMax topic length:\033[1;32m\t\t$main::config{MAX_TOPIC}\033[0m\n";
+       print "\033[0mMax kick length:\033[1;32m\t\t$main::config{MAX_KICK}\033[0m\n";
+       print "\033[0mMax name length:\033[1;32m\t\t$main::config{MAX_GECOS}\033[0m\n";
+       print "\033[0mMax away length:\033[1;32m\t\t$main::config{MAX_AWAY}\033[0m\n";
+       print "\033[0mGCC Version Found:\033[1;32m\t\t$main::config{GCCVER}.x\033[0m\n";
+       print "\033[0mCompiler program:\033[1;32m\t\t$main::config{CC}\033[0m\n";
+       print "\033[0mStatic modules:\033[1;32m\t\t\t$main::config{STATIC_LINK}\033[0m\n";
+       print "\033[0mIPv6 Support:\033[1;32m\t\t\t$main::config{IPV6}\033[0m\n";
+       print "\033[0mIPv6 to IPv4 Links:\033[1;32m\t\t$main::config{SUPPORT_IP6LINKS}\033[0m\n";
+       print "\033[0mGnuTLS Support:\033[1;32m\t\t\t$main::config{USE_GNUTLS}\033[0m\n";
+       print "\033[0mOpenSSL Support:\033[1;32m\t\t$main::config{USE_OPENSSL}\033[0m\n\n";
+}
+
+sub is_dir
+{
+       my ($path) = @_;
+       if (chdir($path))
+       {
+               chdir($main::this);
+               return 1;
+       }
+       else
+       {
+               # Just in case..
+               chdir($main::this);
+               return 0;
+       }
+}
+
+sub showhelp
+{
+       chomp($PWD = `pwd`);
+       print "Usage: configure [options]
+
+*** NOTE: NON-INTERACTIVE CONFIGURE IS *NOT* SUPPORTED BY THE ***
+*** INSPIRCD DEVELOPMENT TEAM. DO NOT ASK FOR HELP REGARDING  ***
+***     NON-INTERACTIVE CONFIGURE ON THE FORUMS OR ON IRC!    ***
+
+Options: [defaults in brackets after descriptions]
+
+When no options are specified, interactive
+configuration is started and you must specify
+any required values manually. If one or more
+options are specified, non-interactive configuration
+is started, and any omitted values are defaulted.
+
+Arguments with a single \"-\" symbol, as in
+InspIRCd 1.0.x, are also allowed.
+
+  --disable-interactive        Sets no options intself, but
+                               will disable any interactive prompting.
+  --update                     Update makefiles and dependencies
+  --modupdate                  Detect new modules and write makefiles
+  --svnupdate {--rebuild}      Update working copy via subversion
+                                {and optionally rebuild if --rebuild
+                                 is also specified}
+  --clean                      Remove .config.cache file and go interactive
+  --enable-gnutls              Enable GnuTLS module [no]
+  --enable-openssl             Enable OpenSSL module [no]
+  --with-nick-length=[n]       Specify max. nick length [32]
+  --with-channel-length=[n]    Specify max. channel length [64]
+  --with-max-clients=[n]       Specify maximum number of users
+                               which may connect locally
+  --enable-optimization=[n]    Optimize using -O[n] gcc flag
+  --enable-epoll               Enable epoll() where supported [set]
+  --enable-kqueue              Enable kqueue() where supported [set]
+  --disable-epoll              Do not enable epoll(), fall back
+                               to select() [not set]
+  --disable-kqueue             Do not enable kqueue(), fall back
+                               to select() [not set]
+  --enable-ipv6                Build ipv6 native InspIRCd [no]
+  --enable-remote-ipv6         Build with ipv6 support for remote
+                               servers on the network [yes]
+  --disable-remote-ipv6        Do not allow remote ipv6 servers [not set]
+  --with-cc=[filename]         Use an alternative g++ binary to
+                               build InspIRCd [g++]
+  --with-ident-length=[n]      Specify max length of ident [12]
+  --with-quit-length=[n]       Specify max length of quit [200]
+  --with-topic-length=[n]      Specify max length of topic [350]
+  --with-kick-length=[n]       Specify max length of kick [200]
+  --with-gecos-length=[n]      Specify max length of gecos [150]
+  --with-away-length=[n]       Specify max length of away [150]
+  --with-max-modes=[n]         Specify max modes per line which
+                               have parameters [20]
+  --with-maxbuf=[n]            Change the per message buffer size [512]
+                               DO NOT ALTER THIS OPTION WITHOUT GOOD REASON
+                               AS IT *WILL* BREAK CLIENTS!!!
+  --prefix=[directory]         Base directory to install into (if defined,
+                               can automatically define config, module, bin
+                              and library dirs as subdirectories of prefix)
+                               [$PWD]
+  --config-dir=[directory]     Config file directory for config and SSL certs
+                               [$PWD/conf]
+  --module-dir=[directory]     Modules directory for loadable modules
+                               [$PWD/modules]
+  --binary-dir=[directory]     Binaries directory for core binary
+                               [$PWD/bin]
+  --library-dir=[directory]    Library directory for core libraries
+                               [$PWD/lib]
+  --help                       Show this help text and exit
+
+";
+       exit(0);
+}
+
+1;
+
index 885a30603060fc038bc781fe7057466bd1d9ed5b..517e08b1faaa826e8ceb3ff38082fa57cef460fc 100644 (file)
@@ -1 +1,115 @@
-package make::gnutlscert;\r\ruse Exporter 'import';\ruse make::configure;\r@EXPORT = qw(make_gnutls_cert);\r\r\rsub make_gnutls_cert()\r{\r     open (FH, ">certtool.template");\r       my $timestr = time();\r  my $org = promptstring_s("Please enter the organization name", "My IRC Network");\r      my $unit = promptstring_s("Please enter the unit Name", "Server Admins");\r      my $state = promptstring_s("Pleae enter your state (two letter code)", "CA");\r  my $country = promptstring_s("Please enter your country", "Oompa Loompa Land");\r        my $commonname = promptstring_s("Please enter the certificate common name (hostname)", "irc.mynetwork.com");\r   my $email = promptstring_s("Please enter a contact email address", "oompa\@loompa.com");\r       print FH <<__END__;\r# X.509 Certificate options\r#\r# DN options\r\r# The organization of the subject.\rorganization = "$org"\r\r# The organizational unit of the subject.\runit = "$unit"\r\r# The locality of the subject.\r# locality =\r\r# The state of the certificate owner.\rstate = "$state"\r\r# The country of the subject. Two letter code.\rcountry = $country\r\r# The common name of the certificate owner.\rcn = "$commonname"\r\r# A user id of the certificate owner.\r#uid = "clauper"\r\r# If the supported DN OIDs are not adequate you can set\r# any OID here.\r# For example set the X.520 Title and the X.520 Pseudonym\r# by using OID and string pairs.\r#dn_oid = "2.5.4.12" "Dr." "2.5.4.65" "jackal"\r\r# This is deprecated and should not be used in new\r# certificates.\r# pkcs9_email = "none\@none.org"\r\r# The serial number of the certificate\rserial = $timestr\r\r# In how many days, counting from today, this certificate will expire.\rexpiration_days = 700\r\r# X.509 v3 extensions\r\r# A dnsname in case of a WWW server.\r#dns_name = "www.none.org"\r\r# An IP address in case of a server.\r#ip_address = "192.168.1.1"\r\r# An email in case of a person\remail = "$email"\r\r# An URL that has CRLs (certificate revocation lists)\r# available. Needed in CA certificates.\r#crl_dist_points = "http://www.getcrl.crl/getcrl/"\r\r# Whether this is a CA certificate or not\r#ca\r\r# Whether this certificate will be used for a TLS client\rtls_www_client\r\r# Whether this certificate will be used for a TLS server\rtls_www_server\r\r# Whether this certificate will be used to sign data (needed\r# in TLS DHE ciphersuites).\rsigning_key\r\r# Whether this certificate will be used to encrypt data (needed\r# in TLS RSA ciphersuites). Note that it is prefered to use different\r# keys for encryption and signing.\rencryption_key\r\r# Whether this key will be used to sign other certificates.\rcert_signing_key\r\r# Whether this key will be used to sign CRLs.\rcrl_signing_key\r\r# Whether this key will be used to sign code.\rcode_signing_key\r\r# Whether this key will be used to sign OCSP data.\rocsp_signing_key\r\r# Whether this key will be used for time stamping.\rtime_stamping_key\r__END__\rclose(FH);\rsystem("certtool --generate-privkey --outfile key.pem") or return 1;\rsystem("certtool --generate-self-signed --load-privkey key.pem --outfile cert.pem --template certtool.template") or return 1;\runlink("certtool.template");\r}\r\r1;\r\r
\ No newline at end of file
+package make::gnutlscert;
+
+use Exporter 'import';
+use make::configure;
+@EXPORT = qw(make_gnutls_cert);
+
+
+sub make_gnutls_cert()
+{
+       open (FH, ">certtool.template");
+       my $timestr = time();
+       my $org = promptstring_s("Please enter the organization name", "My IRC Network");
+       my $unit = promptstring_s("Please enter the unit Name", "Server Admins");
+       my $state = promptstring_s("Pleae enter your state (two letter code)", "CA");
+       my $country = promptstring_s("Please enter your country", "Oompa Loompa Land");
+       my $commonname = promptstring_s("Please enter the certificate common name (hostname)", "irc.mynetwork.com");
+       my $email = promptstring_s("Please enter a contact email address", "oompa\@loompa.com");
+       print FH <<__END__;
+# X.509 Certificate options
+#
+# DN options
+
+# The organization of the subject.
+organization = "$org"
+
+# The organizational unit of the subject.
+unit = "$unit"
+
+# The locality of the subject.
+# locality =
+
+# The state of the certificate owner.
+state = "$state"
+
+# The country of the subject. Two letter code.
+country = $country
+
+# The common name of the certificate owner.
+cn = "$commonname"
+
+# A user id of the certificate owner.
+#uid = "clauper"
+
+# If the supported DN OIDs are not adequate you can set
+# any OID here.
+# For example set the X.520 Title and the X.520 Pseudonym
+# by using OID and string pairs.
+#dn_oid = "2.5.4.12" "Dr." "2.5.4.65" "jackal"
+
+# This is deprecated and should not be used in new
+# certificates.
+# pkcs9_email = "none\@none.org"
+
+# The serial number of the certificate
+serial = $timestr
+
+# In how many days, counting from today, this certificate will expire.
+expiration_days = 700
+
+# X.509 v3 extensions
+
+# A dnsname in case of a WWW server.
+#dns_name = "www.none.org"
+
+# An IP address in case of a server.
+#ip_address = "192.168.1.1"
+
+# An email in case of a person
+email = "$email"
+
+# An URL that has CRLs (certificate revocation lists)
+# available. Needed in CA certificates.
+#crl_dist_points = "http://www.getcrl.crl/getcrl/"
+
+# Whether this is a CA certificate or not
+#ca
+
+# Whether this certificate will be used for a TLS client
+tls_www_client
+
+# Whether this certificate will be used for a TLS server
+tls_www_server
+
+# Whether this certificate will be used to sign data (needed
+# in TLS DHE ciphersuites).
+signing_key
+
+# Whether this certificate will be used to encrypt data (needed
+# in TLS RSA ciphersuites). Note that it is prefered to use different
+# keys for encryption and signing.
+encryption_key
+
+# Whether this key will be used to sign other certificates.
+cert_signing_key
+
+# Whether this key will be used to sign CRLs.
+crl_signing_key
+
+# Whether this key will be used to sign code.
+code_signing_key
+
+# Whether this key will be used to sign OCSP data.
+ocsp_signing_key
+
+# Whether this key will be used for time stamping.
+time_stamping_key
+__END__
+close(FH);
+system("certtool --generate-privkey --outfile key.pem") or return 1;
+system("certtool --generate-self-signed --load-privkey key.pem --outfile cert.pem --template certtool.template") or return 1;
+unlink("certtool.template");
+}
+
+1;
+
index cb94869f9974d18b6c692d7a4635aa9d5891f622..a4954e0be5fb651b758fd75160a427f35117cf91 100644 (file)
@@ -1 +1,36 @@
-package make::opensslcert;\r\ruse Exporter 'import';\ruse make::configure;\r@EXPORT = qw(make_openssl_cert);\r\r\rsub make_openssl_cert()\r{\r  open (FH, ">openssl.template");\r        my $org = promptstring_s("Please enter the organization name", "My IRC Network");\r      my $unit = promptstring_s("Please enter the unit Name", "Server Admins");\r      my $country = promptstring_s("Please enter your country (two letter code)", "US");\r     my $state = promptstring_s("Please enter your state or locality name", "Alaska");\r      my $city = promptstring_s("Please enter your city", "Factory Town");\r   my $email = promptstring_s("Please enter a contact email address", "oompa\@loompa.com");\r       my $commonname = promptstring_s("Please enter the common name (domain name) of the irc server", "example.inspircd.org");\r       print FH <<__END__;\r$country\r$state\r$city\r$org\r$unit\r$commonname\r$email\r__END__\rclose(FH);\r\rmy $time = promptstring_s("Please enter the number of days that this certificate is valid for","365");\r     \rsystem("cat openssl.template | openssl req -x509 -nodes -newkey rsa:1024 -keyout key.pem -out cert.pem -days $time 2>/dev/null");\rsystem("openssl dhparam -out dhparams.pem 1024");\runlink("openssl.template");\r}\r\r1;\r
\ No newline at end of file
+package make::opensslcert;
+
+use Exporter 'import';
+use make::configure;
+@EXPORT = qw(make_openssl_cert);
+
+
+sub make_openssl_cert()
+{
+       open (FH, ">openssl.template");
+       my $org = promptstring_s("Please enter the organization name", "My IRC Network");
+       my $unit = promptstring_s("Please enter the unit Name", "Server Admins");
+       my $country = promptstring_s("Please enter your country (two letter code)", "US");
+       my $state = promptstring_s("Please enter your state or locality name", "Alaska");
+       my $city = promptstring_s("Please enter your city", "Factory Town");
+       my $email = promptstring_s("Please enter a contact email address", "oompa\@loompa.com");
+       my $commonname = promptstring_s("Please enter the common name (domain name) of the irc server", "example.inspircd.org");
+       print FH <<__END__;
+$country
+$state
+$city
+$org
+$unit
+$commonname
+$email
+__END__
+close(FH);
+
+my $time = promptstring_s("Please enter the number of days that this certificate is valid for","365");
+       
+system("cat openssl.template | openssl req -x509 -nodes -newkey rsa:1024 -keyout key.pem -out cert.pem -days $time 2>/dev/null");
+system("openssl dhparam -out dhparams.pem 1024");
+unlink("openssl.template");
+}
+
+1;
index 873797f801065c1a963fd87a63b78f5ee4fc86a0..c00a541b337e33755b19a8ccb18af9cd74a9a1ff 100644 (file)
@@ -1 +1,383 @@
-#\r# Copyright 2002-2007 The ChatSpike Development Team\r# <brain@chatspike.net>\r# <Craig@chatspike.net>\r#\r# Licensed under GPL, please see the COPYING file\r# for more information\r#\r\rpackage make::utilities;\ruse Exporter 'import';\ruse POSIX;\ruse Getopt::Long;\r@EXPORT = qw(make_rpath pkgconfig_get_include_dirs pkgconfig_get_lib_dirs pkgconfig_check_version translate_functions promptstring vcheck);\r\r# Parse the output of a *_config program,\r# such as pcre_config, take out the -L\r# directive and return an rpath for it.\r\r# \033[1;32msrc/Makefile\033[0m\r\rmy %already_added = ();\r\rsub promptstring($$$$$)\r{\r  my ($prompt, $configitem, $default, $package, $commandlineswitch) = @_;\r        my $var;\r       if (!$main::interactive)\r       {\r              undef $opt_commandlineswitch;\r          GetOptions ("$commandlineswitch=s" => \$opt_commandlineswitch);\r                if (defined $opt_commandlineswitch)\r            {\r                      print "\033[1;32m$opt_commandlineswitch\033[0m\n";\r                     $var = $opt_commandlineswitch;\r         }\r              else\r           {\r                      die "Could not detect $package! Please specify the $prompt via the command line option \033[1;32m--$commandlineswitch=\"/path/to/file\"\033[0m";\r               }\r      }\r      else\r   {\r              print "\nPlease enter the $prompt?\n";\r         print "[\033[1;32m$default\033[0m] -> ";\r               chomp($var = <STDIN>);\r }\r      if ($var eq "")\r        {\r              $var = $default;\r       }\r      $main::config{$configitem} = $var;\r}\r\rsub make_rpath($;$)\r{\r    my ($executable, $module) = @_;\r        chomp($data = `$executable`);\r  my $output = "";\r       while ($data =~ /-L(\S+)/)\r     {\r              $libpath = $1;\r         if (!exists $already_added{$libpath})\r          {\r                      print "Adding extra library path to \033[1;32m$module\033[0m ... \033[1;32m$libpath\033[0m\n";\r                 $already_added{$libpath} = 1;\r          }\r              $output .= "-Wl,--rpath -Wl,$libpath -L$libpath ";\r             $data =~ s/-L(\S+)//;\r  }\r      return $output;\r}\r\rsub extend_pkg_path()\r{\r     if (!exists $ENV{PKG_CONFIG_PATH})\r     {\r              $ENV{PKG_CONFIG_PATH} = "/usr/lib/pkgconfig:/usr/local/lib/pkgconfig:/usr/local/libdata/pkgconfig:/usr/X11R6/libdata/pkgconfig";\r       }\r      else\r   {\r              $ENV{PKG_CONFIG_PATH} .= ":/usr/local/lib/pkgconfig:/usr/local/libdata/pkgconfig:/usr/X11R6/libdata/pkgconfig";\r        }\r}\r\rsub pkgconfig_get_include_dirs($$$;$)\r{\r   my ($packagename, $headername, $defaults, $module) = @_;\r\r      my $key = "default_includedir_$packagename";\r   if (exists $main::config{$key})\r        {\r              print "Locating include directory for package \033[1;32m$packagename\033[0m for module \033[1;32m$module\033[0m... ";\r          $ret = $main::config{$key};\r            print "\033[1;32m$ret\033[0m (cached)\n";\r              return $ret;\r   }\r\r     extend_pkg_path();\r\r    print "Locating include directory for package \033[1;32m$packagename\033[0m for module \033[1;32m$module\033[0m... ";\r\r $v = `pkg-config --modversion $packagename 2>/dev/null`;\r       $ret = `pkg-config --cflags $packagename 2>/dev/null`;\r\r        if ((!defined $v) || ($v eq ""))\r       {\r              $foo = `locate "$headername" | head -n 1`;\r             $foo =~ /(.+)\Q$headername\E/;\r         $find = $1;\r            chomp($find);\r          if ((defined $find) && ($find ne "") && ($find ne $packagename))\r               {\r                      print "(\033[1;32mFound via search\033[0m) ";\r                  $foo = "-I$1";\r         }\r              else\r           {\r                      $foo = " ";\r                    undef $v;\r              }\r              $ret = "$foo";\r }\r      if (($defaults ne "") && (($ret eq "") || (!defined $ret)))\r    {\r              $ret = "$foo " . $defaults;\r    }\r      chomp($ret);\r   if ((($ret eq " ") || (!defined $ret)) && ((!defined $v) || ($v eq "")))\r       {\r              my $key = "default_includedir_$packagename";\r           if (exists $main::config{$key})\r                {\r                      $ret = $main::config{$key};\r            }\r              else\r           {\r                      $headername =~ s/^\///;\r                        promptstring("path to the directory containing $headername", $key, "/usr/include",$packagename,"$packagename-includes");\r                       $packagename =~ tr/a-z/A-Z/;\r                   $main::config{$key} = "-I$main::config{$key}" . " $defaults -DVERSION_$packagename=\"$v\"";\r                    $main::config{$key} =~ s/^\s+//g;\r                      $ret = $main::config{$key};\r                    return $ret;\r           }\r      }\r      else\r   {\r              chomp($v);\r             my $key = "default_includedir_$packagename";\r           $packagename =~ tr/a-z/A-Z/;\r           $main::config{$key} = "$ret -DVERSION_$packagename=\"$v\"";\r            $main::config{$key} =~ s/^\s+//g;\r              $ret = $main::config{$key};\r            print "\033[1;32m$ret\033[0m (version $v)\n";\r  }\r      $ret =~ s/^\s+//g;\r     return $ret;\r}\r\rsub vcheck($$)\r{\r       my ($version1, $version2) = @_;\r        $version1 =~ s/\-r(\d+)/\.\1/g; # minor revs/patchlevels\r       $version2 =~ s/\-r(\d+)/\.\1/g;\r        $version1 =~ s/p(\d+)/\.\1/g;\r  $version2 =~ s/p(\d+)/\.\1/g;\r  $version1 =~ s/\-//g;\r  $version2 =~ s/\-//g;\r  $version1 =~ s/a-z//g;\r $version2 =~ s/a-z//g;\r my @v1 = split('\.', $version1);\r       my @v2 = split('\.', $version2);\r       for ($curr = 0; $curr < scalar(@v1); $curr++)\r  {\r              if ($v1[$curr] < $v2[$curr])\r           {\r                      return 0;\r              }\r      }\r      return 1;\r}\r\rsub pkgconfig_check_version($$;$)\r{\r       my ($packagename, $version, $module) = @_;\r\r    extend_pkg_path();\r\r    print "Checking version of package \033[1;32m$packagename\033[0m is >= \033[1;32m$version\033[0m... ";\r\r        $v = `pkg-config --modversion $packagename 2>/dev/null`;\r       if (defined $v)\r        {\r              chomp($v);\r     }\r      if ((defined $v) && ($v ne ""))\r        {\r              if (vcheck($v,$version) == 1)\r          {\r                      print "\033[1;32mYes (version $v)\033[0m\n";\r                   return 1;\r              }\r              else\r           {\r                      print "\033[1;32mNo (version $v)\033[0m\n";\r                    return 0;\r              }\r      }\r      # If we didnt find it, we  cant definitively say its too old.\r  # Return ok, and let pkgconflibs() or pkgconfincludes() pick up\r        # the missing library later on.\r        print "\033[1;32mNo (not found)\033[0m\n";\r     return 1;\r}\r\rsub pkgconfig_get_lib_dirs($$$;$)\r{\r       my ($packagename, $libname, $defaults, $module) = @_;\r\r my $key = "default_libdir_$packagename";\r       if (exists $main::config{$key})\r        {\r              print "Locating library directory for package \033[1;32m$packagename\033[0m for module \033[1;32m$module\033[0m... ";\r          $ret = $main::config{$key};\r            print "\033[1;32m$ret\033[0m (cached)\n";\r              return $ret;\r   }\r\r     extend_pkg_path();\r\r    print "Locating library directory for package \033[1;32m$packagename\033[0m for module \033[1;32m$module\033[0m... ";\r\r $v = `pkg-config --modversion $packagename 2>/dev/null`;\r       $ret = `pkg-config --libs $packagename 2>/dev/null`;\r\r  if ((!defined $v) || ($v eq ""))\r       {\r              $foo = `locate "$libname" | head -n 1`;\r                $foo =~ /(.+)\Q$libname\E/;\r            $find = $1;\r            chomp($find);\r          if ((defined $find) && ($find ne "") && ($find ne $packagename))\r               {\r                      print "(\033[1;32mFound via search\033[0m) ";\r                  $foo = "-L$1";\r         }\r              else\r           {\r                      $foo = " ";\r                    undef $v;\r              }\r              $ret = "$foo";\r }\r\r     if (($defaults ne "") && (($ret eq "") || (!defined $ret)))\r    {\r              $ret = "$foo " . $defaults;\r    }\r      chomp($ret);\r   if ((($ret eq " ") || (!defined $ret)) && ((!defined $v) || ($v eq "")))\r       {\r              my $key = "default_libdir_$packagename";\r               if (exists $main::config{$key})\r                {\r                      $ret = $main::config{$key};\r            }\r              else\r           {\r                      $libname =~ s/^\///;\r                   promptstring("path to the directory containing $libname", $key, "/usr/lib",$packagename,"$packagename-libs");\r                  $main::config{$key} = "-L$main::config{$key}" . " $defaults";\r                  $main::config{$key} =~ s/^\s+//g;\r                      $ret = $main::config{$key};\r                    return $ret;\r           }\r      }\r      else\r   {\r              chomp($v);\r             print "\033[1;32m$ret\033[0m (version $v)\n";\r          my $key = "default_libdir_$packagename";\r               $main::config{$key} = $ret;\r            $main::config{$key} =~ s/^\s+//g;\r              $ret =~ s/^\s+//g;\r     }\r      $ret =~ s/^\s+//g;\r     return $ret;\r}\r\r# Translate a $CompileFlags etc line and parse out function calls\r# to functions within these modules at configure time.\rsub translate_functions($$)\r{\r my ($line,$module) = @_;\r\r      eval\r   {\r              $module =~ /modules*\/(.+?)$/;\r         $module = $1;\r\r         # This is only a cursory check, just designed to catch casual accidental use of backticks.\r             # There are pleanty of ways around it, but its not supposed to be for security, just checking\r          # that people are using the new configuration api as theyre supposed to and not just using\r             # backticks instead of eval(), being as eval has accountability. People wanting to get around\r          # the accountability will do so anyway.\r                if (($line =~ /`/) && ($line !~ /eval\(.+?`.+?\)/))\r            {\r                      die "Developers should no longer use backticks in configuration macros. Please use exec() and eval() macros instead. Offending line: $line (In module: $module)";\r              }\r              while ($line =~ /exec\("(.+?)"\)/)\r             {\r                      print "Executing program for module \033[1;32m$module\033[0m ... \033[1;32m$1\033[0m\n";\r                       my $replace = `$1`;\r                    chomp($replace);\r                       $line =~ s/exec\("(.+?)"\)/$replace/;\r          }\r              while ($line =~ /eval\("(.+?)"\)/)\r             {\r                      print "Evaluating perl code for module \033[1;32m$module\033[0m ... ";\r                 my $tmpfile;\r                   do\r                     {\r                              $tmpfile = tmpnam();\r                   } until sysopen(TF, $tmpfile, O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW, 0700);\r                 print "(Created and executed \033[1;32m$tmpfile\033[0m)\n";\r                    print TF $1;\r                   close TF;\r                      my $replace = `perl $tmpfile`;\r                 chomp($replace);\r                       $line =~ s/eval\("(.+?)"\)/$replace/;\r          }\r              while ($line =~ /pkgconflibs\("(.+?)","(.+?)","(.+?)"\)/)\r              {\r                      my $replace = pkgconfig_get_lib_dirs($1, $2, $3, $module);\r                     $line =~ s/pkgconflibs\("(.+?)","(.+?)","(.+?)"\)/$replace/;\r           }\r              while ($line =~ /pkgconfversion\("(.+?)","(.+?)"\)/)\r           {\r                      if (pkgconfig_check_version($1, $2, $module) != 1)\r                     {\r                              die "Version of package $1 is too old. Please upgrade it to version \033[1;32m$2\033[0m or greater and try again.";\r                    }\r                      # This doesnt actually get replaced with anything\r                      $line =~ s/pkgconfversion\("(.+?)","(.+?)"\)//;\r                }\r              while ($line =~ /pkgconflibs\("(.+?)","(.+?)",""\)/)\r           {\r                      my $replace = pkgconfig_get_lib_dirs($1, $2, "", $module);\r                     $line =~ s/pkgconflibs\("(.+?)","(.+?)",""\)/$replace/;\r                }\r              while ($line =~ /pkgconfincludes\("(.+?)","(.+?)",""\)/)\r               {\r                      my $replace = pkgconfig_get_include_dirs($1, $2, "", $module);\r                 $line =~ s/pkgconfincludes\("(.+?)","(.+?)",""\)/$replace/;\r            }\r              while ($line =~ /pkgconfincludes\("(.+?)","(.+?)","(.+?)"\)/)\r          {\r                      my $replace = pkgconfig_get_include_dirs($1, $2, $3, $module);\r                 $line =~ s/pkgconfincludes\("(.+?)","(.+?)","(.+?)"\)/$replace/;\r               }\r              while ($line =~ /rpath\("(.+?)"\)/)\r            {\r                      my $replace = make_rpath($1,$module);\r                  $replace = "" if ($^O =~ /darwin/i);\r                   $line =~ s/rpath\("(.+?)"\)/$replace/;\r         }\r      };\r     if ($@)\r        {\r              $err = $@;\r             $err =~ s/at .+? line \d+.*//g;\r                print "\n\nConfiguration failed. The following error occured:\n\n$err\n";\r              exit;\r  }\r      else\r   {\r              return $line;\r  }\r}\r\r1;\r\r
\ No newline at end of file
+#
+# Copyright 2002-2007 The ChatSpike Development Team
+# <brain@chatspike.net>
+# <Craig@chatspike.net>
+#
+# Licensed under GPL, please see the COPYING file
+# for more information
+#
+
+package make::utilities;
+use Exporter 'import';
+use POSIX;
+use Getopt::Long;
+@EXPORT = qw(make_rpath pkgconfig_get_include_dirs pkgconfig_get_lib_dirs pkgconfig_check_version translate_functions promptstring vcheck);
+
+# Parse the output of a *_config program,
+# such as pcre_config, take out the -L
+# directive and return an rpath for it.
+
+# \033[1;32msrc/Makefile\033[0m
+
+my %already_added = ();
+
+sub promptstring($$$$$)
+{
+       my ($prompt, $configitem, $default, $package, $commandlineswitch) = @_;
+       my $var;
+       if (!$main::interactive)
+       {
+               undef $opt_commandlineswitch;
+               GetOptions ("$commandlineswitch=s" => \$opt_commandlineswitch);
+               if (defined $opt_commandlineswitch)
+               {
+                       print "\033[1;32m$opt_commandlineswitch\033[0m\n";
+                       $var = $opt_commandlineswitch;
+               }
+               else
+               {
+                       die "Could not detect $package! Please specify the $prompt via the command line option \033[1;32m--$commandlineswitch=\"/path/to/file\"\033[0m";
+               }
+       }
+       else
+       {
+               print "\nPlease enter the $prompt?\n";
+               print "[\033[1;32m$default\033[0m] -> ";
+               chomp($var = <STDIN>);
+       }
+       if ($var eq "")
+       {
+               $var = $default;
+       }
+       $main::config{$configitem} = $var;
+}
+
+sub make_rpath($;$)
+{
+       my ($executable, $module) = @_;
+       chomp($data = `$executable`);
+       my $output = "";
+       while ($data =~ /-L(\S+)/)
+       {
+               $libpath = $1;
+               if (!exists $already_added{$libpath})
+               {
+                       print "Adding extra library path to \033[1;32m$module\033[0m ... \033[1;32m$libpath\033[0m\n";
+                       $already_added{$libpath} = 1;
+               }
+               $output .= "-Wl,--rpath -Wl,$libpath -L$libpath ";
+               $data =~ s/-L(\S+)//;
+       }
+       return $output;
+}
+
+sub extend_pkg_path()
+{
+       if (!exists $ENV{PKG_CONFIG_PATH})
+       {
+               $ENV{PKG_CONFIG_PATH} = "/usr/lib/pkgconfig:/usr/local/lib/pkgconfig:/usr/local/libdata/pkgconfig:/usr/X11R6/libdata/pkgconfig";
+       }
+       else
+       {
+               $ENV{PKG_CONFIG_PATH} .= ":/usr/local/lib/pkgconfig:/usr/local/libdata/pkgconfig:/usr/X11R6/libdata/pkgconfig";
+       }
+}
+
+sub pkgconfig_get_include_dirs($$$;$)
+{
+       my ($packagename, $headername, $defaults, $module) = @_;
+
+       my $key = "default_includedir_$packagename";
+       if (exists $main::config{$key})
+       {
+               print "Locating include directory for package \033[1;32m$packagename\033[0m for module \033[1;32m$module\033[0m... ";
+               $ret = $main::config{$key};
+               print "\033[1;32m$ret\033[0m (cached)\n";
+               return $ret;
+       }
+
+       extend_pkg_path();
+
+       print "Locating include directory for package \033[1;32m$packagename\033[0m for module \033[1;32m$module\033[0m... ";
+
+       $v = `pkg-config --modversion $packagename 2>/dev/null`;
+       $ret = `pkg-config --cflags $packagename 2>/dev/null`;
+
+       if ((!defined $v) || ($v eq ""))
+       {
+               $foo = `locate "$headername" | head -n 1`;
+               $foo =~ /(.+)\Q$headername\E/;
+               $find = $1;
+               chomp($find);
+               if ((defined $find) && ($find ne "") && ($find ne $packagename))
+               {
+                       print "(\033[1;32mFound via search\033[0m) ";
+                       $foo = "-I$1";
+               }
+               else
+               {
+                       $foo = " ";
+                       undef $v;
+               }
+               $ret = "$foo";
+       }
+       if (($defaults ne "") && (($ret eq "") || (!defined $ret)))
+       {
+               $ret = "$foo " . $defaults;
+       }
+       chomp($ret);
+       if ((($ret eq " ") || (!defined $ret)) && ((!defined $v) || ($v eq "")))
+       {
+               my $key = "default_includedir_$packagename";
+               if (exists $main::config{$key})
+               {
+                       $ret = $main::config{$key};
+               }
+               else
+               {
+                       $headername =~ s/^\///;
+                       promptstring("path to the directory containing $headername", $key, "/usr/include",$packagename,"$packagename-includes");
+                       $packagename =~ tr/a-z/A-Z/;
+                       $main::config{$key} = "-I$main::config{$key}" . " $defaults -DVERSION_$packagename=\"$v\"";
+                       $main::config{$key} =~ s/^\s+//g;
+                       $ret = $main::config{$key};
+                       return $ret;
+               }
+       }
+       else
+       {
+               chomp($v);
+               my $key = "default_includedir_$packagename";
+               $packagename =~ tr/a-z/A-Z/;
+               $main::config{$key} = "$ret -DVERSION_$packagename=\"$v\"";
+               $main::config{$key} =~ s/^\s+//g;
+               $ret = $main::config{$key};
+               print "\033[1;32m$ret\033[0m (version $v)\n";
+       }
+       $ret =~ s/^\s+//g;
+       return $ret;
+}
+
+sub vcheck($$)
+{
+       my ($version1, $version2) = @_;
+       $version1 =~ s/\-r(\d+)/\.\1/g; # minor revs/patchlevels
+       $version2 =~ s/\-r(\d+)/\.\1/g;
+       $version1 =~ s/p(\d+)/\.\1/g;
+       $version2 =~ s/p(\d+)/\.\1/g;
+       $version1 =~ s/\-//g;
+       $version2 =~ s/\-//g;
+       $version1 =~ s/a-z//g;
+       $version2 =~ s/a-z//g;
+       my @v1 = split('\.', $version1);
+       my @v2 = split('\.', $version2);
+       for ($curr = 0; $curr < scalar(@v1); $curr++)
+       {
+               if ($v1[$curr] < $v2[$curr])
+               {
+                       return 0;
+               }
+       }
+       return 1;
+}
+
+sub pkgconfig_check_version($$;$)
+{
+       my ($packagename, $version, $module) = @_;
+
+       extend_pkg_path();
+
+       print "Checking version of package \033[1;32m$packagename\033[0m is >= \033[1;32m$version\033[0m... ";
+
+       $v = `pkg-config --modversion $packagename 2>/dev/null`;
+       if (defined $v)
+       {
+               chomp($v);
+       }
+       if ((defined $v) && ($v ne ""))
+       {
+               if (vcheck($v,$version) == 1)
+               {
+                       print "\033[1;32mYes (version $v)\033[0m\n";
+                       return 1;
+               }
+               else
+               {
+                       print "\033[1;32mNo (version $v)\033[0m\n";
+                       return 0;
+               }
+       }
+       # If we didnt find it, we  cant definitively say its too old.
+       # Return ok, and let pkgconflibs() or pkgconfincludes() pick up
+       # the missing library later on.
+       print "\033[1;32mNo (not found)\033[0m\n";
+       return 1;
+}
+
+sub pkgconfig_get_lib_dirs($$$;$)
+{
+       my ($packagename, $libname, $defaults, $module) = @_;
+
+       my $key = "default_libdir_$packagename";
+       if (exists $main::config{$key})
+       {
+               print "Locating library directory for package \033[1;32m$packagename\033[0m for module \033[1;32m$module\033[0m... ";
+               $ret = $main::config{$key};
+               print "\033[1;32m$ret\033[0m (cached)\n";
+               return $ret;
+       }
+
+       extend_pkg_path();
+
+       print "Locating library directory for package \033[1;32m$packagename\033[0m for module \033[1;32m$module\033[0m... ";
+
+       $v = `pkg-config --modversion $packagename 2>/dev/null`;
+       $ret = `pkg-config --libs $packagename 2>/dev/null`;
+
+       if ((!defined $v) || ($v eq ""))
+       {
+               $foo = `locate "$libname" | head -n 1`;
+               $foo =~ /(.+)\Q$libname\E/;
+               $find = $1;
+               chomp($find);
+               if ((defined $find) && ($find ne "") && ($find ne $packagename))
+               {
+                       print "(\033[1;32mFound via search\033[0m) ";
+                       $foo = "-L$1";
+               }
+               else
+               {
+                       $foo = " ";
+                       undef $v;
+               }
+               $ret = "$foo";
+       }
+
+       if (($defaults ne "") && (($ret eq "") || (!defined $ret)))
+       {
+               $ret = "$foo " . $defaults;
+       }
+       chomp($ret);
+       if ((($ret eq " ") || (!defined $ret)) && ((!defined $v) || ($v eq "")))
+       {
+               my $key = "default_libdir_$packagename";
+               if (exists $main::config{$key})
+               {
+                       $ret = $main::config{$key};
+               }
+               else
+               {
+                       $libname =~ s/^\///;
+                       promptstring("path to the directory containing $libname", $key, "/usr/lib",$packagename,"$packagename-libs");
+                       $main::config{$key} = "-L$main::config{$key}" . " $defaults";
+                       $main::config{$key} =~ s/^\s+//g;
+                       $ret = $main::config{$key};
+                       return $ret;
+               }
+       }
+       else
+       {
+               chomp($v);
+               print "\033[1;32m$ret\033[0m (version $v)\n";
+               my $key = "default_libdir_$packagename";
+               $main::config{$key} = $ret;
+               $main::config{$key} =~ s/^\s+//g;
+               $ret =~ s/^\s+//g;
+       }
+       $ret =~ s/^\s+//g;
+       return $ret;
+}
+
+# Translate a $CompileFlags etc line and parse out function calls
+# to functions within these modules at configure time.
+sub translate_functions($$)
+{
+       my ($line,$module) = @_;
+
+       eval
+       {
+               $module =~ /modules*\/(.+?)$/;
+               $module = $1;
+
+               # This is only a cursory check, just designed to catch casual accidental use of backticks.
+               # There are pleanty of ways around it, but its not supposed to be for security, just checking
+               # that people are using the new configuration api as theyre supposed to and not just using
+               # backticks instead of eval(), being as eval has accountability. People wanting to get around
+               # the accountability will do so anyway.
+               if (($line =~ /`/) && ($line !~ /eval\(.+?`.+?\)/))
+               {
+                       die "Developers should no longer use backticks in configuration macros. Please use exec() and eval() macros instead. Offending line: $line (In module: $module)";
+               }
+               while ($line =~ /exec\("(.+?)"\)/)
+               {
+                       print "Executing program for module \033[1;32m$module\033[0m ... \033[1;32m$1\033[0m\n";
+                       my $replace = `$1`;
+                       chomp($replace);
+                       $line =~ s/exec\("(.+?)"\)/$replace/;
+               }
+               while ($line =~ /eval\("(.+?)"\)/)
+               {
+                       print "Evaluating perl code for module \033[1;32m$module\033[0m ... ";
+                       my $tmpfile;
+                       do
+                       {
+                               $tmpfile = tmpnam();
+                       } until sysopen(TF, $tmpfile, O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW, 0700);
+                       print "(Created and executed \033[1;32m$tmpfile\033[0m)\n";
+                       print TF $1;
+                       close TF;
+                       my $replace = `perl $tmpfile`;
+                       chomp($replace);
+                       $line =~ s/eval\("(.+?)"\)/$replace/;
+               }
+               while ($line =~ /pkgconflibs\("(.+?)","(.+?)","(.+?)"\)/)
+               {
+                       my $replace = pkgconfig_get_lib_dirs($1, $2, $3, $module);
+                       $line =~ s/pkgconflibs\("(.+?)","(.+?)","(.+?)"\)/$replace/;
+               }
+               while ($line =~ /pkgconfversion\("(.+?)","(.+?)"\)/)
+               {
+                       if (pkgconfig_check_version($1, $2, $module) != 1)
+                       {
+                               die "Version of package $1 is too old. Please upgrade it to version \033[1;32m$2\033[0m or greater and try again.";
+                       }
+                       # This doesnt actually get replaced with anything
+                       $line =~ s/pkgconfversion\("(.+?)","(.+?)"\)//;
+               }
+               while ($line =~ /pkgconflibs\("(.+?)","(.+?)",""\)/)
+               {
+                       my $replace = pkgconfig_get_lib_dirs($1, $2, "", $module);
+                       $line =~ s/pkgconflibs\("(.+?)","(.+?)",""\)/$replace/;
+               }
+               while ($line =~ /pkgconfincludes\("(.+?)","(.+?)",""\)/)
+               {
+                       my $replace = pkgconfig_get_include_dirs($1, $2, "", $module);
+                       $line =~ s/pkgconfincludes\("(.+?)","(.+?)",""\)/$replace/;
+               }
+               while ($line =~ /pkgconfincludes\("(.+?)","(.+?)","(.+?)"\)/)
+               {
+                       my $replace = pkgconfig_get_include_dirs($1, $2, $3, $module);
+                       $line =~ s/pkgconfincludes\("(.+?)","(.+?)","(.+?)"\)/$replace/;
+               }
+               while ($line =~ /rpath\("(.+?)"\)/)
+               {
+                       my $replace = make_rpath($1,$module);
+                       $replace = "" if ($^O =~ /darwin/i);
+                       $line =~ s/rpath\("(.+?)"\)/$replace/;
+               }
+       };
+       if ($@)
+       {
+               $err = $@;
+               $err =~ s/at .+? line \d+.*//g;
+               print "\n\nConfiguration failed. The following error occured:\n\n$err\n";
+               exit;
+       }
+       else
+       {
+               return $line;
+       }
+}
+
+1;
+
index ef6ff5ccf6f3e601df5199f4ef5b9d74163b0e4e..9c002773b9a406469c7d71f0cf34c6dbbe12876f 100644 (file)
@@ -1 +1,95 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd_config.h"\r#include "base.h"\r#include <time.h>\r#include "inspircd.h"\r\rconst int bitfields[]           =       {1,2,4,8,16,32,64,128};\rconst int inverted_bitfields[]  =       {~1,~2,~4,~8,~16,~32,~64,~128};\r\rclassbase::classbase()\r{\r this->age = time(NULL);\r}\r\rbool Extensible::Shrink(const std::string &key)\r{\r   /* map::size_type map::erase( const key_type& key );\r    * returns the number of elements removed, std::map\r     * is single-associative so this should only be 0 or 1\r  */\r    return this->Extension_Items.erase(key);\r}\r\rvoid Extensible::GetExtList(std::deque<std::string> &list)\r{\r       for (ExtensibleStore::iterator u = Extension_Items.begin(); u != Extension_Items.end(); u++)\r   {\r              list.push_back(u->first);\r      }\r}\r\rvoid BoolSet::Set(int number)\r{\r   this->bits |= bitfields[number];\r}\r\rvoid BoolSet::Unset(int number)\r{\r  this->bits &= inverted_bitfields[number];\r}\r\rvoid BoolSet::Invert(int number)\r{\r        this->bits ^= bitfields[number];\r}\r\rbool BoolSet::Get(int number)\r{\r    return ((this->bits | bitfields[number]) > 0);\r}\r\rbool BoolSet::operator==(BoolSet other)\r{\r    return (this->bits == other.bits);\r}\r\rBoolSet BoolSet::operator|(BoolSet other)\r{\r      BoolSet x(this->bits | other.bits);\r    return x;\r}\r\rBoolSet BoolSet::operator&(BoolSet other)\r{\r       BoolSet x(this->bits & other.bits);\r    return x;\r}\r\rBoolSet::BoolSet()\r{\r      this->bits = 0;\r}\r\rBoolSet::BoolSet(char bitmask)\r{\r    this->bits = bitmask;\r}\r\rbool BoolSet::operator=(BoolSet other)\r{\r      this->bits = other.bits;\r       return true;\r}\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd_config.h"
+#include "base.h"
+#include <time.h>
+#include "inspircd.h"
+
+const int bitfields[]           =       {1,2,4,8,16,32,64,128};
+const int inverted_bitfields[]  =       {~1,~2,~4,~8,~16,~32,~64,~128};
+
+classbase::classbase()
+{
+       this->age = time(NULL);
+}
+
+bool Extensible::Shrink(const std::string &key)
+{
+       /* map::size_type map::erase( const key_type& key );
+        * returns the number of elements removed, std::map
+        * is single-associative so this should only be 0 or 1
+        */
+       return this->Extension_Items.erase(key);
+}
+
+void Extensible::GetExtList(std::deque<std::string> &list)
+{
+       for (ExtensibleStore::iterator u = Extension_Items.begin(); u != Extension_Items.end(); u++)
+       {
+               list.push_back(u->first);
+       }
+}
+
+void BoolSet::Set(int number)
+{
+       this->bits |= bitfields[number];
+}
+
+void BoolSet::Unset(int number)
+{
+       this->bits &= inverted_bitfields[number];
+}
+
+void BoolSet::Invert(int number)
+{
+       this->bits ^= bitfields[number];
+}
+
+bool BoolSet::Get(int number)
+{
+       return ((this->bits | bitfields[number]) > 0);
+}
+
+bool BoolSet::operator==(BoolSet other)
+{
+       return (this->bits == other.bits);
+}
+
+BoolSet BoolSet::operator|(BoolSet other)
+{
+       BoolSet x(this->bits | other.bits);
+       return x;
+}
+
+BoolSet BoolSet::operator&(BoolSet other)
+{
+       BoolSet x(this->bits & other.bits);
+       return x;
+}
+
+BoolSet::BoolSet()
+{
+       this->bits = 0;
+}
+
+BoolSet::BoolSet(char bitmask)
+{
+       this->bits = bitmask;
+}
+
+bool BoolSet::operator=(BoolSet other)
+{
+       this->bits = other.bits;
+       return true;
+}
index 74543925e78b428be4c279df9ea520fcec0b1f82..b44a863b4fc501eb8e4ae1a92b2d503ddcd86e98 100644 (file)
@@ -1 +1,1067 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include <stdarg.h>\r#include "configreader.h"\r#include "users.h"\r#include "modules.h"\r#include "wildcard.h"\r#include "mode.h"\r\rchanrec::chanrec(InspIRCd* Instance) : ServerInstance(Instance)\r{\r    *name = *topic = *setby = *key = 0;\r    maxbans = created = topicset = limit = 0;\r      memset(&modes,0,64);\r   age = ServerInstance->Time(true);\r}\r\rvoid chanrec::SetMode(char mode,bool mode_on)\r{\r   modes[mode-65] = mode_on;\r      if (!mode_on)\r          this->SetModeParam(mode,"",false);\r}\r\r\rvoid chanrec::SetModeParam(char mode,const char* parameter,bool mode_on)\r{\r      CustomModeList::iterator n = custom_mode_params.find(mode);     \r\r      if (mode_on)\r   {\r              if (n == custom_mode_params.end())\r                     custom_mode_params[mode] = strdup(parameter);\r  }\r      else\r   {\r              if (n != custom_mode_params.end())\r             {\r                      free(n->second);\r                       custom_mode_params.erase(n);\r           }\r      }\r}\r\rbool chanrec::IsModeSet(char mode)\r{\r      return modes[mode-65];\r}\r\rstd::string chanrec::GetModeParameter(char mode)\r{\r   switch (mode)\r  {\r              case 'k':\r                      return this->key;\r              case 'l':\r                      return ConvToStr(this->limit);\r         default:\r                       CustomModeList::iterator n = custom_mode_params.find(mode);\r                    if (n != custom_mode_params.end())\r                             return n->second;\r                      return "";\r             break;\r }\r}\r\rlong chanrec::GetUserCounter()\r{\r  return (this->internal_userlist.size());\r}\r\rvoid chanrec::AddUser(userrec* user)\r{\r     internal_userlist[user] = user->nick;\r}\r\runsigned long chanrec::DelUser(userrec* user)\r{\r       CUListIter a = internal_userlist.find(user);\r   \r       if (a != internal_userlist.end())\r      {\r              internal_userlist.erase(a);\r            /* And tidy any others... */\r           DelOppedUser(user);\r            DelHalfoppedUser(user);\r                DelVoicedUser(user);\r   }\r      \r       return internal_userlist.size();\r}\r\rbool chanrec::HasUser(userrec* user)\r{\r     return (internal_userlist.find(user) != internal_userlist.end());\r}\r\rvoid chanrec::AddOppedUser(userrec* user)\r{\r       internal_op_userlist[user] = user->nick;\r}\r\rvoid chanrec::DelOppedUser(userrec* user)\r{\r        CUListIter a = internal_op_userlist.find(user);\r        if (a != internal_op_userlist.end())\r   {\r              internal_op_userlist.erase(a);\r         return;\r        }\r}\r\rvoid chanrec::AddHalfoppedUser(userrec* user)\r{\r   internal_halfop_userlist[user] = user->nick;\r}\r\rvoid chanrec::DelHalfoppedUser(userrec* user)\r{\r        CUListIter a = internal_halfop_userlist.find(user);\r\r   if (a != internal_halfop_userlist.end())\r       {   \r           internal_halfop_userlist.erase(a);\r     }\r}\r\rvoid chanrec::AddVoicedUser(userrec* user)\r{\r      internal_voice_userlist[user] = user->nick;\r}\r\rvoid chanrec::DelVoicedUser(userrec* user)\r{\r    CUListIter a = internal_voice_userlist.find(user);\r     \r       if (a != internal_voice_userlist.end())\r        {\r              internal_voice_userlist.erase(a);\r      }\r}\r\rCUList* chanrec::GetUsers()\r{\r     return &internal_userlist;\r}\r\rCUList* chanrec::GetOppedUsers()\r{\r       return &internal_op_userlist;\r}\r\rCUList* chanrec::GetHalfoppedUsers()\r{\r        return &internal_halfop_userlist;\r}\r\rCUList* chanrec::GetVoicedUsers()\r{\r       return &internal_voice_userlist;\r}\r\rvoid chanrec::SetDefaultModes()\r{\r  irc::spacesepstream list(ServerInstance->Config->DefaultModes);\r        std::string modeseq = list.GetToken();\r std::string parameter;\r userrec* dummyuser = new userrec(ServerInstance);\r      dummyuser->SetFd(FD_MAGIC_NUMBER);\r\r    for (std::string::iterator n = modeseq.begin(); n != modeseq.end(); ++n)\r       {\r              ModeHandler* mode = ServerInstance->Modes->FindMode(*n, MODETYPE_CHANNEL);\r             if (mode)\r              {\r                      if (mode->GetNumParams(true))\r                          parameter = list.GetToken().c_str();\r                   else\r                           parameter.clear();\r\r                    mode->OnModeChange(dummyuser, dummyuser, this, parameter, true);\r               }\r      }\r\r     delete dummyuser;\r}\r\r/* \r * add a channel to a user, creating the record for it if needed and linking\r * it to the user record \r */\rchanrec* chanrec::JoinUser(InspIRCd* Instance, userrec *user, const char* cn, bool override, const char* key, time_t TS)\r{\r if (!user || !cn)\r              return NULL;\r\r  bool new_channel = false;\r      char cname[MAXBUF];\r    int MOD_RESULT = 0;\r    strlcpy(cname,cn,CHANMAX);\r\r    std::string privs;\r\r    chanrec* Ptr = Instance->FindChan(cname);\r\r     if (!Ptr)\r      {\r              if ((!IS_LOCAL(user)) && (!TS))\r                        Instance->Log(DEBUG,"*** BUG *** chanrec::JoinUser called for REMOTE user '%s' on channel '%s' but no TS given!", user->nick, cn);\r\r            privs = "@";\r\r          if (IS_LOCAL(user) && override == false)\r               {\r                      MOD_RESULT = 0;\r                        FOREACH_RESULT_I(Instance,I_OnUserPreJoin,OnUserPreJoin(user,NULL,cname,privs));\r                       if (MOD_RESULT == 1)\r                           return NULL;\r           }\r\r             /* create a new one */\r         Ptr = new chanrec(Instance);\r           (*(Instance->chanlist))[cname] = Ptr;\r\r         strlcpy(Ptr->name, cname,CHANMAX);\r\r            /* As spotted by jilles, dont bother to set this on remote users */\r            if (IS_LOCAL(user))\r                    Ptr->SetDefaultModes();\r\r               Ptr->created = TS ? TS : Instance->Time();\r             Ptr->age = Ptr->created;\r               *Ptr->topic = 0;\r               *Ptr->setby = 0;\r               Ptr->topicset = 0;\r             new_channel = true;\r    }\r      else\r   {\r              /* Already on the channel */\r           if (Ptr->HasUser(user))\r                        return NULL;\r\r          /*\r              * remote users are allowed us to bypass channel modes\r          * and bans (used by servers)\r           */\r            if (IS_LOCAL(user) && override == false)\r               {\r                      MOD_RESULT = 0;\r                        FOREACH_RESULT_I(Instance,I_OnUserPreJoin,OnUserPreJoin(user,Ptr,cname,privs));\r                        if (MOD_RESULT == 1)\r                   {\r                              return NULL;\r                   }\r                      else if (MOD_RESULT == 0)\r                      {\r                              if (*Ptr->key)\r                         {\r                                      MOD_RESULT = 0;\r                                        FOREACH_RESULT_I(Instance,I_OnCheckKey,OnCheckKey(user, Ptr, key ? key : ""));\r                                 if (!MOD_RESULT)\r                                       {\r                                              if ((!key) || strcmp(key,Ptr->key))\r                                            {\r                                                      user->WriteServ("475 %s %s :Cannot join channel (Incorrect channel key)",user->nick, Ptr->name);\r                                                       return NULL;\r                                           }\r                                      }\r                              }\r                              if (Ptr->modes[CM_INVITEONLY])\r                         {\r                                      MOD_RESULT = 0;\r                                        FOREACH_RESULT_I(Instance,I_OnCheckInvite,OnCheckInvite(user, Ptr));\r                                   if (!MOD_RESULT)\r                                       {\r                                              if (user->IsInvited(Ptr->name))\r                                                {\r                                                      /* user was invited to channel */\r                                                      /* there may be an optional channel NOTICE here */\r                                             }\r                                              else\r                                           {\r                                                      user->WriteServ("473 %s %s :Cannot join channel (Invite only)",user->nick, Ptr->name);\r                                                 return NULL;\r                                           }\r                                      }\r                                      user->RemoveInvite(Ptr->name);\r                         }\r                              if (Ptr->limit)\r                                {\r                                      MOD_RESULT = 0;\r                                        FOREACH_RESULT_I(Instance,I_OnCheckLimit,OnCheckLimit(user, Ptr));\r                                     if (!MOD_RESULT)\r                                       {\r                                              if (Ptr->GetUserCounter() >= Ptr->limit)\r                                               {\r                                                      user->WriteServ("471 %s %s :Cannot join channel (Channel is full)",user->nick, Ptr->name);\r                                                     return NULL;\r                                           }\r                                      }\r                              }\r                              if (Ptr->bans.size())\r                          {\r                                      if (Ptr->IsBanned(user))\r                                       {\r                                              user->WriteServ("474 %s %s :Cannot join channel (You're banned)",user->nick, Ptr->name);\r                                               return NULL;\r                                   }\r                              }\r                      }\r              }\r      }\r\r     /* NOTE: If the user is an oper here, we can extend their user->chans by up to\r  * OperMaxchans. For remote users which are not bound by the channel limits,\r    * we can extend infinitely. Otherwise, nope, youre restricted to MaxChans.\r     */\r    if (!IS_LOCAL(user) || override == true)\r       {\r              return chanrec::ForceChan(Instance, Ptr, user, privs);\r }\r      else if (IS_OPER(user))\r        {\r              /* Oper allows extension up to the OperMaxchans value */\r               if (user->chans.size() < Instance->Config->OperMaxChans)\r               {\r                      return chanrec::ForceChan(Instance, Ptr, user, privs);\r         }\r      }\r      else if (user->chans.size() < Instance->Config->MaxChans)\r      {\r              return chanrec::ForceChan(Instance, Ptr, user, privs);\r }\r\r\r    user->WriteServ("405 %s %s :You are on too many channels",user->nick, cname);\r\r if (new_channel)\r       {\r              /* Things went seriously pear shaped, so take this away. bwahaha. */\r           chan_hash::iterator n = Instance->chanlist->find(cname);\r               if (n != Instance->chanlist->end())\r            {\r                      Ptr->DelUser(user);\r                    DELETE(Ptr);\r                   Instance->chanlist->erase(n);\r          }\r      }\r\r     return NULL;\r}\r\rchanrec* chanrec::ForceChan(InspIRCd* Instance, chanrec* Ptr, userrec* user, const std::string &privs)\r{\r       userrec* dummyuser = new userrec(Instance);\r    std::string nick = user->nick;\r bool silent = false;\r\r  dummyuser->SetFd(FD_MAGIC_NUMBER);\r     Ptr->AddUser(user);\r\r   /* Just in case they have no permissions */\r    user->chans[Ptr] = 0;\r\r for (std::string::const_iterator x = privs.begin(); x != privs.end(); x++)\r     {\r              const char status = *x;\r                ModeHandler* mh = Instance->Modes->FindPrefix(status);\r         if (mh)\r                {\r                      Ptr->SetPrefix(user, status, mh->GetPrefixRank(), true);\r                       /* Make sure that the mode handler knows this mode was now set */\r                      mh->OnModeChange(dummyuser, dummyuser, Ptr, nick, true);\r\r                      switch (mh->GetPrefix())\r                       {\r                              /* These logic ops are SAFE IN THIS CASE\r                                * because if the entry doesnt exist,\r                           * addressing operator[] creates it.\r                            * If they do exist, it points to it.\r                           * At all other times where we dont want\r                                * to create an item if it doesnt exist, we\r                             * must stick to ::find().\r                              */\r                            case '@':\r                                      user->chans[Ptr] |= UCMODE_OP;\r                         break;\r                         case '%':\r                                      user->chans[Ptr] |= UCMODE_HOP;\r                                break;\r                         case '+':\r                                      user->chans[Ptr] |= UCMODE_VOICE;\r                              break;\r                 }\r              }\r      }\r\r     delete dummyuser;\r\r     FOREACH_MOD_I(Instance,I_OnUserJoin,OnUserJoin(user, Ptr, silent));\r\r   if (!silent)\r           Ptr->WriteChannel(user,"JOIN :%s",Ptr->name);\r\r /* Theyre not the first ones in here, make sure everyone else sees the modes we gave the user */\r       std::string ms = Instance->Modes->ModeString(user, Ptr);\r       if ((Ptr->GetUserCounter() > 1) && (ms.length()))\r              Ptr->WriteAllExceptSender(user, true, 0, "MODE %s +%s", Ptr->name, ms.c_str());\r\r       /* Major improvement by Brain - we dont need to be calculating all this pointlessly for remote users */\r        if (IS_LOCAL(user))\r    {\r              if (Ptr->topicset)\r             {\r                      user->WriteServ("332 %s %s :%s", user->nick, Ptr->name, Ptr->topic);\r                   user->WriteServ("333 %s %s %s %lu", user->nick, Ptr->name, Ptr->setby, (unsigned long)Ptr->topicset);\r          }\r              Ptr->UserList(user);\r   }\r      FOREACH_MOD_I(Instance,I_OnPostJoin,OnPostJoin(user, Ptr));\r    return Ptr;\r}\r\rbool chanrec::IsBanned(userrec* user)\r{\r char mask[MAXBUF];\r     int MOD_RESULT = 0;\r    FOREACH_RESULT(I_OnCheckBan,OnCheckBan(user, this));\r   if (!MOD_RESULT)\r       {\r              snprintf(mask, MAXBUF, "%s!%s@%s", user->nick, user->ident, user->GetIPString());\r              for (BanList::iterator i = this->bans.begin(); i != this->bans.end(); i++)\r             {\r                      /* This allows CIDR ban matching\r                        * \r                     *        Full masked host                      Full unmasked host                   IP with/without CIDR\r                       */\r                    if ((match(user->GetFullHost(),i->data)) || (match(user->GetFullRealHost(),i->data)) || (match(mask, i->data, true)))\r                  {\r                              return true;\r                   }\r              }\r      }\r      return false;\r}\r\r/* chanrec::PartUser\r * remove a channel from a users record, and return the number of users left.\r * Therefore, if this function returns 0 the caller should delete the chanrec.\r */\rlong chanrec::PartUser(userrec *user, const char* reason)\r{\r     bool silent = false;\r\r  if (!user)\r             return this->GetUserCounter();\r\r        UCListIter i = user->chans.find(this);\r if (i != user->chans.end())\r    {\r              FOREACH_MOD(I_OnUserPart,OnUserPart(user, this, reason ? reason : "", silent));\r\r               if (!silent)\r                   this->WriteChannel(user, "PART %s%s%s", this->name, reason ? " :" : "", reason ? reason : "");\r\r                user->chans.erase(i);\r          this->RemoveAllPrefixes(user);\r }\r\r     if (!this->DelUser(user)) /* if there are no users left on the channel... */\r   {\r              chan_hash::iterator iter = ServerInstance->chanlist->find(this->name);\r         /* kill the record */\r          if (iter != ServerInstance->chanlist->end())\r           {\r                      FOREACH_MOD(I_OnChannelDelete,OnChannelDelete(this));\r                  ServerInstance->chanlist->erase(iter);\r         }\r              return 0;\r      }\r\r     return this->GetUserCounter();\r}\r\rlong chanrec::ServerKickUser(userrec* user, const char* reason, bool triggerevents)\r{\r        bool silent = false;\r\r  if (!user || !reason)\r          return this->GetUserCounter();\r\r        if (IS_LOCAL(user))\r    {\r              if (!this->HasUser(user))\r              {\r                      /* Not on channel */\r                   return this->GetUserCounter();\r         }\r      }\r\r     if (triggerevents)\r     {\r              FOREACH_MOD(I_OnUserKick,OnUserKick(NULL, user, this, reason, silent));\r        }\r\r     UCListIter i = user->chans.find(this);\r if (i != user->chans.end())\r    {\r              if (!silent)\r                   this->WriteChannelWithServ(ServerInstance->Config->ServerName, "KICK %s %s :%s", this->name, user->nick, reason);\r\r             user->chans.erase(i);\r          this->RemoveAllPrefixes(user);\r }\r\r     if (!this->DelUser(user))\r      {\r              chan_hash::iterator iter = ServerInstance->chanlist->find(this->name);\r         /* kill the record */\r          if (iter != ServerInstance->chanlist->end())\r           {\r                      FOREACH_MOD(I_OnChannelDelete,OnChannelDelete(this));\r                  ServerInstance->chanlist->erase(iter);\r         }\r              return 0;\r      }\r\r     return this->GetUserCounter();\r}\r\rlong chanrec::KickUser(userrec *src, userrec *user, const char* reason)\r{\r    bool silent = false;\r\r  if (!src || !user || !reason)\r          return this->GetUserCounter();\r\r        if (IS_LOCAL(src))\r     {\r              if (!this->HasUser(user))\r              {\r                      src->WriteServ("441 %s %s %s :They are not on that channel",src->nick, user->nick, this->name);\r                        return this->GetUserCounter();\r         }\r              if ((ServerInstance->ULine(user->server)) && (!ServerInstance->ULine(src->server)))\r            {\r                      src->WriteServ("482 %s %s :Only a u-line may kick a u-line from a channel.",src->nick, this->name);\r                    return this->GetUserCounter();\r         }\r              int MOD_RESULT = 0;\r\r           if (!ServerInstance->ULine(src->server))\r               {\r                      MOD_RESULT = 0;\r                        FOREACH_RESULT(I_OnUserPreKick,OnUserPreKick(src,user,this,reason));\r                   if (MOD_RESULT == 1)\r                           return this->GetUserCounter();\r         }\r              /* Set to -1 by OnUserPreKick if explicit allow was set */\r             if (MOD_RESULT != -1)\r          {\r                      FOREACH_RESULT(I_OnAccessCheck,OnAccessCheck(src,user,this,AC_KICK));\r                  if ((MOD_RESULT == ACR_DENY) && (!ServerInstance->ULine(src->server)))\r                         return this->GetUserCounter();\r \r                       if ((MOD_RESULT == ACR_DEFAULT) || (!ServerInstance->ULine(src->server)))\r                      {\r                              int them = this->GetStatus(src);\r                               int us = this->GetStatus(user);\r                                if ((them < STATUS_HOP) || (them < us))\r                                {\r                                      src->WriteServ("482 %s %s :You must be a channel %soperator",src->nick, this->name, them == STATUS_HOP ? "" : "half-");\r                                        return this->GetUserCounter();\r                         }\r                      }\r              }\r      }\r\r     FOREACH_MOD(I_OnUserKick,OnUserKick(src, user, this, reason, silent));\r\r        UCListIter i = user->chans.find(this);\r if (i != user->chans.end())\r    {\r              /* zap it from the channel list of the user */\r         if (!silent)\r                   this->WriteChannel(src, "KICK %s %s :%s", this->name, user->nick, reason);\r\r            user->chans.erase(i);\r          this->RemoveAllPrefixes(user);\r }\r\r     if (!this->DelUser(user))\r      /* if there are no users left on the channel */\r        {\r              chan_hash::iterator iter = ServerInstance->chanlist->find(this->name);\r\r                /* kill the record */\r          if (iter != ServerInstance->chanlist->end())\r           {\r                      FOREACH_MOD(I_OnChannelDelete,OnChannelDelete(this));\r                  ServerInstance->chanlist->erase(iter);\r         }\r              return 0;\r      }\r\r     return this->GetUserCounter();\r}\r\rvoid chanrec::WriteChannel(userrec* user, char* text, ...)\r{\r char textbuffer[MAXBUF];\r       va_list argsPtr;\r\r      if (!user || !text)\r            return;\r\r       va_start(argsPtr, text);\r       vsnprintf(textbuffer, MAXBUF, text, argsPtr);\r  va_end(argsPtr);\r\r      this->WriteChannel(user, std::string(textbuffer));\r}\r\rvoid chanrec::WriteChannel(userrec* user, const std::string &text)\r{\r     CUList *ulist = this->GetUsers();\r      char tb[MAXBUF];\r\r      if (!user)\r             return;\r\r       snprintf(tb,MAXBUF,":%s %s",user->GetFullHost(),text.c_str());\r std::string out = tb;\r\r for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)\r      {\r              if (IS_LOCAL(i->first))\r                        i->first->Write(out);\r  }\r}\r\rvoid chanrec::WriteChannelWithServ(const char* ServName, const char* text, ...)\r{\r char textbuffer[MAXBUF];\r       va_list argsPtr;\r\r      if (!text)\r             return;\r\r       va_start(argsPtr, text);\r       vsnprintf(textbuffer, MAXBUF, text, argsPtr);\r  va_end(argsPtr);\r\r      this->WriteChannelWithServ(ServName, std::string(textbuffer));\r}\r\rvoid chanrec::WriteChannelWithServ(const char* ServName, const std::string &text)\r{\r  CUList *ulist = this->GetUsers();\r      char tb[MAXBUF];\r\r      snprintf(tb,MAXBUF,":%s %s",ServName ? ServName : ServerInstance->Config->ServerName, text.c_str());\r   std::string out = tb;\r\r for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)\r      {\r              if (IS_LOCAL(i->first))\r                        i->first->Write(out);\r  }\r}\r\r/* write formatted text from a source user to all users on a channel except\r * for the sender (for privmsg etc) */\rvoid chanrec::WriteAllExceptSender(userrec* user, bool serversource, char status, char* text, ...)\r{\r   char textbuffer[MAXBUF];\r       va_list argsPtr;\r\r      if (!text)\r             return;\r\r       va_start(argsPtr, text);\r       vsnprintf(textbuffer, MAXBUF, text, argsPtr);\r  va_end(argsPtr);\r\r      this->WriteAllExceptSender(user, serversource, status, std::string(textbuffer));\r}\r\rvoid chanrec::WriteAllExcept(userrec* user, bool serversource, char status, CUList &except_list, char* text, ...)\r{\r        char textbuffer[MAXBUF];\r       va_list argsPtr;\r\r      if (!text)\r             return;\r\r       va_start(argsPtr, text);\r       vsnprintf(textbuffer, MAXBUF, text, argsPtr);\r  va_end(argsPtr);\r\r      this->WriteAllExcept(user, serversource, status, except_list, std::string(textbuffer));\r}\r\rvoid chanrec::WriteAllExcept(userrec* user, bool serversource, char status, CUList &except_list, const std::string &text)\r{\r CUList *ulist;\r char tb[MAXBUF];\r\r      switch (status)\r        {\r              case '@':\r                      ulist = this->GetOppedUsers();\r                 break;\r         case '%':\r                      ulist = this->GetHalfoppedUsers();\r                     break;\r         case '+':\r                      ulist = this->GetVoicedUsers();\r                        break;\r         default:\r                       ulist = this->GetUsers();\r                      break;\r }\r\r     snprintf(tb,MAXBUF,":%s %s",user->GetFullHost(),text.c_str());\r std::string out = tb;\r\r for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)\r      {\r              if ((IS_LOCAL(i->first)) && (except_list.find(i->first) == except_list.end()))\r         {\r                      if (serversource)\r                              i->first->WriteServ(text);\r                     else\r                           i->first->Write(out);\r          }\r      }\r}\r\rvoid chanrec::WriteAllExceptSender(userrec* user, bool serversource, char status, const std::string& text)\r{\r      CUList except_list;\r    except_list[user] = user->nick;\r        this->WriteAllExcept(user, serversource, status, except_list, std::string(text));\r}\r\r/*\r * return a count of the users on a specific channel accounting for\r * invisible users who won't increase the count. e.g. for /LIST\r */\rint chanrec::CountInvisible()\r{\r        int count = 0;\r CUList *ulist= this->GetUsers();\r       for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)\r      {\r              if (!(i->first->IsModeSet('i')))\r                       count++;\r       }\r\r     return count;\r}\r\rchar* chanrec::ChanModes(bool showkey)\r{\r      static char scratch[MAXBUF];\r   static char sparam[MAXBUF];\r    char* offset = scratch;\r        std::string extparam;\r\r *scratch = '\0';\r       *sparam = '\0';\r\r       /* This was still iterating up to 190, chanrec::modes is only 64 elements -- Om */\r     for(int n = 0; n < 64; n++)\r    {\r              if(this->modes[n])\r             {\r                      *offset++ = n + 65;\r                    extparam.clear();\r                      switch (n)\r                     {\r                              case CM_KEY:\r                                   extparam = (showkey ? this->key : "<key>");\r                            break;\r                         case CM_LIMIT:\r                                 extparam = ConvToStr(this->limit);\r                             break;\r                         case CM_NOEXTERNAL:\r                            case CM_TOPICLOCK:\r                             case CM_INVITEONLY:\r                            case CM_MODERATED:\r                             case CM_SECRET:\r                                case CM_PRIVATE:\r                                       /* We know these have no parameters */\r                         break;\r                         default:\r                                       extparam = this->GetModeParameter(n + 65);\r                             break;\r                 }\r                      if (!extparam.empty())\r                 {\r                              charlcat(sparam,' ',MAXBUF);\r                           strlcat(sparam,extparam.c_str(),MAXBUF);\r                       }\r              }\r      }\r\r     /* Null terminate scratch */\r   *offset = '\0';\r        strlcat(scratch,sparam,MAXBUF);\r        return scratch;\r}\r\r/* compile a userlist of a channel into a string, each nick seperated by\r * spaces and op, voice etc status shown as @ and +, and send it to 'user'\r */\rvoid chanrec::UserList(userrec *user, CUList *ulist)\r{\r      char list[MAXBUF];\r     size_t dlen, curlen;\r   int MOD_RESULT = 0;\r\r   if (!IS_LOCAL(user))\r           return;\r\r       FOREACH_RESULT(I_OnUserList,OnUserList(user, this, ulist));\r    if (MOD_RESULT == 1)\r           return;\r\r       dlen = curlen = snprintf(list,MAXBUF,"353 %s = %s :", user->nick, this->name);\r\r        int numusers = 0;\r      char* ptr = list + dlen;\r\r      if (!ulist)\r            ulist = this->GetUsers();\r\r     /* Improvement by Brain - this doesnt change in value, so why was it inside\r     * the loop?\r    */\r    bool has_user = this->HasUser(user);\r\r  for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)\r      {\r              if ((!has_user) && (i->first->modes[UM_INVISIBLE]))\r            {\r                      /*\r                      * user is +i, and source not on the channel, does not show\r                     * nick in NAMES list\r                   */\r                    continue;\r              }\r\r             if (i->first->Visibility && !i->first->Visibility->VisibleTo(user))\r                    continue;\r\r             size_t ptrlen = snprintf(ptr, MAXBUF, "%s%s ", this->GetPrefixChar(i->first), i->second.c_str());\r              /* OnUserList can change this - reset it back to normal */\r             i->second = i->first->nick;\r\r           curlen += ptrlen;\r              ptr += ptrlen;\r\r                numusers++;\r\r           if (curlen > (480-NICKMAX))\r            {\r                      /* list overflowed into multiple numerics */\r                   user->WriteServ(std::string(list));\r\r                   /* reset our lengths */\r                        dlen = curlen = snprintf(list,MAXBUF,"353 %s = %s :", user->nick, this->name);\r                 ptr = list + dlen;\r\r                    ptrlen = 0;\r                    numusers = 0;\r          }\r      }\r\r     /* if whats left in the list isnt empty, send it */\r    if (numusers)\r  {\r              user->WriteServ(std::string(list));\r    }\r\r     user->WriteServ("366 %s %s :End of /NAMES list.", user->nick, this->name);\r}\r\rlong chanrec::GetMaxBans()\r{\r     /* Return the cached value if there is one */\r  if (this->maxbans)\r             return this->maxbans;\r\r /* If there isnt one, we have to do some O(n) hax to find it the first time. (ick) */\r  for (std::map<std::string,int>::iterator n = ServerInstance->Config->maxbans.begin(); n != ServerInstance->Config->maxbans.end(); n++)\r {\r              if (match(this->name,n->first.c_str()))\r                {\r                      this->maxbans = n->second;\r                     return n->second;\r              }\r      }\r\r     /* Screw it, just return the default of 64 */\r  this->maxbans = 64;\r    return this->maxbans;\r}\r\rvoid chanrec::ResetMaxBans()\r{\r        this->maxbans = 0;\r}\r\r/* returns the status character for a given user on a channel, e.g. @ for op,\r * % for halfop etc. If the user has several modes set, the highest mode\r * the user has must be returned.\r */\rconst char* chanrec::GetPrefixChar(userrec *user)\r{\r static char pf[2] = {0, 0};\r    \r       prefixlist::iterator n = prefixes.find(user);\r  if (n != prefixes.end())\r       {\r              if (n->second.size())\r          {\r                      /* If the user has any prefixes, their highest prefix\r                   * will always be at the head of the list, as the list is\r                       * sorted in rank order highest first (see SetPrefix()\r                  * for reasons why)\r                     */\r                    *pf = n->second.begin()->first;\r                        return pf;\r             }\r      }\r\r     *pf = 0;\r       return pf;\r}\r\rconst char* chanrec::GetAllPrefixChars(userrec* user)\r{\r  static char prefix[MAXBUF];\r    int ctr = 0;\r   *prefix = 0;\r\r  prefixlist::iterator n = prefixes.find(user);\r  if (n != prefixes.end())\r       {\r              for (std::vector<prefixtype>::iterator x = n->second.begin(); x != n->second.end(); x++)\r               {\r                      prefix[ctr++] = x->first;\r              }\r      }\r\r     prefix[ctr] = 0;\r\r      return prefix;\r}\r\runsigned int chanrec::GetPrefixValue(userrec* user)\r{\r        prefixlist::iterator n = prefixes.find(user);\r  if (n != prefixes.end())\r       {\r              if (n->second.size())\r                  return n->second.begin()->second;\r      }\r      return 0;\r}\r\rint chanrec::GetStatusFlags(userrec *user)\r{\r      UCListIter i = user->chans.find(this);\r if (i != user->chans.end())\r    {\r              return i->second;\r      }\r      return 0;\r}\r\rint chanrec::GetStatus(userrec *user)\r{\r   if (ServerInstance->ULine(user->server))\r               return STATUS_OP;\r\r     UCListIter i = user->chans.find(this);\r if (i != user->chans.end())\r    {\r              if ((i->second & UCMODE_OP) > 0)\r               {\r                      return STATUS_OP;\r              }\r              if ((i->second & UCMODE_HOP) > 0)\r              {\r                      return STATUS_HOP;\r             }\r              if ((i->second & UCMODE_VOICE) > 0)\r            {\r                      return STATUS_VOICE;\r           }\r              return STATUS_NORMAL;\r  }\r      return STATUS_NORMAL;\r}\r\rvoid chanrec::SetPrefix(userrec* user, char prefix, unsigned int prefix_value, bool adding)\r{\r prefixlist::iterator n = prefixes.find(user);\r  prefixtype pfx = std::make_pair(prefix,prefix_value);\r  if (adding)\r    {\r              if (n != prefixes.end())\r               {\r                      if (std::find(n->second.begin(), n->second.end(), pfx) == n->second.end())\r                     {\r                              n->second.push_back(pfx);\r                              /* We must keep prefixes in rank order, largest first.\r                          * This is for two reasons, firstly because x-chat *ass-u-me's* this\r                            * state, and secondly it turns out to be a benefit to us later.\r                                * See above in GetPrefix().\r                            */\r                            std::sort(n->second.begin(), n->second.end(), ModeParser::PrefixComparison);\r                   }\r              }\r              else\r           {\r                      pfxcontainer one;\r                      one.push_back(pfx);\r                    prefixes.insert(std::make_pair<userrec*,pfxcontainer>(user, one));\r             }\r      }\r      else\r   {\r              if (n != prefixes.end())\r               {\r                      pfxcontainer::iterator x = std::find(n->second.begin(), n->second.end(), pfx);\r                 if (x != n->second.end())\r                              n->second.erase(x);\r            }\r      }\r}\r\rvoid chanrec::RemoveAllPrefixes(userrec* user)\r{\r  prefixlist::iterator n = prefixes.find(user);\r  if (n != prefixes.end())\r       {\r              prefixes.erase(n);\r     }\r}\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include <stdarg.h>
+#include "configreader.h"
+#include "users.h"
+#include "modules.h"
+#include "wildcard.h"
+#include "mode.h"
+
+chanrec::chanrec(InspIRCd* Instance) : ServerInstance(Instance)
+{
+       *name = *topic = *setby = *key = 0;
+       maxbans = created = topicset = limit = 0;
+       memset(&modes,0,64);
+       age = ServerInstance->Time(true);
+}
+
+void chanrec::SetMode(char mode,bool mode_on)
+{
+       modes[mode-65] = mode_on;
+       if (!mode_on)
+               this->SetModeParam(mode,"",false);
+}
+
+
+void chanrec::SetModeParam(char mode,const char* parameter,bool mode_on)
+{
+       CustomModeList::iterator n = custom_mode_params.find(mode);     
+
+       if (mode_on)
+       {
+               if (n == custom_mode_params.end())
+                       custom_mode_params[mode] = strdup(parameter);
+       }
+       else
+       {
+               if (n != custom_mode_params.end())
+               {
+                       free(n->second);
+                       custom_mode_params.erase(n);
+               }
+       }
+}
+
+bool chanrec::IsModeSet(char mode)
+{
+       return modes[mode-65];
+}
+
+std::string chanrec::GetModeParameter(char mode)
+{
+       switch (mode)
+       {
+               case 'k':
+                       return this->key;
+               case 'l':
+                       return ConvToStr(this->limit);
+               default:
+                       CustomModeList::iterator n = custom_mode_params.find(mode);
+                       if (n != custom_mode_params.end())
+                               return n->second;
+                       return "";
+               break;
+       }
+}
+
+long chanrec::GetUserCounter()
+{
+       return (this->internal_userlist.size());
+}
+
+void chanrec::AddUser(userrec* user)
+{
+       internal_userlist[user] = user->nick;
+}
+
+unsigned long chanrec::DelUser(userrec* user)
+{
+       CUListIter a = internal_userlist.find(user);
+       
+       if (a != internal_userlist.end())
+       {
+               internal_userlist.erase(a);
+               /* And tidy any others... */
+               DelOppedUser(user);
+               DelHalfoppedUser(user);
+               DelVoicedUser(user);
+       }
+       
+       return internal_userlist.size();
+}
+
+bool chanrec::HasUser(userrec* user)
+{
+       return (internal_userlist.find(user) != internal_userlist.end());
+}
+
+void chanrec::AddOppedUser(userrec* user)
+{
+       internal_op_userlist[user] = user->nick;
+}
+
+void chanrec::DelOppedUser(userrec* user)
+{
+       CUListIter a = internal_op_userlist.find(user);
+       if (a != internal_op_userlist.end())
+       {
+               internal_op_userlist.erase(a);
+               return;
+       }
+}
+
+void chanrec::AddHalfoppedUser(userrec* user)
+{
+       internal_halfop_userlist[user] = user->nick;
+}
+
+void chanrec::DelHalfoppedUser(userrec* user)
+{
+       CUListIter a = internal_halfop_userlist.find(user);
+
+       if (a != internal_halfop_userlist.end())
+       {   
+               internal_halfop_userlist.erase(a);
+       }
+}
+
+void chanrec::AddVoicedUser(userrec* user)
+{
+       internal_voice_userlist[user] = user->nick;
+}
+
+void chanrec::DelVoicedUser(userrec* user)
+{
+       CUListIter a = internal_voice_userlist.find(user);
+       
+       if (a != internal_voice_userlist.end())
+       {
+               internal_voice_userlist.erase(a);
+       }
+}
+
+CUList* chanrec::GetUsers()
+{
+       return &internal_userlist;
+}
+
+CUList* chanrec::GetOppedUsers()
+{
+       return &internal_op_userlist;
+}
+
+CUList* chanrec::GetHalfoppedUsers()
+{
+       return &internal_halfop_userlist;
+}
+
+CUList* chanrec::GetVoicedUsers()
+{
+       return &internal_voice_userlist;
+}
+
+void chanrec::SetDefaultModes()
+{
+       irc::spacesepstream list(ServerInstance->Config->DefaultModes);
+       std::string modeseq = list.GetToken();
+       std::string parameter;
+       userrec* dummyuser = new userrec(ServerInstance);
+       dummyuser->SetFd(FD_MAGIC_NUMBER);
+
+       for (std::string::iterator n = modeseq.begin(); n != modeseq.end(); ++n)
+       {
+               ModeHandler* mode = ServerInstance->Modes->FindMode(*n, MODETYPE_CHANNEL);
+               if (mode)
+               {
+                       if (mode->GetNumParams(true))
+                               parameter = list.GetToken().c_str();
+                       else
+                               parameter.clear();
+
+                       mode->OnModeChange(dummyuser, dummyuser, this, parameter, true);
+               }
+       }
+
+       delete dummyuser;
+}
+
+/* 
+ * add a channel to a user, creating the record for it if needed and linking
+ * it to the user record 
+ */
+chanrec* chanrec::JoinUser(InspIRCd* Instance, userrec *user, const char* cn, bool override, const char* key, time_t TS)
+{
+       if (!user || !cn)
+               return NULL;
+
+       bool new_channel = false;
+       char cname[MAXBUF];
+       int MOD_RESULT = 0;
+       strlcpy(cname,cn,CHANMAX);
+
+       std::string privs;
+
+       chanrec* Ptr = Instance->FindChan(cname);
+
+       if (!Ptr)
+       {
+               if ((!IS_LOCAL(user)) && (!TS))
+                       Instance->Log(DEBUG,"*** BUG *** chanrec::JoinUser called for REMOTE user '%s' on channel '%s' but no TS given!", user->nick, cn);
+
+               privs = "@";
+
+               if (IS_LOCAL(user) && override == false)
+               {
+                       MOD_RESULT = 0;
+                       FOREACH_RESULT_I(Instance,I_OnUserPreJoin,OnUserPreJoin(user,NULL,cname,privs));
+                       if (MOD_RESULT == 1)
+                               return NULL;
+               }
+
+               /* create a new one */
+               Ptr = new chanrec(Instance);
+               (*(Instance->chanlist))[cname] = Ptr;
+
+               strlcpy(Ptr->name, cname,CHANMAX);
+
+               /* As spotted by jilles, dont bother to set this on remote users */
+               if (IS_LOCAL(user))
+                       Ptr->SetDefaultModes();
+
+               Ptr->created = TS ? TS : Instance->Time();
+               Ptr->age = Ptr->created;
+               *Ptr->topic = 0;
+               *Ptr->setby = 0;
+               Ptr->topicset = 0;
+               new_channel = true;
+       }
+       else
+       {
+               /* Already on the channel */
+               if (Ptr->HasUser(user))
+                       return NULL;
+
+               /*
+                * remote users are allowed us to bypass channel modes
+                * and bans (used by servers)
+                */
+               if (IS_LOCAL(user) && override == false)
+               {
+                       MOD_RESULT = 0;
+                       FOREACH_RESULT_I(Instance,I_OnUserPreJoin,OnUserPreJoin(user,Ptr,cname,privs));
+                       if (MOD_RESULT == 1)
+                       {
+                               return NULL;
+                       }
+                       else if (MOD_RESULT == 0)
+                       {
+                               if (*Ptr->key)
+                               {
+                                       MOD_RESULT = 0;
+                                       FOREACH_RESULT_I(Instance,I_OnCheckKey,OnCheckKey(user, Ptr, key ? key : ""));
+                                       if (!MOD_RESULT)
+                                       {
+                                               if ((!key) || strcmp(key,Ptr->key))
+                                               {
+                                                       user->WriteServ("475 %s %s :Cannot join channel (Incorrect channel key)",user->nick, Ptr->name);
+                                                       return NULL;
+                                               }
+                                       }
+                               }
+                               if (Ptr->modes[CM_INVITEONLY])
+                               {
+                                       MOD_RESULT = 0;
+                                       FOREACH_RESULT_I(Instance,I_OnCheckInvite,OnCheckInvite(user, Ptr));
+                                       if (!MOD_RESULT)
+                                       {
+                                               if (user->IsInvited(Ptr->name))
+                                               {
+                                                       /* user was invited to channel */
+                                                       /* there may be an optional channel NOTICE here */
+                                               }
+                                               else
+                                               {
+                                                       user->WriteServ("473 %s %s :Cannot join channel (Invite only)",user->nick, Ptr->name);
+                                                       return NULL;
+                                               }
+                                       }
+                                       user->RemoveInvite(Ptr->name);
+                               }
+                               if (Ptr->limit)
+                               {
+                                       MOD_RESULT = 0;
+                                       FOREACH_RESULT_I(Instance,I_OnCheckLimit,OnCheckLimit(user, Ptr));
+                                       if (!MOD_RESULT)
+                                       {
+                                               if (Ptr->GetUserCounter() >= Ptr->limit)
+                                               {
+                                                       user->WriteServ("471 %s %s :Cannot join channel (Channel is full)",user->nick, Ptr->name);
+                                                       return NULL;
+                                               }
+                                       }
+                               }
+                               if (Ptr->bans.size())
+                               {
+                                       if (Ptr->IsBanned(user))
+                                       {
+                                               user->WriteServ("474 %s %s :Cannot join channel (You're banned)",user->nick, Ptr->name);
+                                               return NULL;
+                                       }
+                               }
+                       }
+               }
+       }
+
+       /* NOTE: If the user is an oper here, we can extend their user->chans by up to
+        * OperMaxchans. For remote users which are not bound by the channel limits,
+        * we can extend infinitely. Otherwise, nope, youre restricted to MaxChans.
+        */
+       if (!IS_LOCAL(user) || override == true)
+       {
+               return chanrec::ForceChan(Instance, Ptr, user, privs);
+       }
+       else if (IS_OPER(user))
+       {
+               /* Oper allows extension up to the OperMaxchans value */
+               if (user->chans.size() < Instance->Config->OperMaxChans)
+               {
+                       return chanrec::ForceChan(Instance, Ptr, user, privs);
+               }
+       }
+       else if (user->chans.size() < Instance->Config->MaxChans)
+       {
+               return chanrec::ForceChan(Instance, Ptr, user, privs);
+       }
+
+
+       user->WriteServ("405 %s %s :You are on too many channels",user->nick, cname);
+
+       if (new_channel)
+       {
+               /* Things went seriously pear shaped, so take this away. bwahaha. */
+               chan_hash::iterator n = Instance->chanlist->find(cname);
+               if (n != Instance->chanlist->end())
+               {
+                       Ptr->DelUser(user);
+                       DELETE(Ptr);
+                       Instance->chanlist->erase(n);
+               }
+       }
+
+       return NULL;
+}
+
+chanrec* chanrec::ForceChan(InspIRCd* Instance, chanrec* Ptr, userrec* user, const std::string &privs)
+{
+       userrec* dummyuser = new userrec(Instance);
+       std::string nick = user->nick;
+       bool silent = false;
+
+       dummyuser->SetFd(FD_MAGIC_NUMBER);
+       Ptr->AddUser(user);
+
+       /* Just in case they have no permissions */
+       user->chans[Ptr] = 0;
+
+       for (std::string::const_iterator x = privs.begin(); x != privs.end(); x++)
+       {
+               const char status = *x;
+               ModeHandler* mh = Instance->Modes->FindPrefix(status);
+               if (mh)
+               {
+                       Ptr->SetPrefix(user, status, mh->GetPrefixRank(), true);
+                       /* Make sure that the mode handler knows this mode was now set */
+                       mh->OnModeChange(dummyuser, dummyuser, Ptr, nick, true);
+
+                       switch (mh->GetPrefix())
+                       {
+                               /* These logic ops are SAFE IN THIS CASE
+                                * because if the entry doesnt exist,
+                                * addressing operator[] creates it.
+                                * If they do exist, it points to it.
+                                * At all other times where we dont want
+                                * to create an item if it doesnt exist, we
+                                * must stick to ::find().
+                                */
+                               case '@':
+                                       user->chans[Ptr] |= UCMODE_OP;
+                               break;
+                               case '%':
+                                       user->chans[Ptr] |= UCMODE_HOP;
+                               break;
+                               case '+':
+                                       user->chans[Ptr] |= UCMODE_VOICE;
+                               break;
+                       }
+               }
+       }
+
+       delete dummyuser;
+
+       FOREACH_MOD_I(Instance,I_OnUserJoin,OnUserJoin(user, Ptr, silent));
+
+       if (!silent)
+               Ptr->WriteChannel(user,"JOIN :%s",Ptr->name);
+
+       /* Theyre not the first ones in here, make sure everyone else sees the modes we gave the user */
+       std::string ms = Instance->Modes->ModeString(user, Ptr);
+       if ((Ptr->GetUserCounter() > 1) && (ms.length()))
+               Ptr->WriteAllExceptSender(user, true, 0, "MODE %s +%s", Ptr->name, ms.c_str());
+
+       /* Major improvement by Brain - we dont need to be calculating all this pointlessly for remote users */
+       if (IS_LOCAL(user))
+       {
+               if (Ptr->topicset)
+               {
+                       user->WriteServ("332 %s %s :%s", user->nick, Ptr->name, Ptr->topic);
+                       user->WriteServ("333 %s %s %s %lu", user->nick, Ptr->name, Ptr->setby, (unsigned long)Ptr->topicset);
+               }
+               Ptr->UserList(user);
+       }
+       FOREACH_MOD_I(Instance,I_OnPostJoin,OnPostJoin(user, Ptr));
+       return Ptr;
+}
+
+bool chanrec::IsBanned(userrec* user)
+{
+       char mask[MAXBUF];
+       int MOD_RESULT = 0;
+       FOREACH_RESULT(I_OnCheckBan,OnCheckBan(user, this));
+       if (!MOD_RESULT)
+       {
+               snprintf(mask, MAXBUF, "%s!%s@%s", user->nick, user->ident, user->GetIPString());
+               for (BanList::iterator i = this->bans.begin(); i != this->bans.end(); i++)
+               {
+                       /* This allows CIDR ban matching
+                        * 
+                        *        Full masked host                      Full unmasked host                   IP with/without CIDR
+                        */
+                       if ((match(user->GetFullHost(),i->data)) || (match(user->GetFullRealHost(),i->data)) || (match(mask, i->data, true)))
+                       {
+                               return true;
+                       }
+               }
+       }
+       return false;
+}
+
+/* chanrec::PartUser
+ * remove a channel from a users record, and return the number of users left.
+ * Therefore, if this function returns 0 the caller should delete the chanrec.
+ */
+long chanrec::PartUser(userrec *user, const char* reason)
+{
+       bool silent = false;
+
+       if (!user)
+               return this->GetUserCounter();
+
+       UCListIter i = user->chans.find(this);
+       if (i != user->chans.end())
+       {
+               FOREACH_MOD(I_OnUserPart,OnUserPart(user, this, reason ? reason : "", silent));
+
+               if (!silent)
+                       this->WriteChannel(user, "PART %s%s%s", this->name, reason ? " :" : "", reason ? reason : "");
+
+               user->chans.erase(i);
+               this->RemoveAllPrefixes(user);
+       }
+
+       if (!this->DelUser(user)) /* if there are no users left on the channel... */
+       {
+               chan_hash::iterator iter = ServerInstance->chanlist->find(this->name);
+               /* kill the record */
+               if (iter != ServerInstance->chanlist->end())
+               {
+                       FOREACH_MOD(I_OnChannelDelete,OnChannelDelete(this));
+                       ServerInstance->chanlist->erase(iter);
+               }
+               return 0;
+       }
+
+       return this->GetUserCounter();
+}
+
+long chanrec::ServerKickUser(userrec* user, const char* reason, bool triggerevents)
+{
+       bool silent = false;
+
+       if (!user || !reason)
+               return this->GetUserCounter();
+
+       if (IS_LOCAL(user))
+       {
+               if (!this->HasUser(user))
+               {
+                       /* Not on channel */
+                       return this->GetUserCounter();
+               }
+       }
+
+       if (triggerevents)
+       {
+               FOREACH_MOD(I_OnUserKick,OnUserKick(NULL, user, this, reason, silent));
+       }
+
+       UCListIter i = user->chans.find(this);
+       if (i != user->chans.end())
+       {
+               if (!silent)
+                       this->WriteChannelWithServ(ServerInstance->Config->ServerName, "KICK %s %s :%s", this->name, user->nick, reason);
+
+               user->chans.erase(i);
+               this->RemoveAllPrefixes(user);
+       }
+
+       if (!this->DelUser(user))
+       {
+               chan_hash::iterator iter = ServerInstance->chanlist->find(this->name);
+               /* kill the record */
+               if (iter != ServerInstance->chanlist->end())
+               {
+                       FOREACH_MOD(I_OnChannelDelete,OnChannelDelete(this));
+                       ServerInstance->chanlist->erase(iter);
+               }
+               return 0;
+       }
+
+       return this->GetUserCounter();
+}
+
+long chanrec::KickUser(userrec *src, userrec *user, const char* reason)
+{
+       bool silent = false;
+
+       if (!src || !user || !reason)
+               return this->GetUserCounter();
+
+       if (IS_LOCAL(src))
+       {
+               if (!this->HasUser(user))
+               {
+                       src->WriteServ("441 %s %s %s :They are not on that channel",src->nick, user->nick, this->name);
+                       return this->GetUserCounter();
+               }
+               if ((ServerInstance->ULine(user->server)) && (!ServerInstance->ULine(src->server)))
+               {
+                       src->WriteServ("482 %s %s :Only a u-line may kick a u-line from a channel.",src->nick, this->name);
+                       return this->GetUserCounter();
+               }
+               int MOD_RESULT = 0;
+
+               if (!ServerInstance->ULine(src->server))
+               {
+                       MOD_RESULT = 0;
+                       FOREACH_RESULT(I_OnUserPreKick,OnUserPreKick(src,user,this,reason));
+                       if (MOD_RESULT == 1)
+                               return this->GetUserCounter();
+               }
+               /* Set to -1 by OnUserPreKick if explicit allow was set */
+               if (MOD_RESULT != -1)
+               {
+                       FOREACH_RESULT(I_OnAccessCheck,OnAccessCheck(src,user,this,AC_KICK));
+                       if ((MOD_RESULT == ACR_DENY) && (!ServerInstance->ULine(src->server)))
+                               return this->GetUserCounter();
+       
+                       if ((MOD_RESULT == ACR_DEFAULT) || (!ServerInstance->ULine(src->server)))
+                       {
+                               int them = this->GetStatus(src);
+                               int us = this->GetStatus(user);
+                               if ((them < STATUS_HOP) || (them < us))
+                               {
+                                       src->WriteServ("482 %s %s :You must be a channel %soperator",src->nick, this->name, them == STATUS_HOP ? "" : "half-");
+                                       return this->GetUserCounter();
+                               }
+                       }
+               }
+       }
+
+       FOREACH_MOD(I_OnUserKick,OnUserKick(src, user, this, reason, silent));
+
+       UCListIter i = user->chans.find(this);
+       if (i != user->chans.end())
+       {
+               /* zap it from the channel list of the user */
+               if (!silent)
+                       this->WriteChannel(src, "KICK %s %s :%s", this->name, user->nick, reason);
+
+               user->chans.erase(i);
+               this->RemoveAllPrefixes(user);
+       }
+
+       if (!this->DelUser(user))
+       /* if there are no users left on the channel */
+       {
+               chan_hash::iterator iter = ServerInstance->chanlist->find(this->name);
+
+               /* kill the record */
+               if (iter != ServerInstance->chanlist->end())
+               {
+                       FOREACH_MOD(I_OnChannelDelete,OnChannelDelete(this));
+                       ServerInstance->chanlist->erase(iter);
+               }
+               return 0;
+       }
+
+       return this->GetUserCounter();
+}
+
+void chanrec::WriteChannel(userrec* user, char* text, ...)
+{
+       char textbuffer[MAXBUF];
+       va_list argsPtr;
+
+       if (!user || !text)
+               return;
+
+       va_start(argsPtr, text);
+       vsnprintf(textbuffer, MAXBUF, text, argsPtr);
+       va_end(argsPtr);
+
+       this->WriteChannel(user, std::string(textbuffer));
+}
+
+void chanrec::WriteChannel(userrec* user, const std::string &text)
+{
+       CUList *ulist = this->GetUsers();
+       char tb[MAXBUF];
+
+       if (!user)
+               return;
+
+       snprintf(tb,MAXBUF,":%s %s",user->GetFullHost(),text.c_str());
+       std::string out = tb;
+
+       for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
+       {
+               if (IS_LOCAL(i->first))
+                       i->first->Write(out);
+       }
+}
+
+void chanrec::WriteChannelWithServ(const char* ServName, const char* text, ...)
+{
+       char textbuffer[MAXBUF];
+       va_list argsPtr;
+
+       if (!text)
+               return;
+
+       va_start(argsPtr, text);
+       vsnprintf(textbuffer, MAXBUF, text, argsPtr);
+       va_end(argsPtr);
+
+       this->WriteChannelWithServ(ServName, std::string(textbuffer));
+}
+
+void chanrec::WriteChannelWithServ(const char* ServName, const std::string &text)
+{
+       CUList *ulist = this->GetUsers();
+       char tb[MAXBUF];
+
+       snprintf(tb,MAXBUF,":%s %s",ServName ? ServName : ServerInstance->Config->ServerName, text.c_str());
+       std::string out = tb;
+
+       for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
+       {
+               if (IS_LOCAL(i->first))
+                       i->first->Write(out);
+       }
+}
+
+/* write formatted text from a source user to all users on a channel except
+ * for the sender (for privmsg etc) */
+void chanrec::WriteAllExceptSender(userrec* user, bool serversource, char status, char* text, ...)
+{
+       char textbuffer[MAXBUF];
+       va_list argsPtr;
+
+       if (!text)
+               return;
+
+       va_start(argsPtr, text);
+       vsnprintf(textbuffer, MAXBUF, text, argsPtr);
+       va_end(argsPtr);
+
+       this->WriteAllExceptSender(user, serversource, status, std::string(textbuffer));
+}
+
+void chanrec::WriteAllExcept(userrec* user, bool serversource, char status, CUList &except_list, char* text, ...)
+{
+       char textbuffer[MAXBUF];
+       va_list argsPtr;
+
+       if (!text)
+               return;
+
+       va_start(argsPtr, text);
+       vsnprintf(textbuffer, MAXBUF, text, argsPtr);
+       va_end(argsPtr);
+
+       this->WriteAllExcept(user, serversource, status, except_list, std::string(textbuffer));
+}
+
+void chanrec::WriteAllExcept(userrec* user, bool serversource, char status, CUList &except_list, const std::string &text)
+{
+       CUList *ulist;
+       char tb[MAXBUF];
+
+       switch (status)
+       {
+               case '@':
+                       ulist = this->GetOppedUsers();
+                       break;
+               case '%':
+                       ulist = this->GetHalfoppedUsers();
+                       break;
+               case '+':
+                       ulist = this->GetVoicedUsers();
+                       break;
+               default:
+                       ulist = this->GetUsers();
+                       break;
+       }
+
+       snprintf(tb,MAXBUF,":%s %s",user->GetFullHost(),text.c_str());
+       std::string out = tb;
+
+       for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
+       {
+               if ((IS_LOCAL(i->first)) && (except_list.find(i->first) == except_list.end()))
+               {
+                       if (serversource)
+                               i->first->WriteServ(text);
+                       else
+                               i->first->Write(out);
+               }
+       }
+}
+
+void chanrec::WriteAllExceptSender(userrec* user, bool serversource, char status, const std::string& text)
+{
+       CUList except_list;
+       except_list[user] = user->nick;
+       this->WriteAllExcept(user, serversource, status, except_list, std::string(text));
+}
+
+/*
+ * return a count of the users on a specific channel accounting for
+ * invisible users who won't increase the count. e.g. for /LIST
+ */
+int chanrec::CountInvisible()
+{
+       int count = 0;
+       CUList *ulist= this->GetUsers();
+       for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
+       {
+               if (!(i->first->IsModeSet('i')))
+                       count++;
+       }
+
+       return count;
+}
+
+char* chanrec::ChanModes(bool showkey)
+{
+       static char scratch[MAXBUF];
+       static char sparam[MAXBUF];
+       char* offset = scratch;
+       std::string extparam;
+
+       *scratch = '\0';
+       *sparam = '\0';
+
+       /* This was still iterating up to 190, chanrec::modes is only 64 elements -- Om */
+       for(int n = 0; n < 64; n++)
+       {
+               if(this->modes[n])
+               {
+                       *offset++ = n + 65;
+                       extparam.clear();
+                       switch (n)
+                       {
+                               case CM_KEY:
+                                       extparam = (showkey ? this->key : "<key>");
+                               break;
+                               case CM_LIMIT:
+                                       extparam = ConvToStr(this->limit);
+                               break;
+                               case CM_NOEXTERNAL:
+                               case CM_TOPICLOCK:
+                               case CM_INVITEONLY:
+                               case CM_MODERATED:
+                               case CM_SECRET:
+                               case CM_PRIVATE:
+                                       /* We know these have no parameters */
+                               break;
+                               default:
+                                       extparam = this->GetModeParameter(n + 65);
+                               break;
+                       }
+                       if (!extparam.empty())
+                       {
+                               charlcat(sparam,' ',MAXBUF);
+                               strlcat(sparam,extparam.c_str(),MAXBUF);
+                       }
+               }
+       }
+
+       /* Null terminate scratch */
+       *offset = '\0';
+       strlcat(scratch,sparam,MAXBUF);
+       return scratch;
+}
+
+/* compile a userlist of a channel into a string, each nick seperated by
+ * spaces and op, voice etc status shown as @ and +, and send it to 'user'
+ */
+void chanrec::UserList(userrec *user, CUList *ulist)
+{
+       char list[MAXBUF];
+       size_t dlen, curlen;
+       int MOD_RESULT = 0;
+
+       if (!IS_LOCAL(user))
+               return;
+
+       FOREACH_RESULT(I_OnUserList,OnUserList(user, this, ulist));
+       if (MOD_RESULT == 1)
+               return;
+
+       dlen = curlen = snprintf(list,MAXBUF,"353 %s = %s :", user->nick, this->name);
+
+       int numusers = 0;
+       char* ptr = list + dlen;
+
+       if (!ulist)
+               ulist = this->GetUsers();
+
+       /* Improvement by Brain - this doesnt change in value, so why was it inside
+        * the loop?
+        */
+       bool has_user = this->HasUser(user);
+
+       for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
+       {
+               if ((!has_user) && (i->first->modes[UM_INVISIBLE]))
+               {
+                       /*
+                        * user is +i, and source not on the channel, does not show
+                        * nick in NAMES list
+                        */
+                       continue;
+               }
+
+               if (i->first->Visibility && !i->first->Visibility->VisibleTo(user))
+                       continue;
+
+               size_t ptrlen = snprintf(ptr, MAXBUF, "%s%s ", this->GetPrefixChar(i->first), i->second.c_str());
+               /* OnUserList can change this - reset it back to normal */
+               i->second = i->first->nick;
+
+               curlen += ptrlen;
+               ptr += ptrlen;
+
+               numusers++;
+
+               if (curlen > (480-NICKMAX))
+               {
+                       /* list overflowed into multiple numerics */
+                       user->WriteServ(std::string(list));
+
+                       /* reset our lengths */
+                       dlen = curlen = snprintf(list,MAXBUF,"353 %s = %s :", user->nick, this->name);
+                       ptr = list + dlen;
+
+                       ptrlen = 0;
+                       numusers = 0;
+               }
+       }
+
+       /* if whats left in the list isnt empty, send it */
+       if (numusers)
+       {
+               user->WriteServ(std::string(list));
+       }
+
+       user->WriteServ("366 %s %s :End of /NAMES list.", user->nick, this->name);
+}
+
+long chanrec::GetMaxBans()
+{
+       /* Return the cached value if there is one */
+       if (this->maxbans)
+               return this->maxbans;
+
+       /* If there isnt one, we have to do some O(n) hax to find it the first time. (ick) */
+       for (std::map<std::string,int>::iterator n = ServerInstance->Config->maxbans.begin(); n != ServerInstance->Config->maxbans.end(); n++)
+       {
+               if (match(this->name,n->first.c_str()))
+               {
+                       this->maxbans = n->second;
+                       return n->second;
+               }
+       }
+
+       /* Screw it, just return the default of 64 */
+       this->maxbans = 64;
+       return this->maxbans;
+}
+
+void chanrec::ResetMaxBans()
+{
+       this->maxbans = 0;
+}
+
+/* returns the status character for a given user on a channel, e.g. @ for op,
+ * % for halfop etc. If the user has several modes set, the highest mode
+ * the user has must be returned.
+ */
+const char* chanrec::GetPrefixChar(userrec *user)
+{
+       static char pf[2] = {0, 0};
+       
+       prefixlist::iterator n = prefixes.find(user);
+       if (n != prefixes.end())
+       {
+               if (n->second.size())
+               {
+                       /* If the user has any prefixes, their highest prefix
+                        * will always be at the head of the list, as the list is
+                        * sorted in rank order highest first (see SetPrefix()
+                        * for reasons why)
+                        */
+                       *pf = n->second.begin()->first;
+                       return pf;
+               }
+       }
+
+       *pf = 0;
+       return pf;
+}
+
+const char* chanrec::GetAllPrefixChars(userrec* user)
+{
+       static char prefix[MAXBUF];
+       int ctr = 0;
+       *prefix = 0;
+
+       prefixlist::iterator n = prefixes.find(user);
+       if (n != prefixes.end())
+       {
+               for (std::vector<prefixtype>::iterator x = n->second.begin(); x != n->second.end(); x++)
+               {
+                       prefix[ctr++] = x->first;
+               }
+       }
+
+       prefix[ctr] = 0;
+
+       return prefix;
+}
+
+unsigned int chanrec::GetPrefixValue(userrec* user)
+{
+       prefixlist::iterator n = prefixes.find(user);
+       if (n != prefixes.end())
+       {
+               if (n->second.size())
+                       return n->second.begin()->second;
+       }
+       return 0;
+}
+
+int chanrec::GetStatusFlags(userrec *user)
+{
+       UCListIter i = user->chans.find(this);
+       if (i != user->chans.end())
+       {
+               return i->second;
+       }
+       return 0;
+}
+
+int chanrec::GetStatus(userrec *user)
+{
+       if (ServerInstance->ULine(user->server))
+               return STATUS_OP;
+
+       UCListIter i = user->chans.find(this);
+       if (i != user->chans.end())
+       {
+               if ((i->second & UCMODE_OP) > 0)
+               {
+                       return STATUS_OP;
+               }
+               if ((i->second & UCMODE_HOP) > 0)
+               {
+                       return STATUS_HOP;
+               }
+               if ((i->second & UCMODE_VOICE) > 0)
+               {
+                       return STATUS_VOICE;
+               }
+               return STATUS_NORMAL;
+       }
+       return STATUS_NORMAL;
+}
+
+void chanrec::SetPrefix(userrec* user, char prefix, unsigned int prefix_value, bool adding)
+{
+       prefixlist::iterator n = prefixes.find(user);
+       prefixtype pfx = std::make_pair(prefix,prefix_value);
+       if (adding)
+       {
+               if (n != prefixes.end())
+               {
+                       if (std::find(n->second.begin(), n->second.end(), pfx) == n->second.end())
+                       {
+                               n->second.push_back(pfx);
+                               /* We must keep prefixes in rank order, largest first.
+                                * This is for two reasons, firstly because x-chat *ass-u-me's* this
+                                * state, and secondly it turns out to be a benefit to us later.
+                                * See above in GetPrefix().
+                                */
+                               std::sort(n->second.begin(), n->second.end(), ModeParser::PrefixComparison);
+                       }
+               }
+               else
+               {
+                       pfxcontainer one;
+                       one.push_back(pfx);
+                       prefixes.insert(std::make_pair<userrec*,pfxcontainer>(user, one));
+               }
+       }
+       else
+       {
+               if (n != prefixes.end())
+               {
+                       pfxcontainer::iterator x = std::find(n->second.begin(), n->second.end(), pfx);
+                       if (x != n->second.end())
+                               n->second.erase(x);
+               }
+       }
+}
+
+void chanrec::RemoveAllPrefixes(userrec* user)
+{
+       prefixlist::iterator n = prefixes.find(user);
+       if (n != prefixes.end())
+       {
+               prefixes.erase(n);
+       }
+}
+
index acfb8da43aaf753963b3a8f36dd1f52fc11c2b3c..698468d0ccbf7c8f34a2c2f266db6b2444171b19 100644 (file)
@@ -1 +1,35 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "configreader.h"\r#include "users.h"\r#include "commands/cmd_admin.h"\r\r\rextern "C" DllExport command_t* init_command(InspIRCd* Instance)\r{\r   return new cmd_admin(Instance);\r}\r\r/** Handle /ADMIN\r */\rCmdResult cmd_admin::Handle (const char** parameters, int pcnt, userrec *user)\r{\r      user->WriteServ("256 %s :Administrative info for %s",user->nick,ServerInstance->Config->ServerName);\r   if (*ServerInstance->Config->AdminName)\r                user->WriteServ("257 %s :Name     - %s",user->nick,ServerInstance->Config->AdminName);\r user->WriteServ("258 %s :Nickname - %s",user->nick,ServerInstance->Config->AdminNick);\r user->WriteServ("258 %s :E-Mail   - %s",user->nick,ServerInstance->Config->AdminEmail);\r        return CMD_SUCCESS;\r}\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "configreader.h"
+#include "users.h"
+#include "commands/cmd_admin.h"
+
+
+extern "C" DllExport command_t* init_command(InspIRCd* Instance)
+{
+       return new cmd_admin(Instance);
+}
+
+/** Handle /ADMIN
+ */
+CmdResult cmd_admin::Handle (const char** parameters, int pcnt, userrec *user)
+{
+       user->WriteServ("256 %s :Administrative info for %s",user->nick,ServerInstance->Config->ServerName);
+       if (*ServerInstance->Config->AdminName)
+               user->WriteServ("257 %s :Name     - %s",user->nick,ServerInstance->Config->AdminName);
+       user->WriteServ("258 %s :Nickname - %s",user->nick,ServerInstance->Config->AdminNick);
+       user->WriteServ("258 %s :E-Mail   - %s",user->nick,ServerInstance->Config->AdminEmail);
+       return CMD_SUCCESS;
+}
index 894924938152b036d69eceee0e1aee79ea94cc39..10f96c80b179bf5176093ef1947d04f0f75ce519 100644 (file)
@@ -1 +1,42 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "configreader.h"\r#include "users.h"\r#include "modules.h"\r#include "commands/cmd_away.h"\r\rextern "C" DllExport command_t* init_command(InspIRCd* Instance)\r{\r        return new cmd_away(Instance);\r}\r\r/** Handle /AWAY\r */\rCmdResult cmd_away::Handle (const char** parameters, int pcnt, userrec *user)\r{\r if ((pcnt) && (*parameters[0]))\r        {\r              strlcpy(user->awaymsg,parameters[0],MAXAWAY);\r          user->WriteServ("306 %s :You have been marked as being away",user->nick);\r              FOREACH_MOD(I_OnSetAway,OnSetAway(user));\r      }\r      else\r   {\r              *user->awaymsg = 0;\r            user->WriteServ("305 %s :You are no longer marked as being away",user->nick);\r          FOREACH_MOD(I_OnCancelAway,OnCancelAway(user));\r        }\r      return CMD_SUCCESS;\r}\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "configreader.h"
+#include "users.h"
+#include "modules.h"
+#include "commands/cmd_away.h"
+
+extern "C" DllExport command_t* init_command(InspIRCd* Instance)
+{
+       return new cmd_away(Instance);
+}
+
+/** Handle /AWAY
+ */
+CmdResult cmd_away::Handle (const char** parameters, int pcnt, userrec *user)
+{
+       if ((pcnt) && (*parameters[0]))
+       {
+               strlcpy(user->awaymsg,parameters[0],MAXAWAY);
+               user->WriteServ("306 %s :You have been marked as being away",user->nick);
+               FOREACH_MOD(I_OnSetAway,OnSetAway(user));
+       }
+       else
+       {
+               *user->awaymsg = 0;
+               user->WriteServ("305 %s :You are no longer marked as being away",user->nick);
+               FOREACH_MOD(I_OnCancelAway,OnCancelAway(user));
+       }
+       return CMD_SUCCESS;
+}
index cdc4b987c69dd73fcbf8dff327d6c1a4501a0d72..daf8fa78b51866b567798a39ff4fd89c1ddbf8a1 100644 (file)
@@ -1 +1,31 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "configreader.h"\r#include "users.h"\r#include "commands/cmd_clearcache.h"\r\rextern "C" DllExport command_t* init_command(InspIRCd* Instance)\r{\r       return new cmd_clearcache(Instance);\r}\r\r/** Handle /CLEARCACHE\r */\rCmdResult cmd_clearcache::Handle (const char** parameters, int pcnt, userrec *user)\r{\r       int n = ServerInstance->Res->ClearCache();\r     user->WriteServ("NOTICE %s :*** Cleared DNS cache of %d items.", user->nick, n);\r       return CMD_SUCCESS;\r}\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "configreader.h"
+#include "users.h"
+#include "commands/cmd_clearcache.h"
+
+extern "C" DllExport command_t* init_command(InspIRCd* Instance)
+{
+       return new cmd_clearcache(Instance);
+}
+
+/** Handle /CLEARCACHE
+ */
+CmdResult cmd_clearcache::Handle (const char** parameters, int pcnt, userrec *user)
+{
+       int n = ServerInstance->Res->ClearCache();
+       user->WriteServ("NOTICE %s :*** Cleared DNS cache of %d items.", user->nick, n);
+       return CMD_SUCCESS;
+}
index 9eff6ed50c7f6ebcefedec018d097ad20ba51676..fc95de5f1b24be420f18b333eddc731eac32b910 100644 (file)
@@ -1 +1,33 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "commands/cmd_commands.h"\r\r/** Handle /COMMANDS\r */\rextern "C" DllExport command_t* init_command(InspIRCd* Instance)\r{\r  return new cmd_commands(Instance);\r}\r\rCmdResult cmd_commands::Handle (const char** parameters, int pcnt, userrec *user)\r{\r      for (command_table::iterator i = ServerInstance->Parser->cmdlist.begin(); i != ServerInstance->Parser->cmdlist.end(); i++)\r     {\r              user->WriteServ("902 %s :%s %s %d",user->nick,i->second->command.c_str(),i->second->source.c_str(),i->second->min_params);\r     }\r      user->WriteServ("903 %s :End of COMMANDS list",user->nick);\r    return CMD_SUCCESS;\r}\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "commands/cmd_commands.h"
+
+/** Handle /COMMANDS
+ */
+extern "C" DllExport command_t* init_command(InspIRCd* Instance)
+{
+       return new cmd_commands(Instance);
+}
+
+CmdResult cmd_commands::Handle (const char** parameters, int pcnt, userrec *user)
+{
+       for (command_table::iterator i = ServerInstance->Parser->cmdlist.begin(); i != ServerInstance->Parser->cmdlist.end(); i++)
+       {
+               user->WriteServ("902 %s :%s %s %d",user->nick,i->second->command.c_str(),i->second->source.c_str(),i->second->min_params);
+       }
+       user->WriteServ("903 %s :End of COMMANDS list",user->nick);
+       return CMD_SUCCESS;
+}
index da4a115654e8ca87cea3913b09cac37bcace572c..fc3ae9d7a36a1b5d68ab37493b4cca79a19c4f9b 100644 (file)
@@ -1 +1,33 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "commands/cmd_connect.h"\r\r/*\r * This is handled by the server linking module, if necessary. Do not remove this stub.\r */\r\rextern "C" DllExport command_t* init_command(InspIRCd* Instance)\r{\r    return new cmd_connect(Instance);\r}\r\r/** Handle /CONNECT\r */\rCmdResult cmd_connect::Handle (const char** parameters, int pcnt, userrec *user)\r{\r        user->WriteServ( "NOTICE %s :You are a nub. Load a linking module.", user->nick);\r      return CMD_SUCCESS;\r}\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "commands/cmd_connect.h"
+
+/*
+ * This is handled by the server linking module, if necessary. Do not remove this stub.
+ */
+
+extern "C" DllExport command_t* init_command(InspIRCd* Instance)
+{
+       return new cmd_connect(Instance);
+}
+
+/** Handle /CONNECT
+ */
+CmdResult cmd_connect::Handle (const char** parameters, int pcnt, userrec *user)
+{
+       user->WriteServ( "NOTICE %s :You are a nub. Load a linking module.", user->nick);
+       return CMD_SUCCESS;
+}
index c8195a41c371f097eff5f7fb02583bdbfbb675c0..7f0a81df814ce12ce99a8d2ab720985d14c3f049 100644 (file)
@@ -1 +1,47 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "configreader.h"\r#include "users.h"\r#include "commands/cmd_die.h"\r#include "exitcodes.h"\r\rextern "C" DllExport command_t* init_command(InspIRCd* Instance)\r{\r       return new cmd_die(Instance);\r}\r\r/** Handle /DIE\r */\rCmdResult cmd_die::Handle (const char** parameters, int pcnt, userrec *user)\r{\r    if (!strcmp(parameters[0],ServerInstance->Config->diepass))\r    {\r              std::string diebuf = std::string("*** DIE command from ") + user->nick + "!" + user->ident + "@" + user->dhost + ". Terminating in " + ConvToStr(ServerInstance->Config->DieDelay) + " seconds.";\r              ServerInstance->Log(SPARSE, diebuf);\r           ServerInstance->SendError(diebuf);\r             \r               if (ServerInstance->Config->DieDelay)\r                  sleep(ServerInstance->Config->DieDelay);\r\r              InspIRCd::Exit(EXIT_STATUS_DIE);\r       }\r      else\r   {\r              ServerInstance->Log(SPARSE, "Failed /DIE command from %s!%s@%s", user->nick, user->ident, user->host);\r         ServerInstance->WriteOpers("*** Failed DIE Command from %s!%s@%s.",user->nick,user->ident,user->host);\r         return CMD_FAILURE;\r    }\r      return CMD_SUCCESS;\r}\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "configreader.h"
+#include "users.h"
+#include "commands/cmd_die.h"
+#include "exitcodes.h"
+
+extern "C" DllExport command_t* init_command(InspIRCd* Instance)
+{
+       return new cmd_die(Instance);
+}
+
+/** Handle /DIE
+ */
+CmdResult cmd_die::Handle (const char** parameters, int pcnt, userrec *user)
+{
+       if (!strcmp(parameters[0],ServerInstance->Config->diepass))
+       {
+               std::string diebuf = std::string("*** DIE command from ") + user->nick + "!" + user->ident + "@" + user->dhost + ". Terminating in " + ConvToStr(ServerInstance->Config->DieDelay) + " seconds.";
+               ServerInstance->Log(SPARSE, diebuf);
+               ServerInstance->SendError(diebuf);
+               
+               if (ServerInstance->Config->DieDelay)
+                       sleep(ServerInstance->Config->DieDelay);
+
+               InspIRCd::Exit(EXIT_STATUS_DIE);
+       }
+       else
+       {
+               ServerInstance->Log(SPARSE, "Failed /DIE command from %s!%s@%s", user->nick, user->ident, user->host);
+               ServerInstance->WriteOpers("*** Failed DIE Command from %s!%s@%s.",user->nick,user->ident,user->host);
+               return CMD_FAILURE;
+       }
+       return CMD_SUCCESS;
+}
index 0282369c1162605f470d69426a530e700f234f1b..793f7a4138aa0a44c0715bdc7752cf6749557605 100644 (file)
@@ -1 +1,77 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "configreader.h"\r#include "users.h"\r#include "modules.h"\r#include "xline.h"\r#include "commands/cmd_eline.h"\r\rextern "C" DllExport command_t* init_command(InspIRCd* Instance)\r{\r    return new cmd_eline(Instance);\r}\r\r/** Handle /ELINE\r */\rCmdResult cmd_eline::Handle (const char** parameters, int pcnt, userrec *user)\r{\r      if (pcnt >= 3)\r {\r              IdentHostPair ih = ServerInstance->XLines->IdentSplit(parameters[0]);\r          if (ServerInstance->HostMatchesEveryone(ih.first+"@"+ih.second,user))\r                  return CMD_FAILURE;\r\r           if (!strchr(parameters[0],'@'))\r                {\r                      user->WriteServ("NOTICE %s :*** E-Line must contain a username, e.g. *@%s",user->nick,parameters[0]);\r                  return CMD_FAILURE;\r            }\r\r             long duration = ServerInstance->Duration(parameters[1]);\r               if (ServerInstance->XLines->add_eline(duration,user->nick,parameters[2],parameters[0]))\r                {\r                      FOREACH_MOD(I_OnAddELine,OnAddELine(duration, user, parameters[2], parameters[0]));\r\r                   if (!duration)\r                 {\r                              ServerInstance->SNO->WriteToSnoMask('x',"%s added permanent E-line for %s.",user->nick,parameters[0]);\r                 }\r                      else\r                   {\r                              time_t c_requires_crap = duration + ServerInstance->Time();\r                            ServerInstance->SNO->WriteToSnoMask('x',"%s added timed E-line for %s, expires on %s",user->nick,parameters[0],\r                                                ServerInstance->TimeString(c_requires_crap).c_str());\r                  }\r              }\r              else\r           {\r                      user->WriteServ("NOTICE %s :*** E-Line for %s already exists",user->nick,parameters[0]);\r               }\r      }\r      else\r   {\r              if (ServerInstance->XLines->del_eline(parameters[0]))\r          {\r                      FOREACH_MOD(I_OnDelELine,OnDelELine(user, parameters[0]));\r                     ServerInstance->SNO->WriteToSnoMask('x',"%s Removed E-line on %s.",user->nick,parameters[0]);\r          }\r              else\r           {\r                      user->WriteServ("NOTICE %s :*** E-Line %s not found in list, try /stats e.",user->nick,parameters[0]);\r         }\r      }\r\r     return CMD_SUCCESS;\r}\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "configreader.h"
+#include "users.h"
+#include "modules.h"
+#include "xline.h"
+#include "commands/cmd_eline.h"
+
+extern "C" DllExport command_t* init_command(InspIRCd* Instance)
+{
+       return new cmd_eline(Instance);
+}
+
+/** Handle /ELINE
+ */
+CmdResult cmd_eline::Handle (const char** parameters, int pcnt, userrec *user)
+{
+       if (pcnt >= 3)
+       {
+               IdentHostPair ih = ServerInstance->XLines->IdentSplit(parameters[0]);
+               if (ServerInstance->HostMatchesEveryone(ih.first+"@"+ih.second,user))
+                       return CMD_FAILURE;
+
+               if (!strchr(parameters[0],'@'))
+               {
+                       user->WriteServ("NOTICE %s :*** E-Line must contain a username, e.g. *@%s",user->nick,parameters[0]);
+                       return CMD_FAILURE;
+               }
+
+               long duration = ServerInstance->Duration(parameters[1]);
+               if (ServerInstance->XLines->add_eline(duration,user->nick,parameters[2],parameters[0]))
+               {
+                       FOREACH_MOD(I_OnAddELine,OnAddELine(duration, user, parameters[2], parameters[0]));
+
+                       if (!duration)
+                       {
+                               ServerInstance->SNO->WriteToSnoMask('x',"%s added permanent E-line for %s.",user->nick,parameters[0]);
+                       }
+                       else
+                       {
+                               time_t c_requires_crap = duration + ServerInstance->Time();
+                               ServerInstance->SNO->WriteToSnoMask('x',"%s added timed E-line for %s, expires on %s",user->nick,parameters[0],
+                                               ServerInstance->TimeString(c_requires_crap).c_str());
+                       }
+               }
+               else
+               {
+                       user->WriteServ("NOTICE %s :*** E-Line for %s already exists",user->nick,parameters[0]);
+               }
+       }
+       else
+       {
+               if (ServerInstance->XLines->del_eline(parameters[0]))
+               {
+                       FOREACH_MOD(I_OnDelELine,OnDelELine(user, parameters[0]));
+                       ServerInstance->SNO->WriteToSnoMask('x',"%s Removed E-line on %s.",user->nick,parameters[0]);
+               }
+               else
+               {
+                       user->WriteServ("NOTICE %s :*** E-Line %s not found in list, try /stats e.",user->nick,parameters[0]);
+               }
+       }
+
+       return CMD_SUCCESS;
+}
index c1632df8292238dc1289cf2a6d69abc2524b0058..f208d40bf6826abb339b69bb49c7f7578f39a531 100644 (file)
@@ -1 +1,89 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "configreader.h"\r#include "users.h"\r#include "modules.h"\r#include "xline.h"\r#include "commands/cmd_gline.h"\r\rextern "C" DllExport command_t* init_command(InspIRCd* Instance)\r{\r    return new cmd_gline(Instance);\r}\r\r/** Handle /GLINE\r */\rCmdResult cmd_gline::Handle (const char** parameters, int pcnt, userrec *user)\r{\r      if (pcnt >= 3)\r {\r              IdentHostPair ih = ServerInstance->XLines->IdentSplit(parameters[0]);\r          if (ServerInstance->HostMatchesEveryone(ih.first+"@"+ih.second,user))\r                  return CMD_FAILURE;\r\r           if (!strchr(parameters[0],'@'))\r                {       \r                       user->WriteServ("NOTICE %s :*** G-Line must contain a username, e.g. *@%s",user->nick,parameters[0]);\r                  return CMD_FAILURE;\r            }\r              else if (strchr(parameters[0],'!'))\r            {\r                      user->WriteServ("NOTICE %s :*** G-Line cannot contain a nickname!",user->nick);\r                        return CMD_FAILURE;\r            }\r\r             long duration = ServerInstance->Duration(parameters[1]);\r               if (ServerInstance->XLines->add_gline(duration,user->nick,parameters[2],parameters[0]))\r                {\r                      int to_apply = APPLY_GLINES;\r\r                  FOREACH_MOD(I_OnAddGLine,OnAddGLine(duration, user, parameters[2], parameters[0]));\r\r                   if (!duration)\r                 {\r                              ServerInstance->SNO->WriteToSnoMask('x',"%s added permanent G-line for %s.",user->nick,parameters[0]);\r                         to_apply |= APPLY_PERM_ONLY;\r                   }\r                      else\r                   {\r                              time_t c_requires_crap = duration + ServerInstance->Time();\r                            ServerInstance->SNO->WriteToSnoMask('x',"%s added timed G-line for %s, expires on %s",user->nick,parameters[0],\r                                                ServerInstance->TimeString(c_requires_crap).c_str());\r                  }\r\r                     ServerInstance->XLines->apply_lines(to_apply);\r         }\r              else\r           {\r                      user->WriteServ("NOTICE %s :*** G-Line for %s already exists",user->nick,parameters[0]);\r               }\r\r     }\r      else\r   {\r              if (ServerInstance->XLines->del_gline(parameters[0]))\r          {\r                      FOREACH_MOD(I_OnDelGLine,OnDelGLine(user, parameters[0]));\r                     ServerInstance->SNO->WriteToSnoMask('x',"%s Removed G-line on %s.",user->nick,parameters[0]);\r          }\r              else\r           {\r                      user->WriteServ("NOTICE %s :*** G-line %s not found in list, try /stats g.",user->nick,parameters[0]);\r         }\r      }\r\r     return CMD_SUCCESS;\r}\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "configreader.h"
+#include "users.h"
+#include "modules.h"
+#include "xline.h"
+#include "commands/cmd_gline.h"
+
+extern "C" DllExport command_t* init_command(InspIRCd* Instance)
+{
+       return new cmd_gline(Instance);
+}
+
+/** Handle /GLINE
+ */
+CmdResult cmd_gline::Handle (const char** parameters, int pcnt, userrec *user)
+{
+       if (pcnt >= 3)
+       {
+               IdentHostPair ih = ServerInstance->XLines->IdentSplit(parameters[0]);
+               if (ServerInstance->HostMatchesEveryone(ih.first+"@"+ih.second,user))
+                       return CMD_FAILURE;
+
+               if (!strchr(parameters[0],'@'))
+               {       
+                       user->WriteServ("NOTICE %s :*** G-Line must contain a username, e.g. *@%s",user->nick,parameters[0]);
+                       return CMD_FAILURE;
+               }
+               else if (strchr(parameters[0],'!'))
+               {
+                       user->WriteServ("NOTICE %s :*** G-Line cannot contain a nickname!",user->nick);
+                       return CMD_FAILURE;
+               }
+
+               long duration = ServerInstance->Duration(parameters[1]);
+               if (ServerInstance->XLines->add_gline(duration,user->nick,parameters[2],parameters[0]))
+               {
+                       int to_apply = APPLY_GLINES;
+
+                       FOREACH_MOD(I_OnAddGLine,OnAddGLine(duration, user, parameters[2], parameters[0]));
+
+                       if (!duration)
+                       {
+                               ServerInstance->SNO->WriteToSnoMask('x',"%s added permanent G-line for %s.",user->nick,parameters[0]);
+                               to_apply |= APPLY_PERM_ONLY;
+                       }
+                       else
+                       {
+                               time_t c_requires_crap = duration + ServerInstance->Time();
+                               ServerInstance->SNO->WriteToSnoMask('x',"%s added timed G-line for %s, expires on %s",user->nick,parameters[0],
+                                               ServerInstance->TimeString(c_requires_crap).c_str());
+                       }
+
+                       ServerInstance->XLines->apply_lines(to_apply);
+               }
+               else
+               {
+                       user->WriteServ("NOTICE %s :*** G-Line for %s already exists",user->nick,parameters[0]);
+               }
+
+       }
+       else
+       {
+               if (ServerInstance->XLines->del_gline(parameters[0]))
+               {
+                       FOREACH_MOD(I_OnDelGLine,OnDelGLine(user, parameters[0]));
+                       ServerInstance->SNO->WriteToSnoMask('x',"%s Removed G-line on %s.",user->nick,parameters[0]);
+               }
+               else
+               {
+                       user->WriteServ("NOTICE %s :*** G-line %s not found in list, try /stats g.",user->nick,parameters[0]);
+               }
+       }
+
+       return CMD_SUCCESS;
+}
+
index de6c18d8248364bf1b92462505d801268fd4b130..3564b0c6acf8f5996340bd887be91482459933a6 100644 (file)
@@ -1 +1,75 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "configreader.h"\r#include "users.h"\r#include "modules.h"\r#include "commands/cmd_info.h"\r\rextern "C" DllExport command_t* init_command(InspIRCd* Instance)\r{\r        return new cmd_info(Instance);\r}\r\r/** Handle /INFO\r */\rCmdResult cmd_info::Handle (const char** parameters, int pcnt, userrec *user)\r{\r user->WriteServ( "371 %s :. o O ( \2The Inspire Internet Relay Chat Server\2  ) O o .", user->nick);\r   user->WriteServ( "371 %s :      ( \2Putting the ricer into ircer since 2007\2 )", user->nick);\r user->WriteServ( "371 %s : ", user->nick);\r     user->WriteServ( "371 %s :\2Core Developers\2:", user->nick);\r  user->WriteServ( "371 %s :        Craig Edwards (Brain)", user->nick);\r user->WriteServ( "371 %s :        Craig McLure", user->nick);\r  user->WriteServ( "371 %s :        w00t", user->nick);\r  user->WriteServ( "371 %s :        Om", user->nick);\r    user->WriteServ( "371 %s :        Special", user->nick);\r       user->WriteServ( "371 %s :        pippijn", user->nick);\r       user->WriteServ( "371 %s :        peavey", user->nick);\r        user->WriteServ( "371 %s :        Burlex", user->nick);\r        user->WriteServ( "371 %s : ", user->nick);\r     user->WriteServ( "371 %s :\2Contributors\2:", user->nick);\r     user->WriteServ( "371 %s :        typobox43   Jazza", user->nick);\r     user->WriteServ( "371 %s :        jamie       LeaChim", user->nick);\r   user->WriteServ( "371 %s :        satmd       nenolod", user->nick);\r   user->WriteServ( "371 %s :        HiroP       BuildSmart", user->nick);\r        user->WriteServ( "371 %s : ", user->nick);\r     user->WriteServ( "371 %s :\2Quality Assurance\2:", user->nick);\r        user->WriteServ( "371 %s :        Bricker     owine", user->nick);\r     user->WriteServ( "371 %s :        dmb         Adremelech", user->nick);\r        user->WriteServ( "371 %s :        ThePopeSVCD satmd", user->nick);\r     user->WriteServ( "371 %s :\2Testers\2:", user->nick);\r  user->WriteServ( "371 %s :        CC          Piggles", user->nick);\r   user->WriteServ( "371 %s :        Foamy       Hart", user->nick);\r      user->WriteServ( "371 %s :        RageD       [ed]", user->nick);\r      user->WriteServ( "371 %s :        Azhrarn     luigiman", user->nick);\r  user->WriteServ( "371 %s :        Chu         aquanight", user->nick);\r user->WriteServ( "371 %s :        xptek       Grantlinks", user->nick);\r        user->WriteServ( "371 %s :        Rob         angelic", user->nick);\r   user->WriteServ( "371 %s :        Jason       ThaPrince", user->nick);\r user->WriteServ( "371 %s :        eggy        skenmy", user->nick);\r    user->WriteServ( "371 %s : ", user->nick);\r     user->WriteServ( "371 %s :Contains portions of \2FireDNS\2 written by", user->nick);\r   user->WriteServ( "371 %s :Ian Gulliver, (c) 2002.", user->nick);\r       user->WriteServ( "371 %s : ", user->nick);\r     user->WriteServ( "371 %s :Thanks to \2irc-junkie\2 and \2SearchIRC\2", user->nick);\r    user->WriteServ( "371 %s :for the nice comments and the help", user->nick);\r    user->WriteServ( "371 %s :you gave us in attracting users to", user->nick);\r    user->WriteServ( "371 %s :this software.", user->nick);\r        user->WriteServ( "371 %s : ", user->nick);\r     user->WriteServ( "371 %s :Best experienced with: \2An IRC client\2.", user->nick);\r     FOREACH_MOD(I_OnInfo,OnInfo(user));\r    user->WriteServ( "374 %s :End of /INFO list", user->nick);\r     return CMD_SUCCESS;\r}\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "configreader.h"
+#include "users.h"
+#include "modules.h"
+#include "commands/cmd_info.h"
+
+extern "C" DllExport command_t* init_command(InspIRCd* Instance)
+{
+       return new cmd_info(Instance);
+}
+
+/** Handle /INFO
+ */
+CmdResult cmd_info::Handle (const char** parameters, int pcnt, userrec *user)
+{
+       user->WriteServ( "371 %s :. o O ( \2The Inspire Internet Relay Chat Server\2  ) O o .", user->nick);
+       user->WriteServ( "371 %s :      ( \2Putting the ricer into ircer since 2007\2 )", user->nick);
+       user->WriteServ( "371 %s : ", user->nick);
+       user->WriteServ( "371 %s :\2Core Developers\2:", user->nick);
+       user->WriteServ( "371 %s :        Craig Edwards (Brain)", user->nick);
+       user->WriteServ( "371 %s :        Craig McLure", user->nick);
+       user->WriteServ( "371 %s :        w00t", user->nick);
+       user->WriteServ( "371 %s :        Om", user->nick);
+       user->WriteServ( "371 %s :        Special", user->nick);
+       user->WriteServ( "371 %s :        pippijn", user->nick);
+       user->WriteServ( "371 %s :        peavey", user->nick);
+       user->WriteServ( "371 %s :        Burlex", user->nick);
+       user->WriteServ( "371 %s : ", user->nick);
+       user->WriteServ( "371 %s :\2Contributors\2:", user->nick);
+       user->WriteServ( "371 %s :        typobox43   Jazza", user->nick);
+       user->WriteServ( "371 %s :        jamie       LeaChim", user->nick);
+       user->WriteServ( "371 %s :        satmd       nenolod", user->nick);
+       user->WriteServ( "371 %s :        HiroP       BuildSmart", user->nick);
+       user->WriteServ( "371 %s : ", user->nick);
+       user->WriteServ( "371 %s :\2Quality Assurance\2:", user->nick);
+       user->WriteServ( "371 %s :        Bricker     owine", user->nick);
+       user->WriteServ( "371 %s :        dmb         Adremelech", user->nick);
+       user->WriteServ( "371 %s :        ThePopeSVCD satmd", user->nick);
+       user->WriteServ( "371 %s :\2Testers\2:", user->nick);
+       user->WriteServ( "371 %s :        CC          Piggles", user->nick);
+       user->WriteServ( "371 %s :        Foamy       Hart", user->nick);
+       user->WriteServ( "371 %s :        RageD       [ed]", user->nick);
+       user->WriteServ( "371 %s :        Azhrarn     luigiman", user->nick);
+       user->WriteServ( "371 %s :        Chu         aquanight", user->nick);
+       user->WriteServ( "371 %s :        xptek       Grantlinks", user->nick);
+       user->WriteServ( "371 %s :        Rob         angelic", user->nick);
+       user->WriteServ( "371 %s :        Jason       ThaPrince", user->nick);
+       user->WriteServ( "371 %s :        eggy        skenmy", user->nick);
+       user->WriteServ( "371 %s : ", user->nick);
+       user->WriteServ( "371 %s :Contains portions of \2FireDNS\2 written by", user->nick);
+       user->WriteServ( "371 %s :Ian Gulliver, (c) 2002.", user->nick);
+       user->WriteServ( "371 %s : ", user->nick);
+       user->WriteServ( "371 %s :Thanks to \2irc-junkie\2 and \2SearchIRC\2", user->nick);
+       user->WriteServ( "371 %s :for the nice comments and the help", user->nick);
+       user->WriteServ( "371 %s :you gave us in attracting users to", user->nick);
+       user->WriteServ( "371 %s :this software.", user->nick);
+       user->WriteServ( "371 %s : ", user->nick);
+       user->WriteServ( "371 %s :Best experienced with: \2An IRC client\2.", user->nick);
+       FOREACH_MOD(I_OnInfo,OnInfo(user));
+       user->WriteServ( "374 %s :End of /INFO list", user->nick);
+       return CMD_SUCCESS;
+}
index 19330783edb038a48f5e8122566ea3f9465c98dc..0eb3a2354ccff70b1ad105fc96e71f36c9d806ce 100644 (file)
@@ -1 +1,98 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "configreader.h"\r#include "users.h"\r#include "modules.h"\r#include "commands/cmd_invite.h"\r\rextern "C" DllExport command_t* init_command(InspIRCd* Instance)\r{\r      return new cmd_invite(Instance);\r}\r\r/** Handle /INVITE\r */\rCmdResult cmd_invite::Handle (const char** parameters, int pcnt, userrec *user)\r{\r   int MOD_RESULT = 0;\r\r   if (pcnt == 2)\r {\r              userrec* u = ServerInstance->FindNick(parameters[0]);\r          chanrec* c = ServerInstance->FindChan(parameters[1]);\r\r         if ((!c) || (!u))\r              {\r                      if (!c)\r                        {\r                              user->WriteServ("401 %s %s :No such nick/channel",user->nick, parameters[1]);\r                  }\r                      else\r                   {\r                              user->WriteServ("401 %s %s :No such nick/channel",user->nick, parameters[0]);\r                  }\r\r                     return CMD_FAILURE;\r            }\r\r             if ((c->modes[CM_INVITEONLY]) && (IS_LOCAL(user)))\r             {\r                      if (c->GetStatus(user) < STATUS_HOP)\r                   {\r                              user->WriteServ("482 %s %s :You must be at least a half-operator to change modes on this channel",user->nick, c->name);\r                                return CMD_FAILURE;\r                    }\r              }\r\r             if (c->HasUser(u))\r             {\r                      user->WriteServ("443 %s %s %s :is already on channel",user->nick,u->nick,c->name);\r                     return CMD_FAILURE;\r            }\r\r             if ((IS_LOCAL(user)) && (!c->HasUser(user)))\r           {\r                      user->WriteServ("442 %s %s :You're not on that channel!",user->nick, c->name);\r                 return CMD_FAILURE;\r            }\r\r             FOREACH_RESULT(I_OnUserPreInvite,OnUserPreInvite(user,u,c));\r\r          if (MOD_RESULT == 1)\r           {\r                      return CMD_FAILURE;\r            }\r\r             u->InviteTo(c->name);\r          u->WriteFrom(user,"INVITE %s :%s",u->nick,c->name);\r            user->WriteServ("341 %s %s %s",user->nick,u->nick,c->name);\r            if (ServerInstance->Config->AnnounceInvites)\r                   c->WriteChannelWithServ(ServerInstance->Config->ServerName, "NOTICE %s :*** %s invited %s into the channel", c->name, user->nick, u->nick);\r            FOREACH_MOD(I_OnUserInvite,OnUserInvite(user,u,c));\r    }\r      else\r   {\r              // pinched from ircu - invite with not enough parameters shows channels\r                // youve been invited to but haven't joined yet.\r               InvitedList* il = user->GetInviteList();\r               for (InvitedList::iterator i = il->begin(); i != il->end(); i++)\r               {\r                      user->WriteServ("346 %s :%s",user->nick,i->c_str());\r           }\r              user->WriteServ("347 %s :End of INVITE list",user->nick);\r      }\r      return CMD_SUCCESS;\r}\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "configreader.h"
+#include "users.h"
+#include "modules.h"
+#include "commands/cmd_invite.h"
+
+extern "C" DllExport command_t* init_command(InspIRCd* Instance)
+{
+       return new cmd_invite(Instance);
+}
+
+/** Handle /INVITE
+ */
+CmdResult cmd_invite::Handle (const char** parameters, int pcnt, userrec *user)
+{
+       int MOD_RESULT = 0;
+
+       if (pcnt == 2)
+       {
+               userrec* u = ServerInstance->FindNick(parameters[0]);
+               chanrec* c = ServerInstance->FindChan(parameters[1]);
+
+               if ((!c) || (!u))
+               {
+                       if (!c)
+                       {
+                               user->WriteServ("401 %s %s :No such nick/channel",user->nick, parameters[1]);
+                       }
+                       else
+                       {
+                               user->WriteServ("401 %s %s :No such nick/channel",user->nick, parameters[0]);
+                       }
+
+                       return CMD_FAILURE;
+               }
+
+               if ((c->modes[CM_INVITEONLY]) && (IS_LOCAL(user)))
+               {
+                       if (c->GetStatus(user) < STATUS_HOP)
+                       {
+                               user->WriteServ("482 %s %s :You must be at least a half-operator to change modes on this channel",user->nick, c->name);
+                               return CMD_FAILURE;
+                       }
+               }
+
+               if (c->HasUser(u))
+               {
+                       user->WriteServ("443 %s %s %s :is already on channel",user->nick,u->nick,c->name);
+                       return CMD_FAILURE;
+               }
+
+               if ((IS_LOCAL(user)) && (!c->HasUser(user)))
+               {
+                       user->WriteServ("442 %s %s :You're not on that channel!",user->nick, c->name);
+                       return CMD_FAILURE;
+               }
+
+               FOREACH_RESULT(I_OnUserPreInvite,OnUserPreInvite(user,u,c));
+
+               if (MOD_RESULT == 1)
+               {
+                       return CMD_FAILURE;
+               }
+
+               u->InviteTo(c->name);
+               u->WriteFrom(user,"INVITE %s :%s",u->nick,c->name);
+               user->WriteServ("341 %s %s %s",user->nick,u->nick,c->name);
+               if (ServerInstance->Config->AnnounceInvites)
+                       c->WriteChannelWithServ(ServerInstance->Config->ServerName, "NOTICE %s :*** %s invited %s into the channel", c->name, user->nick, u->nick);
+               FOREACH_MOD(I_OnUserInvite,OnUserInvite(user,u,c));
+       }
+       else
+       {
+               // pinched from ircu - invite with not enough parameters shows channels
+               // youve been invited to but haven't joined yet.
+               InvitedList* il = user->GetInviteList();
+               for (InvitedList::iterator i = il->begin(); i != il->end(); i++)
+               {
+                       user->WriteServ("346 %s :%s",user->nick,i->c_str());
+               }
+               user->WriteServ("347 %s :End of INVITE list",user->nick);
+       }
+       return CMD_SUCCESS;
+}
+
index f630194271d3c5d7fb80c98774546c72a34fd6e3..0cee160c7f8e39c657328c6b9601594b9ab9d934 100644 (file)
@@ -1 +1,86 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "commands/cmd_ison.h"\r\rextern "C" DllExport command_t* init_command(InspIRCd* Instance)\r{\r       return new cmd_ison(Instance);\r}\r\r/** Handle /ISON\r */\rCmdResult cmd_ison::Handle (const char** parameters, int pcnt, userrec *user)\r{\r std::map<userrec*,userrec*> ison_already;\r      userrec *u;\r    std::string reply = std::string("303 ") + user->nick + " :";\r\r  for (int i = 0; i < pcnt; i++)\r {\r              u = ServerInstance->FindNick(parameters[i]);\r           if (ison_already.find(u) != ison_already.end())\r                        continue;\r\r             if (u)\r         {\r                      reply.append(u->nick).append(" ");\r                     if (reply.length() > 450)\r                      {\r                              user->WriteServ(reply);\r                                reply = std::string("303 ") + user->nick + " :";\r                       }\r                      ison_already[u] = u;\r           }\r              else\r           {\r                      if ((i == pcnt-1) && (strchr(parameters[i],' ')))\r                      {\r                              /* Its a space seperated list of nicks (RFC1459 says to support this)\r                           */\r                            irc::spacesepstream list(parameters[i]);\r                               std::string item("*");\r                         while (((item = list.GetToken()) != ""))\r                               {\r                                      u = ServerInstance->FindNick(item);\r                                    if (ison_already.find(u) != ison_already.end())\r                                                continue;\r\r                                     if (u)\r                                 {\r                                              if (u->Visibility && !u->Visibility->VisibleTo(user))\r                                                  continue;\r\r                                             reply.append(u->nick).append(" ");\r                                             if (reply.length() > 450)\r                                              {\r                                                      user->WriteServ(reply);\r                                                        reply = std::string("303 ") + user->nick + " :";\r                                               }\r                                              ison_already[u] = u;\r                                   }\r                              }\r                      }\r                      /* There will only be one of these, we can bail after. */\r                      break;\r         }\r      }\r\r     if (!reply.empty())\r            user->WriteServ(reply);\r\r       return CMD_SUCCESS;\r}\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "commands/cmd_ison.h"
+
+extern "C" DllExport command_t* init_command(InspIRCd* Instance)
+{
+       return new cmd_ison(Instance);
+}
+
+/** Handle /ISON
+ */
+CmdResult cmd_ison::Handle (const char** parameters, int pcnt, userrec *user)
+{
+       std::map<userrec*,userrec*> ison_already;
+       userrec *u;
+       std::string reply = std::string("303 ") + user->nick + " :";
+
+       for (int i = 0; i < pcnt; i++)
+       {
+               u = ServerInstance->FindNick(parameters[i]);
+               if (ison_already.find(u) != ison_already.end())
+                       continue;
+
+               if (u)
+               {
+                       reply.append(u->nick).append(" ");
+                       if (reply.length() > 450)
+                       {
+                               user->WriteServ(reply);
+                               reply = std::string("303 ") + user->nick + " :";
+                       }
+                       ison_already[u] = u;
+               }
+               else
+               {
+                       if ((i == pcnt-1) && (strchr(parameters[i],' ')))
+                       {
+                               /* Its a space seperated list of nicks (RFC1459 says to support this)
+                                */
+                               irc::spacesepstream list(parameters[i]);
+                               std::string item("*");
+                               while (((item = list.GetToken()) != ""))
+                               {
+                                       u = ServerInstance->FindNick(item);
+                                       if (ison_already.find(u) != ison_already.end())
+                                               continue;
+
+                                       if (u)
+                                       {
+                                               if (u->Visibility && !u->Visibility->VisibleTo(user))
+                                                       continue;
+
+                                               reply.append(u->nick).append(" ");
+                                               if (reply.length() > 450)
+                                               {
+                                                       user->WriteServ(reply);
+                                                       reply = std::string("303 ") + user->nick + " :";
+                                               }
+                                               ison_already[u] = u;
+                                       }
+                               }
+                       }
+                       /* There will only be one of these, we can bail after. */
+                       break;
+               }
+       }
+
+       if (!reply.empty())
+               user->WriteServ(reply);
+
+       return CMD_SUCCESS;
+}
+
index 6780ac4beac3b2040c88d2e13ee14160a4346812..218e0f7b8b33229c28f675d35b9648fb90521369 100644 (file)
@@ -1 +1,52 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "commands/cmd_join.h"\r\rextern "C" DllExport command_t* init_command(InspIRCd* Instance)\r{\r       return new cmd_join(Instance);\r}\r\r/** Handle /JOIN\r */\rCmdResult cmd_join::Handle (const char** parameters, int pcnt, userrec *user)\r{\r if (pcnt > 1)\r  {\r              if (ServerInstance->Parser->LoopCall(user, this, parameters, pcnt, 0, 1))\r                      return CMD_SUCCESS;\r\r           if (ServerInstance->IsChannel(parameters[0]))\r          {\r                      chanrec::JoinUser(ServerInstance, user, parameters[0], false, parameters[1]);\r                  return CMD_SUCCESS;\r            }\r      }\r      else\r   {\r              if (ServerInstance->Parser->LoopCall(user, this, parameters, pcnt, 0))\r                 return CMD_SUCCESS;\r\r           if (ServerInstance->IsChannel(parameters[0]))\r          {\r                      chanrec::JoinUser(ServerInstance, user, parameters[0], false, "");\r                     return CMD_SUCCESS;\r            }\r      }\r\r     user->WriteServ("403 %s %s :Invalid channel name",user->nick, parameters[0]);\r  return CMD_FAILURE;\r}\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "commands/cmd_join.h"
+
+extern "C" DllExport command_t* init_command(InspIRCd* Instance)
+{
+       return new cmd_join(Instance);
+}
+
+/** Handle /JOIN
+ */
+CmdResult cmd_join::Handle (const char** parameters, int pcnt, userrec *user)
+{
+       if (pcnt > 1)
+       {
+               if (ServerInstance->Parser->LoopCall(user, this, parameters, pcnt, 0, 1))
+                       return CMD_SUCCESS;
+
+               if (ServerInstance->IsChannel(parameters[0]))
+               {
+                       chanrec::JoinUser(ServerInstance, user, parameters[0], false, parameters[1]);
+                       return CMD_SUCCESS;
+               }
+       }
+       else
+       {
+               if (ServerInstance->Parser->LoopCall(user, this, parameters, pcnt, 0))
+                       return CMD_SUCCESS;
+
+               if (ServerInstance->IsChannel(parameters[0]))
+               {
+                       chanrec::JoinUser(ServerInstance, user, parameters[0], false, "");
+                       return CMD_SUCCESS;
+               }
+       }
+
+       user->WriteServ("403 %s %s :Invalid channel name",user->nick, parameters[0]);
+       return CMD_FAILURE;
+}
index 263cf35c540a089c4785413adad77b98f22c41f4..17933a43f9a7467fb5d3a17f9d05fa09da658a4b 100644 (file)
@@ -1 +1,58 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "inspircd.h"\r#include "commands/cmd_kick.h"\r\rextern "C" DllExport command_t* init_command(InspIRCd* Instance)\r{\r return new cmd_kick(Instance);\r}\r\r/** Handle /KICK\r */\rCmdResult cmd_kick::Handle (const char** parameters, int pcnt, userrec *user)\r{\r char reason[MAXKICK];\r  chanrec* c = ServerInstance->FindChan(parameters[0]);\r  userrec* u = ServerInstance->FindNick(parameters[1]);\r\r if (!u || !c)\r  {\r              user->WriteServ( "401 %s %s :No such nick/channel", user->nick, u ? parameters[0] : parameters[1]);\r            return CMD_FAILURE;\r    }\r\r     if ((IS_LOCAL(user)) && (!c->HasUser(user)) && (!ServerInstance->ULine(user->server)))\r {\r              user->WriteServ( "442 %s %s :You're not on that channel!", user->nick, parameters[0]);\r         return CMD_FAILURE;\r    }\r\r     if (pcnt > 2)\r  {\r              strlcpy(reason, parameters[2], MAXKICK - 1);\r   }\r      else\r   {\r              strlcpy(reason, user->nick, MAXKICK - 1);\r      }\r\r     if (!c->KickUser(user, u, reason))\r             /* Nobody left here, delete the chanrec */\r             delete c;\r\r     return CMD_SUCCESS;\r}\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "inspircd.h"
+#include "commands/cmd_kick.h"
+
+extern "C" DllExport command_t* init_command(InspIRCd* Instance)
+{
+       return new cmd_kick(Instance);
+}
+
+/** Handle /KICK
+ */
+CmdResult cmd_kick::Handle (const char** parameters, int pcnt, userrec *user)
+{
+       char reason[MAXKICK];
+       chanrec* c = ServerInstance->FindChan(parameters[0]);
+       userrec* u = ServerInstance->FindNick(parameters[1]);
+
+       if (!u || !c)
+       {
+               user->WriteServ( "401 %s %s :No such nick/channel", user->nick, u ? parameters[0] : parameters[1]);
+               return CMD_FAILURE;
+       }
+
+       if ((IS_LOCAL(user)) && (!c->HasUser(user)) && (!ServerInstance->ULine(user->server)))
+       {
+               user->WriteServ( "442 %s %s :You're not on that channel!", user->nick, parameters[0]);
+               return CMD_FAILURE;
+       }
+
+       if (pcnt > 2)
+       {
+               strlcpy(reason, parameters[2], MAXKICK - 1);
+       }
+       else
+       {
+               strlcpy(reason, user->nick, MAXKICK - 1);
+       }
+
+       if (!c->KickUser(user, u, reason))
+               /* Nobody left here, delete the chanrec */
+               delete c;
+
+       return CMD_SUCCESS;
+}
index b8dbfc34588c1a8b0eca228be09c74042472afcb..26f354b8f2bf3e654b8ed21e557f0bb02afc8106 100644 (file)
@@ -1 +1,117 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "configreader.h"\r#include "users.h"\r#include "modules.h"\r#include "wildcard.h"\r#include "commands/cmd_kill.h"\r\rextern "C" DllExport command_t* init_command(InspIRCd* Instance)\r{\r  return new cmd_kill(Instance);\r}\r\r/** Handle /KILL\r */\rCmdResult cmd_kill::Handle (const char** parameters, int pcnt, userrec *user)\r{\r /* Allow comma seperated lists of users for /KILL (thanks w00t) */\r     if (ServerInstance->Parser->LoopCall(user, this, parameters, pcnt, 0))\r         return CMD_SUCCESS;\r\r   userrec *u = ServerInstance->FindNick(parameters[0]);\r  char killreason[MAXBUF];\r       char killoperreason[MAXBUF];\r   int MOD_RESULT = 0;\r\r   if (u)\r {\r              /*\r              * Here, we need to decide how to munge kill messages. Whether to hide killer, what to show opers, etc.\r                 * We only do this when the command is being issued LOCALLY, for remote KILL, we just copy the message we got.\r          *\r              * This conditional is so that we only append the "Killed (" prefix ONCE. If killer is remote, then the kill\r            * just gets processed and passed on, otherwise, if they are local, it gets prefixed. Makes sense :-) -- w00t\r           */\r            if (IS_LOCAL(user))\r            {\r                      /*\r                      * Moved this event inside the IS_LOCAL check also, we don't want half the network killing a user\r                       * and the other half not. This would be a bad thing. ;p -- w00t\r                        */\r                    FOREACH_RESULT(I_OnKill, OnKill(user, u, parameters[1]));\r\r                     if (MOD_RESULT)\r                                return CMD_FAILURE;\r\r                   if (*ServerInstance->Config->HideKillsServer)\r                  {\r                              // hidekills is on, use it\r                             snprintf(killreason, MAXQUIT, "Killed (%s (%s))", ServerInstance->Config->HideKillsServer, parameters[1]);\r                     }\r                      else\r                   {\r                              // hidekills is off, do nothing\r                                snprintf(killreason, MAXQUIT, "Killed (%s (%s))", user->nick, parameters[1]);\r                  }\r\r                     // opers are lucky ducks, they always see the real reason\r                      snprintf(killoperreason, MAXQUIT, "Killed (%s (%s))", user->nick, parameters[1]);\r              }\r              else\r           {\r                      snprintf(killreason, MAXQUIT, "%s", parameters[1]);\r                    /*\r                      * XXX - yes, this means opers will probably see a censored kill remotely. this needs fixing.\r                   * maybe a version of QuitUser that doesn't take nor propegate an oper reason? -- w00t\r                  */\r                    snprintf(killoperreason, MAXQUIT, "%s", parameters[1]);\r                }\r\r             /*\r              * Now we need to decide whether or not to send a local or remote snotice. Currently this checking is a little flawed.\r          * No time to fix it right now, so left a note. -- w00t\r                 */\r            if (!IS_LOCAL(u))\r              {\r                      // remote kill\r                 ServerInstance->SNO->WriteToSnoMask('K', "Remote kill by %s: %s!%s@%s (%s)", user->nick, u->nick, u->ident, u->host, parameters[1]);\r                   FOREACH_MOD(I_OnRemoteKill, OnRemoteKill(user, u, killreason, killoperreason));\r                }\r              else\r           {\r                      // local kill\r                  /*\r                      * XXX - this isn't entirely correct, servers A - B - C, oper on A, client on C. Oper kills client, A and B will get remote kill\r                        * snotices, C will get a local kill snotice. this isn't accurate, and needs fixing at some stage. -- w00t\r                      */\r                    ServerInstance->SNO->WriteToSnoMask('k',"Local Kill by %s: %s!%s@%s (%s)", user->nick, u->nick, u->ident, u->host, parameters[1]);\r                     ServerInstance->Log(DEFAULT,"LOCAL KILL: %s :%s!%s!%s (%s)", u->nick, ServerInstance->Config->ServerName, user->dhost, user->nick, parameters[1]);\r                     user->WriteTo(u, "KILL %s :%s!%s!%s (%s)", u->nick, ServerInstance->Config->ServerName, user->dhost,\r                                   *ServerInstance->Config->HideKillsServer ? ServerInstance->Config->HideKillsServer : user->nick, parameters[1]);\r               }\r\r             // send the quit out\r           userrec::QuitUser(ServerInstance, u, killreason, killoperreason);\r      }\r      else\r   {\r              user->WriteServ( "401 %s %s :No such nick/channel", user->nick, parameters[0]);\r                return CMD_FAILURE;\r    }\r\r     return CMD_SUCCESS;\r}\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "configreader.h"
+#include "users.h"
+#include "modules.h"
+#include "wildcard.h"
+#include "commands/cmd_kill.h"
+
+extern "C" DllExport command_t* init_command(InspIRCd* Instance)
+{
+       return new cmd_kill(Instance);
+}
+
+/** Handle /KILL
+ */
+CmdResult cmd_kill::Handle (const char** parameters, int pcnt, userrec *user)
+{
+       /* Allow comma seperated lists of users for /KILL (thanks w00t) */
+       if (ServerInstance->Parser->LoopCall(user, this, parameters, pcnt, 0))
+               return CMD_SUCCESS;
+
+       userrec *u = ServerInstance->FindNick(parameters[0]);
+       char killreason[MAXBUF];
+       char killoperreason[MAXBUF];
+       int MOD_RESULT = 0;
+
+       if (u)
+       {
+               /*
+                * Here, we need to decide how to munge kill messages. Whether to hide killer, what to show opers, etc.
+                * We only do this when the command is being issued LOCALLY, for remote KILL, we just copy the message we got.
+                *
+                * This conditional is so that we only append the "Killed (" prefix ONCE. If killer is remote, then the kill
+                * just gets processed and passed on, otherwise, if they are local, it gets prefixed. Makes sense :-) -- w00t
+                */
+               if (IS_LOCAL(user))
+               {
+                       /*
+                        * Moved this event inside the IS_LOCAL check also, we don't want half the network killing a user
+                        * and the other half not. This would be a bad thing. ;p -- w00t
+                        */
+                       FOREACH_RESULT(I_OnKill, OnKill(user, u, parameters[1]));
+
+                       if (MOD_RESULT)
+                               return CMD_FAILURE;
+
+                       if (*ServerInstance->Config->HideKillsServer)
+                       {
+                               // hidekills is on, use it
+                               snprintf(killreason, MAXQUIT, "Killed (%s (%s))", ServerInstance->Config->HideKillsServer, parameters[1]);
+                       }
+                       else
+                       {
+                               // hidekills is off, do nothing
+                               snprintf(killreason, MAXQUIT, "Killed (%s (%s))", user->nick, parameters[1]);
+                       }
+
+                       // opers are lucky ducks, they always see the real reason
+                       snprintf(killoperreason, MAXQUIT, "Killed (%s (%s))", user->nick, parameters[1]);
+               }
+               else
+               {
+                       snprintf(killreason, MAXQUIT, "%s", parameters[1]);
+                       /*
+                        * XXX - yes, this means opers will probably see a censored kill remotely. this needs fixing.
+                        * maybe a version of QuitUser that doesn't take nor propegate an oper reason? -- w00t
+                        */
+                       snprintf(killoperreason, MAXQUIT, "%s", parameters[1]);
+               }
+
+               /*
+                * Now we need to decide whether or not to send a local or remote snotice. Currently this checking is a little flawed.
+                * No time to fix it right now, so left a note. -- w00t
+                */
+               if (!IS_LOCAL(u))
+               {
+                       // remote kill
+                       ServerInstance->SNO->WriteToSnoMask('K', "Remote kill by %s: %s!%s@%s (%s)", user->nick, u->nick, u->ident, u->host, parameters[1]);
+                       FOREACH_MOD(I_OnRemoteKill, OnRemoteKill(user, u, killreason, killoperreason));
+               }
+               else
+               {
+                       // local kill
+                       /*
+                        * XXX - this isn't entirely correct, servers A - B - C, oper on A, client on C. Oper kills client, A and B will get remote kill
+                        * snotices, C will get a local kill snotice. this isn't accurate, and needs fixing at some stage. -- w00t
+                        */
+                       ServerInstance->SNO->WriteToSnoMask('k',"Local Kill by %s: %s!%s@%s (%s)", user->nick, u->nick, u->ident, u->host, parameters[1]);
+                       ServerInstance->Log(DEFAULT,"LOCAL KILL: %s :%s!%s!%s (%s)", u->nick, ServerInstance->Config->ServerName, user->dhost, user->nick, parameters[1]);
+                       user->WriteTo(u, "KILL %s :%s!%s!%s (%s)", u->nick, ServerInstance->Config->ServerName, user->dhost,
+                                       *ServerInstance->Config->HideKillsServer ? ServerInstance->Config->HideKillsServer : user->nick, parameters[1]);
+               }
+
+               // send the quit out
+               userrec::QuitUser(ServerInstance, u, killreason, killoperreason);
+       }
+       else
+       {
+               user->WriteServ( "401 %s %s :No such nick/channel", user->nick, parameters[0]);
+               return CMD_FAILURE;
+       }
+
+       return CMD_SUCCESS;
+}
+
index ac1aafe1589760f82053546fae363fbd2c306cc7..05856893a2195ccc7fe1d38c5464085e24d822e8 100644 (file)
@@ -1 +1,88 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "configreader.h"\r#include "users.h"\r#include "modules.h"\r#include "xline.h"\r#include "commands/cmd_kline.h"\r\rextern "C" DllExport command_t* init_command(InspIRCd* Instance)\r{\r    return new cmd_kline(Instance);\r}\r\r/** Handle /KLINE\r */\rCmdResult cmd_kline::Handle (const char** parameters, int pcnt, userrec *user)\r{\r      if (pcnt >= 3)\r {\r              IdentHostPair ih = ServerInstance->XLines->IdentSplit(parameters[0]);\r          if (ServerInstance->HostMatchesEveryone(ih.first+"@"+ih.second,user))\r                  return CMD_FAILURE;\r\r           if (!strchr(parameters[0],'@'))\r                {       \r                       user->WriteServ("NOTICE %s :*** K-Line must contain a username, e.g. *@%s",user->nick,parameters[0]);\r                  return CMD_FAILURE;\r            }\r              else if (strchr(parameters[0],'!'))\r            {\r                      user->WriteServ("NOTICE %s :*** K-Line cannot contain a nickname!",user->nick);\r                        return CMD_FAILURE;\r            }\r\r             long duration = ServerInstance->Duration(parameters[1]);\r               if (ServerInstance->XLines->add_kline(duration,user->nick,parameters[2],parameters[0]))\r                {\r                      int to_apply = APPLY_KLINES;\r\r                  FOREACH_MOD(I_OnAddKLine,OnAddKLine(duration, user, parameters[2], parameters[0]));\r    \r                       if (!duration)\r                 {\r                              ServerInstance->SNO->WriteToSnoMask('x',"%s added permanent K-line for %s.",user->nick,parameters[0]);\r                         to_apply |= APPLY_PERM_ONLY;\r                   }\r                      else\r                   {\r                              time_t c_requires_crap = duration + ServerInstance->Time();\r                            ServerInstance->SNO->WriteToSnoMask('x',"%s added timed K-line for %s, expires on %s",user->nick,parameters[0],\r                                                ServerInstance->TimeString(c_requires_crap).c_str());\r                  }\r\r                     ServerInstance->XLines->apply_lines(to_apply);\r         }\r              else\r           {\r                      user->WriteServ("NOTICE %s :*** K-Line for %s already exists",user->nick,parameters[0]);\r               }\r      }\r      else\r   {\r              if (ServerInstance->XLines->del_kline(parameters[0]))\r          {\r                      FOREACH_MOD(I_OnDelKLine,OnDelKLine(user, parameters[0]));\r                     ServerInstance->SNO->WriteToSnoMask('x',"%s Removed K-line on %s.",user->nick,parameters[0]);\r          }\r              else\r           {\r                      user->WriteServ("NOTICE %s :*** K-Line %s not found in list, try /stats k.",user->nick,parameters[0]);\r         }\r      }\r\r     return CMD_SUCCESS;\r}\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "configreader.h"
+#include "users.h"
+#include "modules.h"
+#include "xline.h"
+#include "commands/cmd_kline.h"
+
+extern "C" DllExport command_t* init_command(InspIRCd* Instance)
+{
+       return new cmd_kline(Instance);
+}
+
+/** Handle /KLINE
+ */
+CmdResult cmd_kline::Handle (const char** parameters, int pcnt, userrec *user)
+{
+       if (pcnt >= 3)
+       {
+               IdentHostPair ih = ServerInstance->XLines->IdentSplit(parameters[0]);
+               if (ServerInstance->HostMatchesEveryone(ih.first+"@"+ih.second,user))
+                       return CMD_FAILURE;
+
+               if (!strchr(parameters[0],'@'))
+               {       
+                       user->WriteServ("NOTICE %s :*** K-Line must contain a username, e.g. *@%s",user->nick,parameters[0]);
+                       return CMD_FAILURE;
+               }
+               else if (strchr(parameters[0],'!'))
+               {
+                       user->WriteServ("NOTICE %s :*** K-Line cannot contain a nickname!",user->nick);
+                       return CMD_FAILURE;
+               }
+
+               long duration = ServerInstance->Duration(parameters[1]);
+               if (ServerInstance->XLines->add_kline(duration,user->nick,parameters[2],parameters[0]))
+               {
+                       int to_apply = APPLY_KLINES;
+
+                       FOREACH_MOD(I_OnAddKLine,OnAddKLine(duration, user, parameters[2], parameters[0]));
+       
+                       if (!duration)
+                       {
+                               ServerInstance->SNO->WriteToSnoMask('x',"%s added permanent K-line for %s.",user->nick,parameters[0]);
+                               to_apply |= APPLY_PERM_ONLY;
+                       }
+                       else
+                       {
+                               time_t c_requires_crap = duration + ServerInstance->Time();
+                               ServerInstance->SNO->WriteToSnoMask('x',"%s added timed K-line for %s, expires on %s",user->nick,parameters[0],
+                                               ServerInstance->TimeString(c_requires_crap).c_str());
+                       }
+
+                       ServerInstance->XLines->apply_lines(to_apply);
+               }
+               else
+               {
+                       user->WriteServ("NOTICE %s :*** K-Line for %s already exists",user->nick,parameters[0]);
+               }
+       }
+       else
+       {
+               if (ServerInstance->XLines->del_kline(parameters[0]))
+               {
+                       FOREACH_MOD(I_OnDelKLine,OnDelKLine(user, parameters[0]));
+                       ServerInstance->SNO->WriteToSnoMask('x',"%s Removed K-line on %s.",user->nick,parameters[0]);
+               }
+               else
+               {
+                       user->WriteServ("NOTICE %s :*** K-Line %s not found in list, try /stats k.",user->nick,parameters[0]);
+               }
+       }
+
+       return CMD_SUCCESS;
+}
+
index 39f01383e30965413be833288c51e4ccc47d6e9c..83e558d5dac66468f9021f5b87427f33a7185a75 100644 (file)
@@ -1 +1,32 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "configreader.h"\r#include "users.h"\r#include "modules.h"\r#include "commands/cmd_links.h"\r\rextern "C" DllExport command_t* init_command(InspIRCd* Instance)\r{\r       return new cmd_links(Instance);\r}\r\r/** Handle /LINKS\r */\rCmdResult cmd_links::Handle (const char** parameters, int pcnt, userrec *user)\r{\r      user->WriteServ("364 %s %s %s :0 %s",user->nick,ServerInstance->Config->ServerName,ServerInstance->Config->ServerName,ServerInstance->Config->ServerDesc);\r     user->WriteServ("365 %s * :End of /LINKS list.",user->nick);\r   return CMD_SUCCESS;\r}\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "configreader.h"
+#include "users.h"
+#include "modules.h"
+#include "commands/cmd_links.h"
+
+extern "C" DllExport command_t* init_command(InspIRCd* Instance)
+{
+       return new cmd_links(Instance);
+}
+
+/** Handle /LINKS
+ */
+CmdResult cmd_links::Handle (const char** parameters, int pcnt, userrec *user)
+{
+       user->WriteServ("364 %s %s %s :0 %s",user->nick,ServerInstance->Config->ServerName,ServerInstance->Config->ServerName,ServerInstance->Config->ServerDesc);
+       user->WriteServ("365 %s * :End of /LINKS list.",user->nick);
+       return CMD_SUCCESS;
+}
index 14cf4527213c89912a2dd345b425b6991fdb7509..ed956e7f10ab178cb9b5ebc551c84d4df6a673c0 100644 (file)
@@ -1 +1,85 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "inspircd.h"\r#include "commands/cmd_list.h"\r#include "wildcard.h"\r\r/** Handle /LIST\r */\rextern "C" DllExport command_t* init_command(InspIRCd* Instance)\r{\r      return new cmd_list(Instance);\r}\r\rCmdResult cmd_list::Handle (const char** parameters, int pcnt, userrec *user)\r{\r      int minusers = 0, maxusers = 0;\r\r       user->WriteServ("321 %s Channel :Users Name",user->nick);\r\r     /* Work around mIRC suckyness. YOU SUCK, KHALED! */\r    if (pcnt == 1)\r {\r              if (*parameters[0] == '<')\r             {\r                      maxusers = atoi(parameters[0]+1);\r                      pcnt = 0;\r              }\r              else if (*parameters[0] == '>')\r                {\r                      minusers = atoi(parameters[0]+1);\r                      pcnt = 0;\r              }\r      }\r\r     for (chan_hash::const_iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++)\r       {\r              // attempt to match a glob pattern\r             long users = i->second->GetUserCounter();\r\r             bool too_few = (minusers && (users <= minusers));\r              bool too_many = (maxusers && (users >= maxusers));\r\r            if (too_many || too_few)\r                       continue;\r\r             if (pcnt)\r              {\r                      if (!match(i->second->name, parameters[0]) && !match(i->second->topic, parameters[0]))\r                         continue;\r              }\r\r             // if the channel is not private/secret, OR the user is on the channel anyway\r          bool n = i->second->HasUser(user);\r             if ((i->second->modes[CM_PRIVATE]) && (!n))\r            {\r                      if (users)\r                             user->WriteServ("322 %s *",user->nick,i->second->name);\r                }\r              else\r           {\r                      if (((!(i->second->modes[CM_PRIVATE])) && (!(i->second->modes[CM_SECRET]))) || (n))\r                    {\r                              long users = i->second->GetUserCounter();\r                              if (users)\r                                     user->WriteServ("322 %s %s %d :[+%s] %s",user->nick,i->second->name,users,i->second->ChanModes(n),i->second->topic);\r                   }\r              }\r      }\r      user->WriteServ("323 %s :End of channel list.",user->nick);\r\r   return CMD_SUCCESS;\r}\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "inspircd.h"
+#include "commands/cmd_list.h"
+#include "wildcard.h"
+
+/** Handle /LIST
+ */
+extern "C" DllExport command_t* init_command(InspIRCd* Instance)
+{
+       return new cmd_list(Instance);
+}
+
+CmdResult cmd_list::Handle (const char** parameters, int pcnt, userrec *user)
+{
+       int minusers = 0, maxusers = 0;
+
+       user->WriteServ("321 %s Channel :Users Name",user->nick);
+
+       /* Work around mIRC suckyness. YOU SUCK, KHALED! */
+       if (pcnt == 1)
+       {
+               if (*parameters[0] == '<')
+               {
+                       maxusers = atoi(parameters[0]+1);
+                       pcnt = 0;
+               }
+               else if (*parameters[0] == '>')
+               {
+                       minusers = atoi(parameters[0]+1);
+                       pcnt = 0;
+               }
+       }
+
+       for (chan_hash::const_iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++)
+       {
+               // attempt to match a glob pattern
+               long users = i->second->GetUserCounter();
+
+               bool too_few = (minusers && (users <= minusers));
+               bool too_many = (maxusers && (users >= maxusers));
+
+               if (too_many || too_few)
+                       continue;
+
+               if (pcnt)
+               {
+                       if (!match(i->second->name, parameters[0]) && !match(i->second->topic, parameters[0]))
+                               continue;
+               }
+
+               // if the channel is not private/secret, OR the user is on the channel anyway
+               bool n = i->second->HasUser(user);
+               if ((i->second->modes[CM_PRIVATE]) && (!n))
+               {
+                       if (users)
+                               user->WriteServ("322 %s *",user->nick,i->second->name);
+               }
+               else
+               {
+                       if (((!(i->second->modes[CM_PRIVATE])) && (!(i->second->modes[CM_SECRET]))) || (n))
+                       {
+                               long users = i->second->GetUserCounter();
+                               if (users)
+                                       user->WriteServ("322 %s %s %d :[+%s] %s",user->nick,i->second->name,users,i->second->ChanModes(n),i->second->topic);
+                       }
+               }
+       }
+       user->WriteServ("323 %s :End of channel list.",user->nick);
+
+       return CMD_SUCCESS;
+}
index 07776c1a849c888d1889f5cc9218a7b852e3a2a9..08179d120bab506b2d9dc828270ae058c5fce379 100644 (file)
@@ -1 +1,39 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "commands/cmd_loadmodule.h"\r\rextern "C" DllExport command_t* init_command(InspIRCd* Instance)\r{\r return new cmd_loadmodule(Instance);\r}\r\r/** Handle /LOADMODULE\r */\rCmdResult cmd_loadmodule::Handle (const char** parameters, int pcnt, userrec *user)\r{\r       if (ServerInstance->LoadModule(parameters[0]))\r {\r              ServerInstance->WriteOpers("*** NEW MODULE: %s loaded %s",user->nick, parameters[0]);\r          user->WriteServ("975 %s %s :Module successfully loaded.",user->nick, parameters[0]);\r           return CMD_SUCCESS;\r    }\r      else\r   {\r              user->WriteServ("974 %s %s :Failed to load module: %s",user->nick, parameters[0],ServerInstance->ModuleError());\r               return CMD_FAILURE;\r    }\r}\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "commands/cmd_loadmodule.h"
+
+extern "C" DllExport command_t* init_command(InspIRCd* Instance)
+{
+       return new cmd_loadmodule(Instance);
+}
+
+/** Handle /LOADMODULE
+ */
+CmdResult cmd_loadmodule::Handle (const char** parameters, int pcnt, userrec *user)
+{
+       if (ServerInstance->LoadModule(parameters[0]))
+       {
+               ServerInstance->WriteOpers("*** NEW MODULE: %s loaded %s",user->nick, parameters[0]);
+               user->WriteServ("975 %s %s :Module successfully loaded.",user->nick, parameters[0]);
+               return CMD_SUCCESS;
+       }
+       else
+       {
+               user->WriteServ("974 %s %s :Failed to load module: %s",user->nick, parameters[0],ServerInstance->ModuleError());
+               return CMD_FAILURE;
+       }
+}
+
index 87194d9e231ef318612c383e438ba7011f1d5e1d..fa58ca076619251285d9a4dc2a7fbc19eef25750 100644 (file)
@@ -1 +1,42 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "inspircd.h"\r#include "commands/cmd_lusers.h"\r\rextern "C" DllExport command_t* init_command(InspIRCd* Instance)\r{\r       return new cmd_lusers(Instance);\r}\r\r/** Handle /LUSERS\r */\rCmdResult cmd_lusers::Handle (const char** parameters, int pcnt, userrec *user)\r{\r   // this lusers command shows one server at all times because\r   // a protocol module must override it to show those stats.\r     user->WriteServ("251 %s :There are %d users and %d invisible on 1 server",user->nick,ServerInstance->UserCount()-ServerInstance->InvisibleUserCount(),ServerInstance->InvisibleUserCount());\r   if (ServerInstance->OperCount())\r               user->WriteServ("252 %s %d :operator(s) online",user->nick,ServerInstance->OperCount());\r       if (ServerInstance->UnregisteredUserCount())\r           user->WriteServ("253 %s %d :unknown connections",user->nick,ServerInstance->UnregisteredUserCount());\r  if (ServerInstance->ChannelCount())\r            user->WriteServ("254 %s %d :channels formed",user->nick,ServerInstance->ChannelCount());\r       if (ServerInstance->LocalUserCount())\r          user->WriteServ("255 %s :I have %d clients and 0 servers",user->nick,ServerInstance->LocalUserCount());\r\r       return CMD_SUCCESS;\r}\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "inspircd.h"
+#include "commands/cmd_lusers.h"
+
+extern "C" DllExport command_t* init_command(InspIRCd* Instance)
+{
+       return new cmd_lusers(Instance);
+}
+
+/** Handle /LUSERS
+ */
+CmdResult cmd_lusers::Handle (const char** parameters, int pcnt, userrec *user)
+{
+       // this lusers command shows one server at all times because
+       // a protocol module must override it to show those stats.
+       user->WriteServ("251 %s :There are %d users and %d invisible on 1 server",user->nick,ServerInstance->UserCount()-ServerInstance->InvisibleUserCount(),ServerInstance->InvisibleUserCount());
+       if (ServerInstance->OperCount())
+               user->WriteServ("252 %s %d :operator(s) online",user->nick,ServerInstance->OperCount());
+       if (ServerInstance->UnregisteredUserCount())
+               user->WriteServ("253 %s %d :unknown connections",user->nick,ServerInstance->UnregisteredUserCount());
+       if (ServerInstance->ChannelCount())
+               user->WriteServ("254 %s %d :channels formed",user->nick,ServerInstance->ChannelCount());
+       if (ServerInstance->LocalUserCount())
+               user->WriteServ("255 %s :I have %d clients and 0 servers",user->nick,ServerInstance->LocalUserCount());
+
+       return CMD_SUCCESS;
+}
+
index 270374cbf0a568e81f67a7188290fb60cb1a86f2..c75a18b3f6949506ff7ed8c5af01130bc802de00 100644 (file)
@@ -1 +1,35 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "configreader.h"\r#include "users.h"\r#include "commands/cmd_map.h"\r\rextern "C" DllExport command_t* init_command(InspIRCd* Instance)\r{\r      return new cmd_map(Instance);\r}\r\r/** Handle /MAP\r */\rCmdResult cmd_map::Handle (const char** parameters, int pcnt, userrec *user)\r{\r    // as with /LUSERS this does nothing without a linking\r // module to override its behaviour and display something\r      // better.\r     user->WriteServ("006 %s :%s",user->nick,ServerInstance->Config->ServerName);\r   user->WriteServ("007 %s :End of /MAP",user->nick);\r\r    return CMD_SUCCESS;\r}\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "configreader.h"
+#include "users.h"
+#include "commands/cmd_map.h"
+
+extern "C" DllExport command_t* init_command(InspIRCd* Instance)
+{
+       return new cmd_map(Instance);
+}
+
+/** Handle /MAP
+ */
+CmdResult cmd_map::Handle (const char** parameters, int pcnt, userrec *user)
+{
+       // as with /LUSERS this does nothing without a linking
+       // module to override its behaviour and display something
+       // better.
+       user->WriteServ("006 %s :%s",user->nick,ServerInstance->Config->ServerName);
+       user->WriteServ("007 %s :End of /MAP",user->nick);
+
+       return CMD_SUCCESS;
+}
index 563fa75db17c0628ed7dcf5faf775232b8a159f5..18c1e69ad995d901d4d69005987b769d134b2060 100644 (file)
@@ -1 +1,31 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "configreader.h"\r#include "users.h"\r#include "commands/cmd_mode.h"\r\rextern "C" DllExport command_t* init_command(InspIRCd* Instance)\r{\r     return new cmd_mode(Instance);\r}\r\r/** Handle /MODE\r */\rCmdResult cmd_mode::Handle (const char** parameters, int pcnt, userrec *user)\r{\r ServerInstance->Modes->Process(parameters, pcnt, user, false);\r return CMD_SUCCESS;\r}\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "configreader.h"
+#include "users.h"
+#include "commands/cmd_mode.h"
+
+extern "C" DllExport command_t* init_command(InspIRCd* Instance)
+{
+       return new cmd_mode(Instance);
+}
+
+/** Handle /MODE
+ */
+CmdResult cmd_mode::Handle (const char** parameters, int pcnt, userrec *user)
+{
+       ServerInstance->Modes->Process(parameters, pcnt, user, false);
+       return CMD_SUCCESS;
+}
+
index b8812c22dea4473a15faccc0879d6b37f057c71b..be236fcd92dec16ffbb6b6a6e315befe829339d1 100644 (file)
@@ -1 +1,75 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "configreader.h"\r#include "users.h"\r#include "modules.h"\r#include "wildcard.h"\r#include "commands/cmd_modules.h"\r\rchar* itab[] = {\r "OnUserConnect", "OnUserQuit", "OnUserDisconnect", "OnUserJoin", "OnUserPart", "OnRehash", "OnServerRaw",\r      "OnUserPreJoin", "OnUserPreKick", "OnUserKick", "OnOper", "OnInfo", "OnWhois", "OnUserPreInvite",\r      "OnUserInvite", "OnUserPreMessage", "OnUserPreNotice", "OnUserPreNick", "OnUserMessage", "OnUserNotice", "OnMode",\r     "OnGetServerDescription", "OnSyncUser", "OnSyncChannel", "OnSyncChannelMetaData", "OnSyncUserMetaData",\r        "OnDecodeMetaData", "ProtoSendMode", "ProtoSendMetaData", "OnWallops", "OnChangeHost", "OnChangeName", "OnAddGLine",\r   "OnAddZLine", "OnAddQLine", "OnAddKLine", "OnAddELine", "OnDelGLine", "OnDelZLine", "OnDelKLine", "OnDelELine", "OnDelQLine",\r  "OnCleanup", "OnUserPostNick", "OnAccessCheck", "On005Numeric", "OnKill", "OnRemoteKill", "OnLoadModule", "OnUnloadModule",\r    "OnBackgroundTimer", "OnSendList", "OnPreCommand", "OnCheckReady", "OnUserRegister", "OnCheckInvite",\r  "OnCheckKey", "OnCheckLimit", "OnCheckBan", "OnStats", "OnChangeLocalUserHost", "OnChangeLocalUserGecos", "OnLocalTopicChange",\r        "OnPostLocalTopicChange", "OnEvent", "OnRequest", "OnOperCompre", "OnGlobalOper", "OnPostConnect", "OnAddBan", "OnDelBan",\r     "OnRawSocketAccept", "OnRawSocketClose", "OnRawSocketWrite", "OnRawSocketRead", "OnChangeLocalUserGECOS", "OnUserRegister",\r    "OnOperCompare", "OnChannelDelete", "OnPostOper", "OnSyncOtherMetaData", "OnSetAway", "OnCancelAway", "OnNamesList",\r   "OnPostCommand", "OnPostJoin", "OnWhoisLine", "OnBuildExemptList", "OnRawSocketConnect", "OnGarbageCollect", NULL\r};\r\rextern "C" DllExport command_t* init_command(InspIRCd* Instance)\r{\r       return new cmd_modules(Instance);\r}\r\r/** Handle /MODULES\r */\rCmdResult cmd_modules::Handle (const char** parameters, int pcnt, userrec *user)\r{\r        for (unsigned int i = 0; i < ServerInstance->Config->module_names.size(); i++)\r {\r              Version V = ServerInstance->modules[i]->GetVersion();\r          char modulename[MAXBUF];\r               char flagstate[MAXBUF];\r                *flagstate = 0;\r                if (V.Flags & VF_STATIC)\r                       strlcat(flagstate,", static",MAXBUF);\r          if (V.Flags & VF_VENDOR)\r                       strlcat(flagstate,", vendor",MAXBUF);\r          if (V.Flags & VF_COMMON)\r                       strlcat(flagstate,", common",MAXBUF);\r          if (V.Flags & VF_SERVICEPROVIDER)\r                      strlcat(flagstate,", service provider",MAXBUF);\r                if (!flagstate[0])\r                     strcpy(flagstate,"  <no flags>");\r              strlcpy(modulename,ServerInstance->Config->module_names[i].c_str(),256);\r               if (IS_OPER(user))\r             {\r                      user->WriteServ("900 %s :0x%08lx %d.%d.%d.%d %s (%s)",user->nick,ServerInstance->modules[i],V.Major,V.Minor,V.Revision,V.Build,ServerConfig::CleanFilename(modulename),flagstate+2);\r           }\r              else\r           {\r                      user->WriteServ("900 %s :%s",user->nick,ServerConfig::CleanFilename(modulename));\r              }\r      }\r      user->WriteServ("901 %s :End of MODULES list",user->nick);\r\r    return CMD_SUCCESS;\r}\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "configreader.h"
+#include "users.h"
+#include "modules.h"
+#include "wildcard.h"
+#include "commands/cmd_modules.h"
+
+char* itab[] = {
+       "OnUserConnect", "OnUserQuit", "OnUserDisconnect", "OnUserJoin", "OnUserPart", "OnRehash", "OnServerRaw",
+       "OnUserPreJoin", "OnUserPreKick", "OnUserKick", "OnOper", "OnInfo", "OnWhois", "OnUserPreInvite",
+       "OnUserInvite", "OnUserPreMessage", "OnUserPreNotice", "OnUserPreNick", "OnUserMessage", "OnUserNotice", "OnMode",
+       "OnGetServerDescription", "OnSyncUser", "OnSyncChannel", "OnSyncChannelMetaData", "OnSyncUserMetaData",
+       "OnDecodeMetaData", "ProtoSendMode", "ProtoSendMetaData", "OnWallops", "OnChangeHost", "OnChangeName", "OnAddGLine",
+       "OnAddZLine", "OnAddQLine", "OnAddKLine", "OnAddELine", "OnDelGLine", "OnDelZLine", "OnDelKLine", "OnDelELine", "OnDelQLine",
+       "OnCleanup", "OnUserPostNick", "OnAccessCheck", "On005Numeric", "OnKill", "OnRemoteKill", "OnLoadModule", "OnUnloadModule",
+       "OnBackgroundTimer", "OnSendList", "OnPreCommand", "OnCheckReady", "OnUserRegister", "OnCheckInvite",
+       "OnCheckKey", "OnCheckLimit", "OnCheckBan", "OnStats", "OnChangeLocalUserHost", "OnChangeLocalUserGecos", "OnLocalTopicChange",
+       "OnPostLocalTopicChange", "OnEvent", "OnRequest", "OnOperCompre", "OnGlobalOper", "OnPostConnect", "OnAddBan", "OnDelBan",
+       "OnRawSocketAccept", "OnRawSocketClose", "OnRawSocketWrite", "OnRawSocketRead", "OnChangeLocalUserGECOS", "OnUserRegister",
+       "OnOperCompare", "OnChannelDelete", "OnPostOper", "OnSyncOtherMetaData", "OnSetAway", "OnCancelAway", "OnNamesList",
+       "OnPostCommand", "OnPostJoin", "OnWhoisLine", "OnBuildExemptList", "OnRawSocketConnect", "OnGarbageCollect", NULL
+};
+
+extern "C" DllExport command_t* init_command(InspIRCd* Instance)
+{
+       return new cmd_modules(Instance);
+}
+
+/** Handle /MODULES
+ */
+CmdResult cmd_modules::Handle (const char** parameters, int pcnt, userrec *user)
+{
+       for (unsigned int i = 0; i < ServerInstance->Config->module_names.size(); i++)
+       {
+               Version V = ServerInstance->modules[i]->GetVersion();
+               char modulename[MAXBUF];
+               char flagstate[MAXBUF];
+               *flagstate = 0;
+               if (V.Flags & VF_STATIC)
+                       strlcat(flagstate,", static",MAXBUF);
+               if (V.Flags & VF_VENDOR)
+                       strlcat(flagstate,", vendor",MAXBUF);
+               if (V.Flags & VF_COMMON)
+                       strlcat(flagstate,", common",MAXBUF);
+               if (V.Flags & VF_SERVICEPROVIDER)
+                       strlcat(flagstate,", service provider",MAXBUF);
+               if (!flagstate[0])
+                       strcpy(flagstate,"  <no flags>");
+               strlcpy(modulename,ServerInstance->Config->module_names[i].c_str(),256);
+               if (IS_OPER(user))
+               {
+                       user->WriteServ("900 %s :0x%08lx %d.%d.%d.%d %s (%s)",user->nick,ServerInstance->modules[i],V.Major,V.Minor,V.Revision,V.Build,ServerConfig::CleanFilename(modulename),flagstate+2);
+               }
+               else
+               {
+                       user->WriteServ("900 %s :%s",user->nick,ServerConfig::CleanFilename(modulename));
+               }
+       }
+       user->WriteServ("901 %s :End of MODULES list",user->nick);
+
+       return CMD_SUCCESS;
+}
index f14af0bd15f708cc1b463c2f5e9525ccbfeb8d8c..6aaf1a9af2979e006e932e71732a0c0f7a09f18b 100644 (file)
@@ -1 +1,29 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "commands/cmd_motd.h"\r\rextern "C" DllExport command_t* init_command(InspIRCd* Instance)\r{\r       return new cmd_motd(Instance);\r}\r\r/** Handle /MOTD\r */\rCmdResult cmd_motd::Handle (const char** parameters, int pcnt, userrec *user)\r{\r user->ShowMOTD();\r      return CMD_SUCCESS;\r}\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "commands/cmd_motd.h"
+
+extern "C" DllExport command_t* init_command(InspIRCd* Instance)
+{
+       return new cmd_motd(Instance);
+}
+
+/** Handle /MOTD
+ */
+CmdResult cmd_motd::Handle (const char** parameters, int pcnt, userrec *user)
+{
+       user->ShowMOTD();
+       return CMD_SUCCESS;
+}
index c157c3c040d5e7423bb6e16050108913ebfa9985..fe61c4dea3f6c61aba99004adac1323e7b7ce4e9 100644 (file)
@@ -1 +1,54 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "commands/cmd_names.h"\r\rextern "C" DllExport command_t* init_command(InspIRCd* Instance)\r{\r      return new cmd_names(Instance);\r}\r\r/** Handle /NAMES\r */\rCmdResult cmd_names::Handle (const char** parameters, int pcnt, userrec *user)\r{\r      chanrec* c;\r\r   if (!pcnt)\r     {\r              user->WriteServ("366 %s * :End of /NAMES list.",user->nick);\r           return CMD_SUCCESS;\r    }\r\r     if (ServerInstance->Parser->LoopCall(user, this, parameters, pcnt, 0))\r         return CMD_SUCCESS;\r\r   c = ServerInstance->FindChan(parameters[0]);\r   if (c)\r {\r              if ((c->modes[CM_SECRET]) && (!c->HasUser(user)))\r              {\r                    user->WriteServ("401 %s %s :No such nick/channel",user->nick, c->name);\r                return CMD_FAILURE;\r              }\r              c->UserList(user);\r     }\r      else\r   {\r              user->WriteServ("401 %s %s :No such nick/channel",user->nick, parameters[0]);\r  }\r\r     return CMD_SUCCESS;\r}\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "commands/cmd_names.h"
+
+extern "C" DllExport command_t* init_command(InspIRCd* Instance)
+{
+       return new cmd_names(Instance);
+}
+
+/** Handle /NAMES
+ */
+CmdResult cmd_names::Handle (const char** parameters, int pcnt, userrec *user)
+{
+       chanrec* c;
+
+       if (!pcnt)
+       {
+               user->WriteServ("366 %s * :End of /NAMES list.",user->nick);
+               return CMD_SUCCESS;
+       }
+
+       if (ServerInstance->Parser->LoopCall(user, this, parameters, pcnt, 0))
+               return CMD_SUCCESS;
+
+       c = ServerInstance->FindChan(parameters[0]);
+       if (c)
+       {
+               if ((c->modes[CM_SECRET]) && (!c->HasUser(user)))
+               {
+                     user->WriteServ("401 %s %s :No such nick/channel",user->nick, c->name);
+                     return CMD_FAILURE;
+               }
+               c->UserList(user);
+       }
+       else
+       {
+               user->WriteServ("401 %s %s :No such nick/channel",user->nick, parameters[0]);
+       }
+
+       return CMD_SUCCESS;
+}
index 5bc9ce6d1243cd823be6ef6a745728f7250a5ace..4e2ebcf6e425de17bdc7797a0dac2c03475dd4b5 100644 (file)
@@ -1 +1,189 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "configreader.h"\r#include "users.h"\r#include "modules.h"\r#include "xline.h"\r#include "commands/cmd_nick.h"\r\rextern "C" DllExport command_t* init_command(InspIRCd* Instance)\r{\r     return new cmd_nick(Instance);\r}\r\r/** Handle nick changes from users.\r * NOTE: If you are used to ircds based on ircd2.8, and are looking\r * for the client introduction code in here, youre in the wrong place.\r * You need to look in the spanningtree module for this!\r */\rCmdResult cmd_nick::Handle (const char** parameters, int pcnt, userrec *user)\r{\r  char oldnick[NICKMAX];\r\r        if (!*parameters[0] || !*user->nick)\r   {\r              /* We cant put blanks in the parameters, so for this (extremely rare) issue we just put '*' here. */\r           user->WriteServ("432 %s * :Erroneous Nickname", *user->nick ? user->nick : "*");\r               return CMD_FAILURE;\r    }\r\r     if (irc::string(user->nick) == irc::string(parameters[0]))\r     {\r              /* If its exactly the same, even case, dont do anything. */\r            if (!strcmp(user->nick,parameters[0]))\r                 return CMD_SUCCESS;\r\r           /* Its a change of case. People insisted that they should be\r            * able to do silly things like this even though the RFC says\r           * the nick AAA is the same as the nick aaa.\r            */\r            strlcpy(oldnick, user->nick, NICKMAX - 1);\r             int MOD_RESULT = 0;\r            FOREACH_RESULT(I_OnUserPreNick,OnUserPreNick(user,parameters[0]));\r             if (MOD_RESULT)\r                        return CMD_FAILURE;\r            if (user->registered == REG_ALL)\r                       user->WriteCommon("NICK %s",parameters[0]);\r            strlcpy(user->nick, parameters[0], NICKMAX - 1);\r               user->InvalidateCache();\r               FOREACH_MOD(I_OnUserPostNick,OnUserPostNick(user,oldnick));\r            return CMD_SUCCESS;\r    }\r      else\r   {\r              QLine* mq = ServerInstance->XLines->matches_qline(parameters[0]);\r              if (mq)\r                {\r                      ServerInstance->SNO->WriteToSnoMask('x', "Q-Lined nickname %s from %s!%s@%s: %s", parameters[0], user->nick, user->ident, user->host, mq->reason);\r                     user->WriteServ("432 %s %s :Invalid nickname: %s",user->nick,parameters[0], mq->reason);\r                       return CMD_FAILURE;\r            }\r              /* Check for nickname overruled -\r               * This happens when one user has connected and sent only NICK, and is essentially\r              * "camping" upon a nickname. To give the new user connecting a fair chance of having\r           * the nickname too, we force a nickchange on the older user (Simply the one who was\r            * here first, no TS checks need to take place here)\r            */\r            userrec* InUse = ServerInstance->FindNick(parameters[0]);\r              if (InUse && (InUse != user) && (ServerInstance->IsNick(parameters[0])))\r               {\r                      if (InUse->registered != REG_ALL)\r                      {\r                              /* change the nick of the older user to nnn-overruled,\r                          * where nnn is their file descriptor. We know this to be unique.\r                               * NOTE: We must do this and not quit the user, even though we do\r                               * not have UID support yet. This is because if we set this user\r                                * as quitting and then introduce the new user before the old one\r                               * has quit, then the user hash gets totally buggered.\r                          * (Yes, that is a technical term). -- Brain\r                            */\r                            std::string changeback = ConvToStr(InUse->GetFd()) + "-overruled";\r                             InUse->WriteTo(InUse, "NICK %s", changeback.c_str());\r                          InUse->WriteServ("433 %s %s :Nickname overruled.", InUse->nick, InUse->nick);\r                          InUse->UpdateNickHash(changeback.c_str());\r                             strlcpy(InUse->nick, changeback.c_str(), NICKMAX - 1);\r                         InUse->InvalidateCache();\r                              /* Take away their nickname-sent state forcing them to send a nick again */\r                            InUse->registered &= ~REG_NICK;\r                        }\r                      else\r                   {\r                              user->WriteServ("433 %s %s :Nickname is already in use.", user->registered >= REG_NICK ? user->nick : "*", parameters[0]);\r                             return CMD_FAILURE;\r                    }\r              }\r      }\r      if ((!ServerInstance->IsNick(parameters[0])) && (IS_LOCAL(user)))\r      {\r              user->WriteServ("432 %s %s :Erroneous Nickname",user->nick,parameters[0]);\r             return CMD_FAILURE;\r    }\r\r     if (user->registered == REG_ALL)\r       {\r              int MOD_RESULT = 0;\r            FOREACH_RESULT(I_OnUserPreNick,OnUserPreNick(user,parameters[0]));\r             if (MOD_RESULT) {\r                      // if a module returns true, the nick change is silently forbidden.\r                    return CMD_FAILURE;\r            }\r\r             user->WriteCommon("NICK %s",parameters[0]);\r\r   }\r\r     strlcpy(oldnick, user->nick, NICKMAX - 1);\r\r    /* change the nick of the user in the users_hash */\r    user = user->UpdateNickHash(parameters[0]);\r\r   /* actually change the nick within the record */\r       if (!user) return CMD_FAILURE;\r if (!*user->nick) return CMD_FAILURE;\r\r strlcpy(user->nick, parameters[0], NICKMAX - 1);\r\r      user->InvalidateCache();\r\r      /* Update display nicks */\r     for (UCListIter v = user->chans.begin(); v != user->chans.end(); v++)\r  {\r              CUList* ulist = v->first->GetUsers();\r          CUList::iterator i = ulist->find(user);\r                if (i != ulist->end())\r                 i->second = user->nick;\r        }\r\r     if (user->registered < REG_NICKUSER)\r   {\r              user->registered = (user->registered | REG_NICK);\r\r             if (ServerInstance->Config->NoUserDns)\r         {\r                      user->dns_done = true;\r                 ServerInstance->next_call = ServerInstance->Time();\r            }\r              else\r           {\r                      user->StartDNSLookup();\r                        if (user->dns_done)\r                    {\r                              /* Cached result or instant failure - fall right through if possible */\r                                ServerInstance->next_call = ServerInstance->Time();\r                    }\r                      else\r                   {\r                              if (ServerInstance->next_call > ServerInstance->Time() + ServerInstance->Config->dns_timeout)\r                                  ServerInstance->next_call = ServerInstance->Time() + ServerInstance->Config->dns_timeout;\r                      }\r              }\r      }\r      if (user->registered == REG_NICKUSER)\r  {\r              /* user is registered now, bit 0 = USER command, bit 1 = sent a NICK command */\r                int MOD_RESULT = 0;\r            FOREACH_RESULT(I_OnUserRegister,OnUserRegister(user));\r         if (MOD_RESULT > 0)\r                    return CMD_FAILURE;\r    }\r      if (user->registered == REG_ALL)\r       {\r              FOREACH_MOD(I_OnUserPostNick,OnUserPostNick(user,oldnick));\r    }\r\r     return CMD_SUCCESS;\r\r}\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "configreader.h"
+#include "users.h"
+#include "modules.h"
+#include "xline.h"
+#include "commands/cmd_nick.h"
+
+extern "C" DllExport command_t* init_command(InspIRCd* Instance)
+{
+       return new cmd_nick(Instance);
+}
+
+/** Handle nick changes from users.
+ * NOTE: If you are used to ircds based on ircd2.8, and are looking
+ * for the client introduction code in here, youre in the wrong place.
+ * You need to look in the spanningtree module for this!
+ */
+CmdResult cmd_nick::Handle (const char** parameters, int pcnt, userrec *user)
+{
+       char oldnick[NICKMAX];
+
+       if (!*parameters[0] || !*user->nick)
+       {
+               /* We cant put blanks in the parameters, so for this (extremely rare) issue we just put '*' here. */
+               user->WriteServ("432 %s * :Erroneous Nickname", *user->nick ? user->nick : "*");
+               return CMD_FAILURE;
+       }
+
+       if (irc::string(user->nick) == irc::string(parameters[0]))
+       {
+               /* If its exactly the same, even case, dont do anything. */
+               if (!strcmp(user->nick,parameters[0]))
+                       return CMD_SUCCESS;
+
+               /* Its a change of case. People insisted that they should be
+                * able to do silly things like this even though the RFC says
+                * the nick AAA is the same as the nick aaa.
+                */
+               strlcpy(oldnick, user->nick, NICKMAX - 1);
+               int MOD_RESULT = 0;
+               FOREACH_RESULT(I_OnUserPreNick,OnUserPreNick(user,parameters[0]));
+               if (MOD_RESULT)
+                       return CMD_FAILURE;
+               if (user->registered == REG_ALL)
+                       user->WriteCommon("NICK %s",parameters[0]);
+               strlcpy(user->nick, parameters[0], NICKMAX - 1);
+               user->InvalidateCache();
+               FOREACH_MOD(I_OnUserPostNick,OnUserPostNick(user,oldnick));
+               return CMD_SUCCESS;
+       }
+       else
+       {
+               QLine* mq = ServerInstance->XLines->matches_qline(parameters[0]);
+               if (mq)
+               {
+                       ServerInstance->SNO->WriteToSnoMask('x', "Q-Lined nickname %s from %s!%s@%s: %s", parameters[0], user->nick, user->ident, user->host, mq->reason);
+                       user->WriteServ("432 %s %s :Invalid nickname: %s",user->nick,parameters[0], mq->reason);
+                       return CMD_FAILURE;
+               }
+               /* Check for nickname overruled -
+                * This happens when one user has connected and sent only NICK, and is essentially
+                * "camping" upon a nickname. To give the new user connecting a fair chance of having
+                * the nickname too, we force a nickchange on the older user (Simply the one who was
+                * here first, no TS checks need to take place here)
+                */
+               userrec* InUse = ServerInstance->FindNick(parameters[0]);
+               if (InUse && (InUse != user) && (ServerInstance->IsNick(parameters[0])))
+               {
+                       if (InUse->registered != REG_ALL)
+                       {
+                               /* change the nick of the older user to nnn-overruled,
+                                * where nnn is their file descriptor. We know this to be unique.
+                                * NOTE: We must do this and not quit the user, even though we do
+                                * not have UID support yet. This is because if we set this user
+                                * as quitting and then introduce the new user before the old one
+                                * has quit, then the user hash gets totally buggered.
+                                * (Yes, that is a technical term). -- Brain
+                                */
+                               std::string changeback = ConvToStr(InUse->GetFd()) + "-overruled";
+                               InUse->WriteTo(InUse, "NICK %s", changeback.c_str());
+                               InUse->WriteServ("433 %s %s :Nickname overruled.", InUse->nick, InUse->nick);
+                               InUse->UpdateNickHash(changeback.c_str());
+                               strlcpy(InUse->nick, changeback.c_str(), NICKMAX - 1);
+                               InUse->InvalidateCache();
+                               /* Take away their nickname-sent state forcing them to send a nick again */
+                               InUse->registered &= ~REG_NICK;
+                       }
+                       else
+                       {
+                               user->WriteServ("433 %s %s :Nickname is already in use.", user->registered >= REG_NICK ? user->nick : "*", parameters[0]);
+                               return CMD_FAILURE;
+                       }
+               }
+       }
+       if ((!ServerInstance->IsNick(parameters[0])) && (IS_LOCAL(user)))
+       {
+               user->WriteServ("432 %s %s :Erroneous Nickname",user->nick,parameters[0]);
+               return CMD_FAILURE;
+       }
+
+       if (user->registered == REG_ALL)
+       {
+               int MOD_RESULT = 0;
+               FOREACH_RESULT(I_OnUserPreNick,OnUserPreNick(user,parameters[0]));
+               if (MOD_RESULT) {
+                       // if a module returns true, the nick change is silently forbidden.
+                       return CMD_FAILURE;
+               }
+
+               user->WriteCommon("NICK %s",parameters[0]);
+
+       }
+
+       strlcpy(oldnick, user->nick, NICKMAX - 1);
+
+       /* change the nick of the user in the users_hash */
+       user = user->UpdateNickHash(parameters[0]);
+
+       /* actually change the nick within the record */
+       if (!user) return CMD_FAILURE;
+       if (!*user->nick) return CMD_FAILURE;
+
+       strlcpy(user->nick, parameters[0], NICKMAX - 1);
+
+       user->InvalidateCache();
+
+       /* Update display nicks */
+       for (UCListIter v = user->chans.begin(); v != user->chans.end(); v++)
+       {
+               CUList* ulist = v->first->GetUsers();
+               CUList::iterator i = ulist->find(user);
+               if (i != ulist->end())
+                       i->second = user->nick;
+       }
+
+       if (user->registered < REG_NICKUSER)
+       {
+               user->registered = (user->registered | REG_NICK);
+
+               if (ServerInstance->Config->NoUserDns)
+               {
+                       user->dns_done = true;
+                       ServerInstance->next_call = ServerInstance->Time();
+               }
+               else
+               {
+                       user->StartDNSLookup();
+                       if (user->dns_done)
+                       {
+                               /* Cached result or instant failure - fall right through if possible */
+                               ServerInstance->next_call = ServerInstance->Time();
+                       }
+                       else
+                       {
+                               if (ServerInstance->next_call > ServerInstance->Time() + ServerInstance->Config->dns_timeout)
+                                       ServerInstance->next_call = ServerInstance->Time() + ServerInstance->Config->dns_timeout;
+                       }
+               }
+       }
+       if (user->registered == REG_NICKUSER)
+       {
+               /* user is registered now, bit 0 = USER command, bit 1 = sent a NICK command */
+               int MOD_RESULT = 0;
+               FOREACH_RESULT(I_OnUserRegister,OnUserRegister(user));
+               if (MOD_RESULT > 0)
+                       return CMD_FAILURE;
+       }
+       if (user->registered == REG_ALL)
+       {
+               FOREACH_MOD(I_OnUserPostNick,OnUserPostNick(user,oldnick));
+       }
+
+       return CMD_SUCCESS;
+
+}
+
index 27fdd527978ea884ae34bb08b44cd5b962126dc4..a797fefabc509c1cdcf136666dc377416ae434e7 100644 (file)
@@ -1 +1,158 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "configreader.h"\r#include "users.h"\r#include "modules.h"\r#include "wildcard.h"\r#include "commands/cmd_notice.h"\r\rextern "C" DllExport command_t* init_command(InspIRCd* Instance)\r{\r        return new cmd_notice(Instance);\r}\r\rCmdResult cmd_notice::Handle (const char** parameters, int pcnt, userrec *user)\r{\r  userrec *dest;\r chanrec *chan;\r\r        CUList exempt_list;\r\r   user->idle_lastmsg = ServerInstance->Time();\r   \r       if (ServerInstance->Parser->LoopCall(user, this, parameters, pcnt, 0))\r         return CMD_SUCCESS;\r    if ((parameters[0][0] == '$') && (IS_OPER(user) || ServerInstance->ULine(user->server)))\r       {\r              int MOD_RESULT = 0;\r            std::string temp = parameters[1];\r              FOREACH_RESULT(I_OnUserPreNotice,OnUserPreNotice(user,(void*)parameters[0],TYPE_SERVER,temp,0,exempt_list));\r           if (MOD_RESULT)\r                        return CMD_FAILURE;\r            parameters[1] = temp.c_str();\r          // notice to server mask\r               const char* servermask = parameters[0] + 1;\r            if (match(ServerInstance->Config->ServerName,servermask))\r              {\r                      user->SendAll("NOTICE", "%s", parameters[1]);\r          }\r              FOREACH_MOD(I_OnUserNotice,OnUserNotice(user,(void*)parameters[0],TYPE_SERVER,parameters[1],0,exempt_list));\r           return CMD_SUCCESS;\r    }\r      char status = 0;\r       if ((*parameters[0] == '@') || (*parameters[0] == '%') || (*parameters[0] == '+'))\r     {\r              status = *parameters[0];\r               parameters[0]++;\r       }\r      if (*parameters[0] == '#')\r     {\r              chan = ServerInstance->FindChan(parameters[0]);\r\r               exempt_list[user] = user->nick;\r\r               if (chan)\r              {\r                      if (IS_LOCAL(user))\r                    {\r                              if ((chan->modes[CM_NOEXTERNAL]) && (!chan->HasUser(user)))\r                            {\r                                      user->WriteServ("404 %s %s :Cannot send to channel (no external messages)", user->nick, chan->name);\r                                   return CMD_FAILURE;\r                            }\r                              if ((chan->modes[CM_MODERATED]) && (chan->GetStatus(user) < STATUS_VOICE))\r                             {\r                                      user->WriteServ("404 %s %s :Cannot send to channel (+m)", user->nick, chan->name);\r                                     return CMD_FAILURE;\r                            }\r                      }\r                      int MOD_RESULT = 0;\r\r                   std::string temp = parameters[1];\r                      FOREACH_RESULT(I_OnUserPreNotice,OnUserPreNotice(user,chan,TYPE_CHANNEL,temp,status, exempt_list));\r                    if (MOD_RESULT) {\r                              return CMD_FAILURE;\r                    }\r                      parameters[1] = temp.c_str();\r\r                 if (temp.empty())\r                      {\r                              user->WriteServ("412 %s :No text to send", user->nick);\r                                return CMD_FAILURE;\r                    }\r\r                     if (status)\r                    {\r                              if (ServerInstance->Config->UndernetMsgPrefix)\r                         {\r                                      chan->WriteAllExcept(user, false, status, exempt_list, "NOTICE %c%s :%c %s", status, chan->name, status, parameters[1]);\r                               }\r                              else\r                           {\r                                      chan->WriteAllExcept(user, false, status, exempt_list, "NOTICE %c%s :%s", status, chan->name, parameters[1]);\r                          }\r                      }\r                      else\r                   {\r                              chan->WriteAllExcept(user, false, status, exempt_list, "NOTICE %s :%s", chan->name, parameters[1]);\r                    }\r\r                     FOREACH_MOD(I_OnUserNotice,OnUserNotice(user,chan,TYPE_CHANNEL,parameters[1],status,exempt_list));\r             }\r              else\r           {\r                      /* no such nick/channel */\r                     user->WriteServ("401 %s %s :No such nick/channel",user->nick, parameters[0]);\r                  return CMD_FAILURE;\r            }\r              return CMD_SUCCESS;\r    }\r      \r       dest = ServerInstance->FindNick(parameters[0]);\r        if (dest)\r      {\r              if (!*parameters[1])\r           {\r                      user->WriteServ("412 %s :No text to send", user->nick);\r                        return CMD_FAILURE;\r            }\r\r             int MOD_RESULT = 0;\r            std::string temp = parameters[1];\r              FOREACH_RESULT(I_OnUserPreNotice,OnUserPreNotice(user,dest,TYPE_USER,temp,0,exempt_list));\r             if (MOD_RESULT) {\r                      return CMD_FAILURE;\r            }\r              parameters[1] = (char*)temp.c_str();\r\r          if (IS_LOCAL(dest))\r            {\r                      // direct write, same server\r                   user->WriteTo(dest, "NOTICE %s :%s", dest->nick, parameters[1]);\r               }\r\r             FOREACH_MOD(I_OnUserNotice,OnUserNotice(user,dest,TYPE_USER,parameters[1],0,exempt_list));\r     }\r      else\r   {\r              /* no such nick/channel */\r             user->WriteServ("401 %s %s :No such nick/channel",user->nick, parameters[0]);\r          return CMD_FAILURE;\r    }\r\r     return CMD_SUCCESS;\r\r}\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "configreader.h"
+#include "users.h"
+#include "modules.h"
+#include "wildcard.h"
+#include "commands/cmd_notice.h"
+
+extern "C" DllExport command_t* init_command(InspIRCd* Instance)
+{
+       return new cmd_notice(Instance);
+}
+
+CmdResult cmd_notice::Handle (const char** parameters, int pcnt, userrec *user)
+{
+       userrec *dest;
+       chanrec *chan;
+
+       CUList exempt_list;
+
+       user->idle_lastmsg = ServerInstance->Time();
+       
+       if (ServerInstance->Parser->LoopCall(user, this, parameters, pcnt, 0))
+               return CMD_SUCCESS;
+       if ((parameters[0][0] == '$') && (IS_OPER(user) || ServerInstance->ULine(user->server)))
+       {
+               int MOD_RESULT = 0;
+               std::string temp = parameters[1];
+               FOREACH_RESULT(I_OnUserPreNotice,OnUserPreNotice(user,(void*)parameters[0],TYPE_SERVER,temp,0,exempt_list));
+               if (MOD_RESULT)
+                       return CMD_FAILURE;
+               parameters[1] = temp.c_str();
+               // notice to server mask
+               const char* servermask = parameters[0] + 1;
+               if (match(ServerInstance->Config->ServerName,servermask))
+               {
+                       user->SendAll("NOTICE", "%s", parameters[1]);
+               }
+               FOREACH_MOD(I_OnUserNotice,OnUserNotice(user,(void*)parameters[0],TYPE_SERVER,parameters[1],0,exempt_list));
+               return CMD_SUCCESS;
+       }
+       char status = 0;
+       if ((*parameters[0] == '@') || (*parameters[0] == '%') || (*parameters[0] == '+'))
+       {
+               status = *parameters[0];
+               parameters[0]++;
+       }
+       if (*parameters[0] == '#')
+       {
+               chan = ServerInstance->FindChan(parameters[0]);
+
+               exempt_list[user] = user->nick;
+
+               if (chan)
+               {
+                       if (IS_LOCAL(user))
+                       {
+                               if ((chan->modes[CM_NOEXTERNAL]) && (!chan->HasUser(user)))
+                               {
+                                       user->WriteServ("404 %s %s :Cannot send to channel (no external messages)", user->nick, chan->name);
+                                       return CMD_FAILURE;
+                               }
+                               if ((chan->modes[CM_MODERATED]) && (chan->GetStatus(user) < STATUS_VOICE))
+                               {
+                                       user->WriteServ("404 %s %s :Cannot send to channel (+m)", user->nick, chan->name);
+                                       return CMD_FAILURE;
+                               }
+                       }
+                       int MOD_RESULT = 0;
+
+                       std::string temp = parameters[1];
+                       FOREACH_RESULT(I_OnUserPreNotice,OnUserPreNotice(user,chan,TYPE_CHANNEL,temp,status, exempt_list));
+                       if (MOD_RESULT) {
+                               return CMD_FAILURE;
+                       }
+                       parameters[1] = temp.c_str();
+
+                       if (temp.empty())
+                       {
+                               user->WriteServ("412 %s :No text to send", user->nick);
+                               return CMD_FAILURE;
+                       }
+
+                       if (status)
+                       {
+                               if (ServerInstance->Config->UndernetMsgPrefix)
+                               {
+                                       chan->WriteAllExcept(user, false, status, exempt_list, "NOTICE %c%s :%c %s", status, chan->name, status, parameters[1]);
+                               }
+                               else
+                               {
+                                       chan->WriteAllExcept(user, false, status, exempt_list, "NOTICE %c%s :%s", status, chan->name, parameters[1]);
+                               }
+                       }
+                       else
+                       {
+                               chan->WriteAllExcept(user, false, status, exempt_list, "NOTICE %s :%s", chan->name, parameters[1]);
+                       }
+
+                       FOREACH_MOD(I_OnUserNotice,OnUserNotice(user,chan,TYPE_CHANNEL,parameters[1],status,exempt_list));
+               }
+               else
+               {
+                       /* no such nick/channel */
+                       user->WriteServ("401 %s %s :No such nick/channel",user->nick, parameters[0]);
+                       return CMD_FAILURE;
+               }
+               return CMD_SUCCESS;
+       }
+       
+       dest = ServerInstance->FindNick(parameters[0]);
+       if (dest)
+       {
+               if (!*parameters[1])
+               {
+                       user->WriteServ("412 %s :No text to send", user->nick);
+                       return CMD_FAILURE;
+               }
+
+               int MOD_RESULT = 0;
+               std::string temp = parameters[1];
+               FOREACH_RESULT(I_OnUserPreNotice,OnUserPreNotice(user,dest,TYPE_USER,temp,0,exempt_list));
+               if (MOD_RESULT) {
+                       return CMD_FAILURE;
+               }
+               parameters[1] = (char*)temp.c_str();
+
+               if (IS_LOCAL(dest))
+               {
+                       // direct write, same server
+                       user->WriteTo(dest, "NOTICE %s :%s", dest->nick, parameters[1]);
+               }
+
+               FOREACH_MOD(I_OnUserNotice,OnUserNotice(user,dest,TYPE_USER,parameters[1],0,exempt_list));
+       }
+       else
+       {
+               /* no such nick/channel */
+               user->WriteServ("401 %s %s :No such nick/channel",user->nick, parameters[0]);
+               return CMD_FAILURE;
+       }
+
+       return CMD_SUCCESS;
+
+}
+
index af811115d0204c6817d041e1edd8fe77bd2aef74..686182876beda77953873396b9c7977ada21e193 100644 (file)
@@ -1 +1,153 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "configreader.h"\r#include "typedefs.h"\r#include "users.h"\r#include "modules.h"\r#include "wildcard.h"\r#include "commands/cmd_oper.h"\r#include "hashcomp.h"\r\rbool OneOfMatches(const char* host, const char* ip, const char* hostlist)\r{\r     std::stringstream hl(hostlist);\r        std::string xhost;\r     while (hl >> xhost)\r    {\r              if (match(host,xhost.c_str()) || match(ip,xhost.c_str(),true))\r         {\r                      return true;\r           }\r      }\r      return false;\r}\r\rextern "C" DllExport command_t* init_command(InspIRCd* Instance)\r{\r    return new cmd_oper(Instance);\r}\r\rCmdResult cmd_oper::Handle (const char** parameters, int pcnt, userrec *user)\r{\r      char LoginName[MAXBUF];\r        char Password[MAXBUF];\r char OperType[MAXBUF];\r char TypeName[MAXBUF];\r char HostName[MAXBUF];\r char TheHost[MAXBUF];\r  char TheIP[MAXBUF];\r    int j;\r bool found = false;\r    bool type_invalid = false;\r\r    bool match_login = false;\r      bool match_pass = false;\r       bool match_hosts = false;\r\r     snprintf(TheHost,MAXBUF,"%s@%s",user->ident,user->host);\r       snprintf(TheIP, MAXBUF,"%s@%s",user->ident,user->GetIPString());\r\r      for (int i = 0; i < ServerInstance->Config->ConfValueEnum(ServerInstance->Config->config_data, "oper"); i++)\r   {\r              ServerInstance->Config->ConfValue(ServerInstance->Config->config_data, "oper", "name", i, LoginName, MAXBUF);\r          ServerInstance->Config->ConfValue(ServerInstance->Config->config_data, "oper", "password", i, Password, MAXBUF);\r               ServerInstance->Config->ConfValue(ServerInstance->Config->config_data, "oper", "type", i, OperType, MAXBUF);\r           ServerInstance->Config->ConfValue(ServerInstance->Config->config_data, "oper", "host", i, HostName, MAXBUF);\r\r          match_login = !strcmp(LoginName,parameters[0]);\r                match_pass = !ServerInstance->OperPassCompare(Password,parameters[1], i);\r              match_hosts = OneOfMatches(TheHost,TheIP,HostName);\r\r           if (match_login && match_pass && match_hosts)\r          {\r                      type_invalid = true;\r                   for (j =0; j < ServerInstance->Config->ConfValueEnum(ServerInstance->Config->config_data, "type"); j++)\r                        {\r                              ServerInstance->Config->ConfValue(ServerInstance->Config->config_data, "type","name", j, TypeName, MAXBUF);\r\r                           if (!strcmp(TypeName,OperType))\r                                {\r                                      /* found this oper's opertype */\r                                       if (!ServerInstance->IsNick(TypeName))\r                                 {\r                                              user->WriteServ("491 %s :Invalid oper type (oper types must follow the same syntax as nicknames)",user->nick);\r                                         ServerInstance->SNO->WriteToSnoMask('o',"CONFIGURATION ERROR! Oper type '%s' contains invalid characters",OperType);\r                                           ServerInstance->Log(DEFAULT,"OPER: Failed oper attempt by %s!%s@%s: credentials valid, but oper type erroneous.",user->nick,user->ident,user->host);\r                                           return CMD_FAILURE;\r                                    }\r                                      ServerInstance->Config->ConfValue(ServerInstance->Config->config_data, "type","host", j, HostName, MAXBUF);\r                                    if (*HostName)\r                                         user->ChangeDisplayedHost(HostName);\r                                   found = true;\r                                  type_invalid = false;\r                                  break;\r                         }\r                      }\r              }\r              if (match_login || found)\r                      break;\r }\r      if (found)\r     {\r              /* correct oper credentials */\r         ServerInstance->SNO->WriteToSnoMask('o',"%s (%s@%s) is now an IRC operator of type %s (using oper '%s')",user->nick,user->ident,user->host,irc::Spacify(OperType),parameters[0]);\r              user->WriteServ("381 %s :You are now an IRC operator of type %s",user->nick,irc::Spacify(OperType));\r           if (!user->modes[UM_OPERATOR])\r                 user->Oper(OperType);\r  }\r      else\r   {\r              std::deque<std::string> n;\r             n.push_back("o");\r              char broadcast[MAXBUF];\r\r               if (!type_invalid)\r             {\r                      std::string fields;\r                    if (!match_login)\r                              fields.append("login ");\r                       if (!match_pass)\r                               fields.append("password ");\r                    if (!match_hosts)\r                              fields.append("hosts");\r                        user->WriteServ("491 %s :Invalid oper credentials",user->nick);\r                        \r                       snprintf(broadcast, MAXBUF, "WARNING! Failed oper attempt by %s!%s@%s using login '%s': The following fields do not match: %s",user->nick,user->ident,user->host, parameters[0], fields.c_str());\r                      ServerInstance->SNO->WriteToSnoMask('o',std::string(broadcast));\r                       n.push_back(broadcast);\r                        Event rmode2((char *)&n, NULL, "send_snoset");\r                 rmode2.Send(ServerInstance);\r\r                  ServerInstance->Log(DEFAULT,"OPER: Failed oper attempt by %s!%s@%s using login '%s': The following fields did not match: %s",user->nick,user->ident,user->host,parameters[0],fields.c_str());\r                  return CMD_FAILURE;\r            }\r              else\r           {\r                      user->WriteServ("491 %s :Your oper block does not have a valid opertype associated with it",user->nick);\r\r                      snprintf(broadcast, MAXBUF, "CONFIGURATION ERROR! Oper block '%s': missing OperType %s",parameters[0],OperType);\r\r                      ServerInstance->SNO->WriteToSnoMask('o', std::string(broadcast));\r                      n.push_back(broadcast);\r                        Event rmode2((char *)&n, NULL, "send_snoset");\r                 rmode2.Send(ServerInstance);\r\r                  ServerInstance->Log(DEFAULT,"OPER: Failed oper attempt by %s!%s@%s using login '%s': credentials valid, but oper type nonexistent.",user->nick,user->ident,user->host,parameters[0]);\r                  return CMD_FAILURE;\r            }\r      }\r      return CMD_SUCCESS;\r}\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "configreader.h"
+#include "typedefs.h"
+#include "users.h"
+#include "modules.h"
+#include "wildcard.h"
+#include "commands/cmd_oper.h"
+#include "hashcomp.h"
+
+bool OneOfMatches(const char* host, const char* ip, const char* hostlist)
+{
+       std::stringstream hl(hostlist);
+       std::string xhost;
+       while (hl >> xhost)
+       {
+               if (match(host,xhost.c_str()) || match(ip,xhost.c_str(),true))
+               {
+                       return true;
+               }
+       }
+       return false;
+}
+
+extern "C" DllExport command_t* init_command(InspIRCd* Instance)
+{
+       return new cmd_oper(Instance);
+}
+
+CmdResult cmd_oper::Handle (const char** parameters, int pcnt, userrec *user)
+{
+       char LoginName[MAXBUF];
+       char Password[MAXBUF];
+       char OperType[MAXBUF];
+       char TypeName[MAXBUF];
+       char HostName[MAXBUF];
+       char TheHost[MAXBUF];
+       char TheIP[MAXBUF];
+       int j;
+       bool found = false;
+       bool type_invalid = false;
+
+       bool match_login = false;
+       bool match_pass = false;
+       bool match_hosts = false;
+
+       snprintf(TheHost,MAXBUF,"%s@%s",user->ident,user->host);
+       snprintf(TheIP, MAXBUF,"%s@%s",user->ident,user->GetIPString());
+
+       for (int i = 0; i < ServerInstance->Config->ConfValueEnum(ServerInstance->Config->config_data, "oper"); i++)
+       {
+               ServerInstance->Config->ConfValue(ServerInstance->Config->config_data, "oper", "name", i, LoginName, MAXBUF);
+               ServerInstance->Config->ConfValue(ServerInstance->Config->config_data, "oper", "password", i, Password, MAXBUF);
+               ServerInstance->Config->ConfValue(ServerInstance->Config->config_data, "oper", "type", i, OperType, MAXBUF);
+               ServerInstance->Config->ConfValue(ServerInstance->Config->config_data, "oper", "host", i, HostName, MAXBUF);
+
+               match_login = !strcmp(LoginName,parameters[0]);
+               match_pass = !ServerInstance->OperPassCompare(Password,parameters[1], i);
+               match_hosts = OneOfMatches(TheHost,TheIP,HostName);
+
+               if (match_login && match_pass && match_hosts)
+               {
+                       type_invalid = true;
+                       for (j =0; j < ServerInstance->Config->ConfValueEnum(ServerInstance->Config->config_data, "type"); j++)
+                       {
+                               ServerInstance->Config->ConfValue(ServerInstance->Config->config_data, "type","name", j, TypeName, MAXBUF);
+
+                               if (!strcmp(TypeName,OperType))
+                               {
+                                       /* found this oper's opertype */
+                                       if (!ServerInstance->IsNick(TypeName))
+                                       {
+                                               user->WriteServ("491 %s :Invalid oper type (oper types must follow the same syntax as nicknames)",user->nick);
+                                               ServerInstance->SNO->WriteToSnoMask('o',"CONFIGURATION ERROR! Oper type '%s' contains invalid characters",OperType);
+                                               ServerInstance->Log(DEFAULT,"OPER: Failed oper attempt by %s!%s@%s: credentials valid, but oper type erroneous.",user->nick,user->ident,user->host);
+                                               return CMD_FAILURE;
+                                       }
+                                       ServerInstance->Config->ConfValue(ServerInstance->Config->config_data, "type","host", j, HostName, MAXBUF);
+                                       if (*HostName)
+                                               user->ChangeDisplayedHost(HostName);
+                                       found = true;
+                                       type_invalid = false;
+                                       break;
+                               }
+                       }
+               }
+               if (match_login || found)
+                       break;
+       }
+       if (found)
+       {
+               /* correct oper credentials */
+               ServerInstance->SNO->WriteToSnoMask('o',"%s (%s@%s) is now an IRC operator of type %s (using oper '%s')",user->nick,user->ident,user->host,irc::Spacify(OperType),parameters[0]);
+               user->WriteServ("381 %s :You are now an IRC operator of type %s",user->nick,irc::Spacify(OperType));
+               if (!user->modes[UM_OPERATOR])
+                       user->Oper(OperType);
+       }
+       else
+       {
+               std::deque<std::string> n;
+               n.push_back("o");
+               char broadcast[MAXBUF];
+
+               if (!type_invalid)
+               {
+                       std::string fields;
+                       if (!match_login)
+                               fields.append("login ");
+                       if (!match_pass)
+                               fields.append("password ");
+                       if (!match_hosts)
+                               fields.append("hosts");
+                       user->WriteServ("491 %s :Invalid oper credentials",user->nick);
+                       
+                       snprintf(broadcast, MAXBUF, "WARNING! Failed oper attempt by %s!%s@%s using login '%s': The following fields do not match: %s",user->nick,user->ident,user->host, parameters[0], fields.c_str());
+                       ServerInstance->SNO->WriteToSnoMask('o',std::string(broadcast));
+                       n.push_back(broadcast);
+                       Event rmode2((char *)&n, NULL, "send_snoset");
+                       rmode2.Send(ServerInstance);
+
+                       ServerInstance->Log(DEFAULT,"OPER: Failed oper attempt by %s!%s@%s using login '%s': The following fields did not match: %s",user->nick,user->ident,user->host,parameters[0],fields.c_str());
+                       return CMD_FAILURE;
+               }
+               else
+               {
+                       user->WriteServ("491 %s :Your oper block does not have a valid opertype associated with it",user->nick);
+
+                       snprintf(broadcast, MAXBUF, "CONFIGURATION ERROR! Oper block '%s': missing OperType %s",parameters[0],OperType);
+
+                       ServerInstance->SNO->WriteToSnoMask('o', std::string(broadcast));
+                       n.push_back(broadcast);
+                       Event rmode2((char *)&n, NULL, "send_snoset");
+                       rmode2.Send(ServerInstance);
+
+                       ServerInstance->Log(DEFAULT,"OPER: Failed oper attempt by %s!%s@%s using login '%s': credentials valid, but oper type nonexistent.",user->nick,user->ident,user->host,parameters[0]);
+                       return CMD_FAILURE;
+               }
+       }
+       return CMD_SUCCESS;
+}
+
index 3bf22ac5d3d8725ac43951a0f1cacbd7d9ff94c0..347466c22375dda74d6850c615bd4d2b7f299a27 100644 (file)
@@ -1 +1,43 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "commands/cmd_part.h"\r\rextern "C" DllExport command_t* init_command(InspIRCd* Instance)\r{\r       return new cmd_part(Instance);\r}\r\rCmdResult cmd_part::Handle (const char** parameters, int pcnt, userrec *user)\r{\r      if (ServerInstance->Parser->LoopCall(user, this, parameters, pcnt, 0))\r         return CMD_SUCCESS;\r\r   chanrec* c = ServerInstance->FindChan(parameters[0]);\r  \r       if (c)\r {\r              if (!c->PartUser(user, pcnt > 1 ? parameters[1] : NULL))\r                       /* Arse, who stole our channel! :/ */\r                  delete c;\r      }\r      else\r   {\r              user->WriteServ( "401 %s %s :No such channel", user->nick, parameters[0]);\r             return CMD_FAILURE;\r    }\r\r     return CMD_SUCCESS;\r}\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "commands/cmd_part.h"
+
+extern "C" DllExport command_t* init_command(InspIRCd* Instance)
+{
+       return new cmd_part(Instance);
+}
+
+CmdResult cmd_part::Handle (const char** parameters, int pcnt, userrec *user)
+{
+       if (ServerInstance->Parser->LoopCall(user, this, parameters, pcnt, 0))
+               return CMD_SUCCESS;
+
+       chanrec* c = ServerInstance->FindChan(parameters[0]);
+       
+       if (c)
+       {
+               if (!c->PartUser(user, pcnt > 1 ? parameters[1] : NULL))
+                       /* Arse, who stole our channel! :/ */
+                       delete c;
+       }
+       else
+       {
+               user->WriteServ( "401 %s %s :No such channel", user->nick, parameters[0]);
+               return CMD_FAILURE;
+       }
+
+       return CMD_SUCCESS;
+}
index 0a836ccdfbf731a557fd29b9affdc432819ce1d0..29c83c3bf9c7fce8dc84450e5fdd5e69860cec8e 100644 (file)
@@ -1 +1,42 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "commands/cmd_pass.h"\r\rextern "C" DllExport command_t* init_command(InspIRCd* Instance)\r{\r       return new cmd_pass(Instance);\r}\r\rCmdResult cmd_pass::Handle (const char** parameters, int pcnt, userrec *user)\r{\r      // Check to make sure they havnt registered -- Fix by FCS\r      if (user->registered == REG_ALL)\r       {\r              user->WriteServ("462 %s :You may not reregister",user->nick);\r          return CMD_FAILURE;\r    }\r      ConnectClass* a = user->GetClass();\r    if (!a)\r                return CMD_FAILURE;\r\r   strlcpy(user->password,parameters[0],63);\r      if (a->GetPass() == parameters[0])\r     {\r              user->haspassed = true;\r        }\r\r     return CMD_SUCCESS;\r}\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "commands/cmd_pass.h"
+
+extern "C" DllExport command_t* init_command(InspIRCd* Instance)
+{
+       return new cmd_pass(Instance);
+}
+
+CmdResult cmd_pass::Handle (const char** parameters, int pcnt, userrec *user)
+{
+       // Check to make sure they havnt registered -- Fix by FCS
+       if (user->registered == REG_ALL)
+       {
+               user->WriteServ("462 %s :You may not reregister",user->nick);
+               return CMD_FAILURE;
+       }
+       ConnectClass* a = user->GetClass();
+       if (!a)
+               return CMD_FAILURE;
+
+       strlcpy(user->password,parameters[0],63);
+       if (a->GetPass() == parameters[0])
+       {
+               user->haspassed = true;
+       }
+
+       return CMD_SUCCESS;
+}
index c36415d128558d508d46da621e779f3a7782bea6..afb708d7097f4937dbe55359496086fd5e10371e 100644 (file)
@@ -1 +1,28 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "configreader.h"\r#include "users.h"\r#include "commands/cmd_ping.h"\r\rextern "C" DllExport command_t* init_command(InspIRCd* Instance)\r{\r     return new cmd_ping(Instance);\r}\r\rCmdResult cmd_ping::Handle (const char** parameters, int pcnt, userrec *user)\r{\r      user->WriteServ("PONG %s :%s",ServerInstance->Config->ServerName,parameters[0]);\r       return CMD_SUCCESS;\r}\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "configreader.h"
+#include "users.h"
+#include "commands/cmd_ping.h"
+
+extern "C" DllExport command_t* init_command(InspIRCd* Instance)
+{
+       return new cmd_ping(Instance);
+}
+
+CmdResult cmd_ping::Handle (const char** parameters, int pcnt, userrec *user)
+{
+       user->WriteServ("PONG %s :%s",ServerInstance->Config->ServerName,parameters[0]);
+       return CMD_SUCCESS;
+}
index 16b42355bfa285b470ae261d8894d25d73cc0a0d..c89542240f15ca9905ecd1db4c55a96a6189e130 100644 (file)
@@ -1 +1,28 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "commands/cmd_pong.h"\r\rextern "C" DllExport command_t* init_command(InspIRCd* Instance)\r{\r       return new cmd_pong(Instance);\r}\r\rCmdResult cmd_pong::Handle (const char** parameters, int pcnt, userrec *user)\r{\r      // set the user as alive so they survive to next ping\r  user->lastping = 1;\r    return CMD_SUCCESS;\r}\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "commands/cmd_pong.h"
+
+extern "C" DllExport command_t* init_command(InspIRCd* Instance)
+{
+       return new cmd_pong(Instance);
+}
+
+CmdResult cmd_pong::Handle (const char** parameters, int pcnt, userrec *user)
+{
+       // set the user as alive so they survive to next ping
+       user->lastping = 1;
+       return CMD_SUCCESS;
+}
index 3fdc12090c055d97abb42e86b1450d8601651cca..f3295df07e88f30d55a4d252bce3d8fb0d668b26 100644 (file)
@@ -1 +1,164 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "configreader.h"\r#include "users.h"\r#include "modules.h"\r#include "wildcard.h"\r#include "commands/cmd_privmsg.h"\r\rextern "C" DllExport  command_t* init_command(InspIRCd* Instance)\r{\r      return new cmd_privmsg(Instance);\r}\r\rCmdResult cmd_privmsg::Handle (const char** parameters, int pcnt, userrec *user)\r{\r        userrec *dest;\r chanrec *chan;\r CUList except_list;\r\r   user->idle_lastmsg = ServerInstance->Time();\r   \r       if (ServerInstance->Parser->LoopCall(user, this, parameters, pcnt, 0))\r         return CMD_SUCCESS;\r\r   if ((parameters[0][0] == '$') && (IS_OPER(user) || ServerInstance->ULine(user->server)))\r       {\r              int MOD_RESULT = 0;\r            std::string temp = parameters[1];\r              FOREACH_RESULT(I_OnUserPreMessage,OnUserPreMessage(user,(void*)parameters[0],TYPE_SERVER,temp,0,except_list));\r         if (MOD_RESULT)\r                        return CMD_FAILURE;\r            parameters[1] = temp.c_str();\r          // notice to server mask\r               const char* servermask = parameters[0] + 1;\r            if (match(ServerInstance->Config->ServerName,servermask))\r              {\r                      user->SendAll("PRIVMSG", "%s", parameters[1]);\r         }\r              FOREACH_MOD(I_OnUserMessage,OnUserMessage(user,(void*)parameters[0],TYPE_SERVER,parameters[1],0,except_list));\r         return CMD_SUCCESS;\r    }\r      char status = 0;\r       if ((*parameters[0] == '@') || (*parameters[0] == '%') || (*parameters[0] == '+'))\r     {\r              status = *parameters[0];\r               parameters[0]++;\r       }\r      if (parameters[0][0] == '#')\r   {\r              chan = ServerInstance->FindChan(parameters[0]);\r\r               except_list[user] = user->nick;\r\r               if (chan)\r              {\r                      if (IS_LOCAL(user))\r                    {\r                              if ((chan->modes[CM_NOEXTERNAL]) && (!chan->HasUser(user)))\r                            {\r                                      user->WriteServ("404 %s %s :Cannot send to channel (no external messages)", user->nick, chan->name);\r                                   return CMD_FAILURE;\r                            }\r                              if ((chan->modes[CM_MODERATED]) && (chan->GetStatus(user) < STATUS_VOICE))\r                             {\r                                      user->WriteServ("404 %s %s :Cannot send to channel (+m)", user->nick, chan->name);\r                                     return CMD_FAILURE;\r                            }\r                      }\r                      int MOD_RESULT = 0;\r\r                   std::string temp = parameters[1];\r                      FOREACH_RESULT(I_OnUserPreMessage,OnUserPreMessage(user,chan,TYPE_CHANNEL,temp,status,except_list));\r                   if (MOD_RESULT) {\r                              return CMD_FAILURE;\r                    }\r                      parameters[1] = temp.c_str();\r\r                 /* Check again, a module may have zapped the input string */\r                   if (temp.empty())\r                      {\r                              user->WriteServ("412 %s :No text to send", user->nick);\r                                return CMD_FAILURE;\r                    }\r\r                     if (status)\r                    {\r                              if (ServerInstance->Config->UndernetMsgPrefix)\r                         {\r                                      chan->WriteAllExcept(user, false, status, except_list, "PRIVMSG %c%s :%c %s", status, chan->name, status, parameters[1]);\r                              }\r                              else\r                           {\r                                      chan->WriteAllExcept(user, false, status, except_list, "PRIVMSG %c%s :%s", status, chan->name, parameters[1]);\r                         }\r                      }\r                      else \r                  {\r                              chan->WriteAllExcept(user, false, status, except_list, "PRIVMSG %s :%s", chan->name, parameters[1]);\r                   }\r\r                     FOREACH_MOD(I_OnUserMessage,OnUserMessage(user,chan,TYPE_CHANNEL,parameters[1],status,except_list));\r           }\r              else\r           {\r                      /* no such nick/channel */\r                     user->WriteServ("401 %s %s :No such nick/channel",user->nick, parameters[0]);\r                  return CMD_FAILURE;\r            }\r              return CMD_SUCCESS;\r    }\r\r     dest = ServerInstance->FindNick(parameters[0]);\r        if (dest)\r      {\r              if (!*parameters[1])\r           {\r                      user->WriteServ("412 %s :No text to send", user->nick);\r                        return CMD_FAILURE;\r            }\r\r             if (IS_AWAY(dest))\r             {\r                      /* auto respond with aweh msg */\r                       user->WriteServ("301 %s %s :%s",user->nick,dest->nick,dest->awaymsg);\r          }\r\r             int MOD_RESULT = 0;\r            \r               std::string temp = parameters[1];\r              FOREACH_RESULT(I_OnUserPreMessage,OnUserPreMessage(user,dest,TYPE_USER,temp,0,except_list));\r           if (MOD_RESULT) {\r                      return CMD_FAILURE;\r            }\r              parameters[1] = (char*)temp.c_str();\r\r          if (IS_LOCAL(dest))\r            {\r                      // direct write, same server\r                   user->WriteTo(dest, "PRIVMSG %s :%s", dest->nick, parameters[1]);\r              }\r\r             FOREACH_MOD(I_OnUserMessage,OnUserMessage(user,dest,TYPE_USER,parameters[1],0,except_list));\r   }\r      else\r   {\r              /* no such nick/channel */\r             user->WriteServ("401 %s %s :No such nick/channel",user->nick, parameters[0]);\r          return CMD_FAILURE;\r    }\r      return CMD_SUCCESS;\r}\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "configreader.h"
+#include "users.h"
+#include "modules.h"
+#include "wildcard.h"
+#include "commands/cmd_privmsg.h"
+
+extern "C" DllExport  command_t* init_command(InspIRCd* Instance)
+{
+       return new cmd_privmsg(Instance);
+}
+
+CmdResult cmd_privmsg::Handle (const char** parameters, int pcnt, userrec *user)
+{
+       userrec *dest;
+       chanrec *chan;
+       CUList except_list;
+
+       user->idle_lastmsg = ServerInstance->Time();
+       
+       if (ServerInstance->Parser->LoopCall(user, this, parameters, pcnt, 0))
+               return CMD_SUCCESS;
+
+       if ((parameters[0][0] == '$') && (IS_OPER(user) || ServerInstance->ULine(user->server)))
+       {
+               int MOD_RESULT = 0;
+               std::string temp = parameters[1];
+               FOREACH_RESULT(I_OnUserPreMessage,OnUserPreMessage(user,(void*)parameters[0],TYPE_SERVER,temp,0,except_list));
+               if (MOD_RESULT)
+                       return CMD_FAILURE;
+               parameters[1] = temp.c_str();
+               // notice to server mask
+               const char* servermask = parameters[0] + 1;
+               if (match(ServerInstance->Config->ServerName,servermask))
+               {
+                       user->SendAll("PRIVMSG", "%s", parameters[1]);
+               }
+               FOREACH_MOD(I_OnUserMessage,OnUserMessage(user,(void*)parameters[0],TYPE_SERVER,parameters[1],0,except_list));
+               return CMD_SUCCESS;
+       }
+       char status = 0;
+       if ((*parameters[0] == '@') || (*parameters[0] == '%') || (*parameters[0] == '+'))
+       {
+               status = *parameters[0];
+               parameters[0]++;
+       }
+       if (parameters[0][0] == '#')
+       {
+               chan = ServerInstance->FindChan(parameters[0]);
+
+               except_list[user] = user->nick;
+
+               if (chan)
+               {
+                       if (IS_LOCAL(user))
+                       {
+                               if ((chan->modes[CM_NOEXTERNAL]) && (!chan->HasUser(user)))
+                               {
+                                       user->WriteServ("404 %s %s :Cannot send to channel (no external messages)", user->nick, chan->name);
+                                       return CMD_FAILURE;
+                               }
+                               if ((chan->modes[CM_MODERATED]) && (chan->GetStatus(user) < STATUS_VOICE))
+                               {
+                                       user->WriteServ("404 %s %s :Cannot send to channel (+m)", user->nick, chan->name);
+                                       return CMD_FAILURE;
+                               }
+                       }
+                       int MOD_RESULT = 0;
+
+                       std::string temp = parameters[1];
+                       FOREACH_RESULT(I_OnUserPreMessage,OnUserPreMessage(user,chan,TYPE_CHANNEL,temp,status,except_list));
+                       if (MOD_RESULT) {
+                               return CMD_FAILURE;
+                       }
+                       parameters[1] = temp.c_str();
+
+                       /* Check again, a module may have zapped the input string */
+                       if (temp.empty())
+                       {
+                               user->WriteServ("412 %s :No text to send", user->nick);
+                               return CMD_FAILURE;
+                       }
+
+                       if (status)
+                       {
+                               if (ServerInstance->Config->UndernetMsgPrefix)
+                               {
+                                       chan->WriteAllExcept(user, false, status, except_list, "PRIVMSG %c%s :%c %s", status, chan->name, status, parameters[1]);
+                               }
+                               else
+                               {
+                                       chan->WriteAllExcept(user, false, status, except_list, "PRIVMSG %c%s :%s", status, chan->name, parameters[1]);
+                               }
+                       }
+                       else 
+                       {
+                               chan->WriteAllExcept(user, false, status, except_list, "PRIVMSG %s :%s", chan->name, parameters[1]);
+                       }
+
+                       FOREACH_MOD(I_OnUserMessage,OnUserMessage(user,chan,TYPE_CHANNEL,parameters[1],status,except_list));
+               }
+               else
+               {
+                       /* no such nick/channel */
+                       user->WriteServ("401 %s %s :No such nick/channel",user->nick, parameters[0]);
+                       return CMD_FAILURE;
+               }
+               return CMD_SUCCESS;
+       }
+
+       dest = ServerInstance->FindNick(parameters[0]);
+       if (dest)
+       {
+               if (!*parameters[1])
+               {
+                       user->WriteServ("412 %s :No text to send", user->nick);
+                       return CMD_FAILURE;
+               }
+
+               if (IS_AWAY(dest))
+               {
+                       /* auto respond with aweh msg */
+                       user->WriteServ("301 %s %s :%s",user->nick,dest->nick,dest->awaymsg);
+               }
+
+               int MOD_RESULT = 0;
+               
+               std::string temp = parameters[1];
+               FOREACH_RESULT(I_OnUserPreMessage,OnUserPreMessage(user,dest,TYPE_USER,temp,0,except_list));
+               if (MOD_RESULT) {
+                       return CMD_FAILURE;
+               }
+               parameters[1] = (char*)temp.c_str();
+
+               if (IS_LOCAL(dest))
+               {
+                       // direct write, same server
+                       user->WriteTo(dest, "PRIVMSG %s :%s", dest->nick, parameters[1]);
+               }
+
+               FOREACH_MOD(I_OnUserMessage,OnUserMessage(user,dest,TYPE_USER,parameters[1],0,except_list));
+       }
+       else
+       {
+               /* no such nick/channel */
+               user->WriteServ("401 %s %s :No such nick/channel",user->nick, parameters[0]);
+               return CMD_FAILURE;
+       }
+       return CMD_SUCCESS;
+}
+
index 892f6480cdc51bef061322625f3ff34260621326..bb112285439eacb5335f13e6591e0946cd596e5d 100644 (file)
@@ -1 +1,80 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "configreader.h"\r#include "users.h"\r#include "modules.h"\r#include "xline.h"\r#include "commands/cmd_qline.h"\r\r\r\rextern "C" DllExport command_t* init_command(InspIRCd* Instance)\r{\r  return new cmd_qline(Instance);\r}\r\rCmdResult cmd_qline::Handle (const char** parameters, int pcnt, userrec *user)\r{\r    if (pcnt >= 3)\r {\r              if (ServerInstance->NickMatchesEveryone(parameters[0],user))\r                   return CMD_FAILURE;\r\r           if (strchr(parameters[0],'@') || strchr(parameters[0],'!') || strchr(parameters[0],'.'))\r               {\r                      user->WriteServ("NOTICE %s :*** A Q-Line only bans a nick pattern, not a nick!user@host pattern.",user->nick);\r                 return CMD_FAILURE;\r            }\r\r             long duration = ServerInstance->Duration(parameters[1]);\r               if (ServerInstance->XLines->add_qline(duration,user->nick,parameters[2],parameters[0]))\r                {\r                      int to_apply = APPLY_QLINES;\r                   FOREACH_MOD(I_OnAddQLine,OnAddQLine(duration, user, parameters[2], parameters[0]));\r                    if (!duration)\r                 {\r                              to_apply |= APPLY_PERM_ONLY;\r                           ServerInstance->SNO->WriteToSnoMask('x',"%s added permanent Q-line for %s.",user->nick,parameters[0]);\r                 }\r                      else\r                   {\r                              time_t c_requires_crap = duration + ServerInstance->Time();\r                            ServerInstance->SNO->WriteToSnoMask('x',"%s added timed Q-line for %s, expires on %s",user->nick,parameters[0],\r                                          ServerInstance->TimeString(c_requires_crap).c_str());\r                        }\r                      ServerInstance->XLines->apply_lines(to_apply);\r         }\r              else\r           {\r                      user->WriteServ("NOTICE %s :*** Q-Line for %s already exists",user->nick,parameters[0]);\r               }\r      }\r      else\r   {\r              if (ServerInstance->XLines->del_qline(parameters[0]))\r          {\r                      FOREACH_MOD(I_OnDelQLine,OnDelQLine(user, parameters[0]));\r                     ServerInstance->SNO->WriteToSnoMask('x',"%s Removed Q-line on %s.",user->nick,parameters[0]);\r          }\r              else\r           {\r                      user->WriteServ("NOTICE %s :*** Q-Line %s not found in list, try /stats q.",user->nick,parameters[0]);\r                 return CMD_FAILURE;\r            }\r      }\r\r     return CMD_SUCCESS;\r}\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "configreader.h"
+#include "users.h"
+#include "modules.h"
+#include "xline.h"
+#include "commands/cmd_qline.h"
+
+
+
+extern "C" DllExport command_t* init_command(InspIRCd* Instance)
+{
+       return new cmd_qline(Instance);
+}
+
+CmdResult cmd_qline::Handle (const char** parameters, int pcnt, userrec *user)
+{
+       if (pcnt >= 3)
+       {
+               if (ServerInstance->NickMatchesEveryone(parameters[0],user))
+                       return CMD_FAILURE;
+
+               if (strchr(parameters[0],'@') || strchr(parameters[0],'!') || strchr(parameters[0],'.'))
+               {
+                       user->WriteServ("NOTICE %s :*** A Q-Line only bans a nick pattern, not a nick!user@host pattern.",user->nick);
+                       return CMD_FAILURE;
+               }
+
+               long duration = ServerInstance->Duration(parameters[1]);
+               if (ServerInstance->XLines->add_qline(duration,user->nick,parameters[2],parameters[0]))
+               {
+                       int to_apply = APPLY_QLINES;
+                       FOREACH_MOD(I_OnAddQLine,OnAddQLine(duration, user, parameters[2], parameters[0]));
+                       if (!duration)
+                       {
+                               to_apply |= APPLY_PERM_ONLY;
+                               ServerInstance->SNO->WriteToSnoMask('x',"%s added permanent Q-line for %s.",user->nick,parameters[0]);
+                       }
+                       else
+                       {
+                               time_t c_requires_crap = duration + ServerInstance->Time();
+                               ServerInstance->SNO->WriteToSnoMask('x',"%s added timed Q-line for %s, expires on %s",user->nick,parameters[0],
+                                         ServerInstance->TimeString(c_requires_crap).c_str());
+                       }
+                       ServerInstance->XLines->apply_lines(to_apply);
+               }
+               else
+               {
+                       user->WriteServ("NOTICE %s :*** Q-Line for %s already exists",user->nick,parameters[0]);
+               }
+       }
+       else
+       {
+               if (ServerInstance->XLines->del_qline(parameters[0]))
+               {
+                       FOREACH_MOD(I_OnDelQLine,OnDelQLine(user, parameters[0]));
+                       ServerInstance->SNO->WriteToSnoMask('x',"%s Removed Q-line on %s.",user->nick,parameters[0]);
+               }
+               else
+               {
+                       user->WriteServ("NOTICE %s :*** Q-Line %s not found in list, try /stats q.",user->nick,parameters[0]);
+                       return CMD_FAILURE;
+               }
+       }
+
+       return CMD_SUCCESS;
+}
+
index 45e970207f49d6bc2ed2241375ab18a72d8be253..a859c179017d6b0b4e8ecfd98ad9f66b7624ab2b 100644 (file)
@@ -1 +1,48 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "configreader.h"\r#include "users.h"\r#include "modules.h"\r#include "commands/cmd_quit.h"\r\r\r\rextern "C" DllExport command_t* init_command(InspIRCd* Instance)\r{\r      return new cmd_quit(Instance);\r}\r\rCmdResult cmd_quit::Handle (const char** parameters, int pcnt, userrec *user)\r{\r\r     std::string quitmsg;\r\r  if (IS_LOCAL(user))\r    {\r              if (*ServerInstance->Config->FixedQuit)\r                        quitmsg = ServerInstance->Config->FixedQuit;\r           else\r                   quitmsg = pcnt ?\r                               ServerInstance->Config->PrefixQuit + std::string(parameters[0]) + ServerInstance->Config->SuffixQuit\r                           : "Client exited";\r     }\r      else\r           quitmsg = pcnt ? parameters[0] : "Client exited";\r\r     userrec::QuitUser(ServerInstance, user, quitmsg);\r\r     return CMD_SUCCESS;\r}\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "configreader.h"
+#include "users.h"
+#include "modules.h"
+#include "commands/cmd_quit.h"
+
+
+
+extern "C" DllExport command_t* init_command(InspIRCd* Instance)
+{
+       return new cmd_quit(Instance);
+}
+
+CmdResult cmd_quit::Handle (const char** parameters, int pcnt, userrec *user)
+{
+
+       std::string quitmsg;
+
+       if (IS_LOCAL(user))
+       {
+               if (*ServerInstance->Config->FixedQuit)
+                       quitmsg = ServerInstance->Config->FixedQuit;
+               else
+                       quitmsg = pcnt ?
+                               ServerInstance->Config->PrefixQuit + std::string(parameters[0]) + ServerInstance->Config->SuffixQuit
+                               : "Client exited";
+       }
+       else
+               quitmsg = pcnt ? parameters[0] : "Client exited";
+
+       userrec::QuitUser(ServerInstance, user, quitmsg);
+
+       return CMD_SUCCESS;
+}
+
index c8415f313df5f3cecb6efc46d5d17b4a36fea30e..34789b0eaca8f0d6b46a8b4771f122d125830650 100644 (file)
@@ -1 +1,56 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "configreader.h"\r#include "users.h"\r#include "modules.h"\r#include "commands/cmd_rehash.h"\r\r\r\rextern "C" DllExport command_t* init_command(InspIRCd* Instance)\r{\r    return new cmd_rehash(Instance);\r}\r\rCmdResult cmd_rehash::Handle (const char** parameters, int pcnt, userrec *user)\r{\r  user->WriteServ("382 %s %s :Rehashing",user->nick,ServerConfig::CleanFilename(ServerInstance->ConfigFileName));\r        std::string parameter;\r std::string old_disabled = ServerInstance->Config->DisabledCommands;\r   if (pcnt)\r      {\r              parameter = parameters[0];\r     }\r      else\r   {\r              ServerInstance->WriteOpers("*** %s is rehashing config file %s",user->nick,ServerConfig::CleanFilename(ServerInstance->ConfigFileName));\r               ServerInstance->CloseLog();\r            ServerInstance->OpenLog(ServerInstance->Config->argv, ServerInstance->Config->argc);\r           ServerInstance->RehashUsersAndChans();\r         FOREACH_MOD(I_OnGarbageCollect, OnGarbageCollect());\r           ServerInstance->Config->Read(false,user);\r              ServerInstance->Res->Rehash();\r         ServerInstance->ResetMaxBans();\r        }\r      if (old_disabled != ServerInstance->Config->DisabledCommands)\r          InitializeDisabledCommands(ServerInstance->Config->DisabledCommands, ServerInstance);\r\r FOREACH_MOD(I_OnRehash,OnRehash(user, parameter));\r\r    ServerInstance->BuildISupport();\r\r      return CMD_SUCCESS;\r}\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "configreader.h"
+#include "users.h"
+#include "modules.h"
+#include "commands/cmd_rehash.h"
+
+
+
+extern "C" DllExport command_t* init_command(InspIRCd* Instance)
+{
+       return new cmd_rehash(Instance);
+}
+
+CmdResult cmd_rehash::Handle (const char** parameters, int pcnt, userrec *user)
+{
+       user->WriteServ("382 %s %s :Rehashing",user->nick,ServerConfig::CleanFilename(ServerInstance->ConfigFileName));
+       std::string parameter;
+       std::string old_disabled = ServerInstance->Config->DisabledCommands;
+       if (pcnt)
+       {
+               parameter = parameters[0];
+       }
+       else
+       {
+               ServerInstance->WriteOpers("*** %s is rehashing config file %s",user->nick,ServerConfig::CleanFilename(ServerInstance->ConfigFileName));
+               ServerInstance->CloseLog();
+               ServerInstance->OpenLog(ServerInstance->Config->argv, ServerInstance->Config->argc);
+               ServerInstance->RehashUsersAndChans();
+               FOREACH_MOD(I_OnGarbageCollect, OnGarbageCollect());
+               ServerInstance->Config->Read(false,user);
+               ServerInstance->Res->Rehash();
+               ServerInstance->ResetMaxBans();
+       }
+       if (old_disabled != ServerInstance->Config->DisabledCommands)
+               InitializeDisabledCommands(ServerInstance->Config->DisabledCommands, ServerInstance);
+
+       FOREACH_MOD(I_OnRehash,OnRehash(user, parameter));
+
+       ServerInstance->BuildISupport();
+
+       return CMD_SUCCESS;
+}
+
index 0eb6f1ec452f20bbe05c8a9021aad418b46ea26d..41da0c40d9b95aca82af4f461b50fdc5c42d70d0 100644 (file)
@@ -1 +1,39 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "commands/cmd_reloadmodule.h"\r\rextern "C" DllExport command_t* init_command(InspIRCd* Instance)\r{\r       return new cmd_reloadmodule(Instance);\r}\r\rCmdResult cmd_reloadmodule::Handle (const char** parameters, int pcnt, userrec *user)\r{\r      if (ServerInstance->UnloadModule(parameters[0]))\r       {\r              ServerInstance->WriteOpers("*** RELOAD MODULE: %s unloaded %s",user->nick, parameters[0]);\r             if (ServerInstance->LoadModule(parameters[0]))\r         {\r                      ServerInstance->WriteOpers("*** RELOAD MODULE: %s reloaded %s",user->nick, parameters[0]);\r                     user->WriteServ("975 %s %s :Module successfully reloaded.",user->nick, parameters[0]);\r                 return CMD_SUCCESS;\r            }\r      }\r      \r       ServerInstance->WriteOpers("*** RELOAD MODULE: %s unsuccessfully reloaded %s",user->nick, parameters[0]);\r      user->WriteServ("975 %s %s :Module failed to reload.",user->nick, parameters[0]);\r      return CMD_FAILURE;\r}\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "commands/cmd_reloadmodule.h"
+
+extern "C" DllExport command_t* init_command(InspIRCd* Instance)
+{
+       return new cmd_reloadmodule(Instance);
+}
+
+CmdResult cmd_reloadmodule::Handle (const char** parameters, int pcnt, userrec *user)
+{
+       if (ServerInstance->UnloadModule(parameters[0]))
+       {
+               ServerInstance->WriteOpers("*** RELOAD MODULE: %s unloaded %s",user->nick, parameters[0]);
+               if (ServerInstance->LoadModule(parameters[0]))
+               {
+                       ServerInstance->WriteOpers("*** RELOAD MODULE: %s reloaded %s",user->nick, parameters[0]);
+                       user->WriteServ("975 %s %s :Module successfully reloaded.",user->nick, parameters[0]);
+                       return CMD_SUCCESS;
+               }
+       }
+       
+       ServerInstance->WriteOpers("*** RELOAD MODULE: %s unsuccessfully reloaded %s",user->nick, parameters[0]);
+       user->WriteServ("975 %s %s :Module failed to reload.",user->nick, parameters[0]);
+       return CMD_FAILURE;
+}
index 1dbf5b121258fd821408d19aa3f89ca50f3f29b3..c910df8bab94c4eab2965ce4921b75b8f2b8c7a1 100644 (file)
@@ -1 +1,49 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "configreader.h"\r#include "users.h"\r#include "commands/cmd_restart.h"\r\rextern "C" DllExport command_t* init_command(InspIRCd* Instance)\r{\r  return new cmd_restart(Instance);\r}\r\rCmdResult cmd_restart::Handle (const char** parameters, int pcnt, userrec *user)\r{\r        ServerInstance->Log(DEFAULT,"Restart: %s",user->nick);\r if (!strcmp(parameters[0],ServerInstance->Config->restartpass))\r        {\r              ServerInstance->WriteOpers("*** RESTART command from %s!%s@%s, restarting server.",user->nick,user->ident,user->host);\r\r                try\r            {\r                      ServerInstance->Restart("Server restarting.");\r         }\r              catch (...)\r            {\r                      /* We dont actually get here unless theres some fatal and unrecoverable error. */\r                      exit(0);\r               }\r      }\r      else\r   {\r              ServerInstance->WriteOpers("*** Failed RESTART Command from %s!%s@%s.",user->nick,user->ident,user->host);\r             return CMD_FAILURE;\r    }\r\r     return CMD_SUCCESS;\r}\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "configreader.h"
+#include "users.h"
+#include "commands/cmd_restart.h"
+
+extern "C" DllExport command_t* init_command(InspIRCd* Instance)
+{
+       return new cmd_restart(Instance);
+}
+
+CmdResult cmd_restart::Handle (const char** parameters, int pcnt, userrec *user)
+{
+       ServerInstance->Log(DEFAULT,"Restart: %s",user->nick);
+       if (!strcmp(parameters[0],ServerInstance->Config->restartpass))
+       {
+               ServerInstance->WriteOpers("*** RESTART command from %s!%s@%s, restarting server.",user->nick,user->ident,user->host);
+
+               try
+               {
+                       ServerInstance->Restart("Server restarting.");
+               }
+               catch (...)
+               {
+                       /* We dont actually get here unless theres some fatal and unrecoverable error. */
+                       exit(0);
+               }
+       }
+       else
+       {
+               ServerInstance->WriteOpers("*** Failed RESTART Command from %s!%s@%s.",user->nick,user->ident,user->host);
+               return CMD_FAILURE;
+       }
+
+       return CMD_SUCCESS;
+}
+
index ef531732d04c547762d59efc33a4b806c72cf92b..95b744412e15cc2fa22ea28e4bb56eb9764e3529 100644 (file)
@@ -1 +1,27 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "commands/cmd_rules.h"\r\rextern "C" DllExport command_t* init_command(InspIRCd* Instance)\r{\r      return new cmd_rules(Instance);\r}\r\rCmdResult cmd_rules::Handle (const char** parameters, int pcnt, userrec *user)\r{\r    user->ShowRULES();\r     return CMD_SUCCESS;\r}\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "commands/cmd_rules.h"
+
+extern "C" DllExport command_t* init_command(InspIRCd* Instance)
+{
+       return new cmd_rules(Instance);
+}
+
+CmdResult cmd_rules::Handle (const char** parameters, int pcnt, userrec *user)
+{
+       user->ShowRULES();
+       return CMD_SUCCESS;
+}
index acad55b1bb584ca867aaaab5851ca5ef4859093a..cace13c38a1f3cdfd7109df50486def903f47082 100644 (file)
@@ -1 +1,30 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "commands/cmd_server.h"\r\r\r\rextern "C" DllExport command_t* init_command(InspIRCd* Instance)\r{\r   return new cmd_server(Instance);\r}\r\rCmdResult cmd_server::Handle (const char** parameters, int pcnt, userrec *user)\r{\r  user->WriteServ("666 %s :You cannot identify as a server, you are a USER. IRC Operators informed.",user->nick);\r        ServerInstance->WriteOpers("*** WARNING: %s attempted to issue a SERVER command and is registered as a user!",user->nick);\r     return CMD_FAILURE;\r}\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "commands/cmd_server.h"
+
+
+
+extern "C" DllExport command_t* init_command(InspIRCd* Instance)
+{
+       return new cmd_server(Instance);
+}
+
+CmdResult cmd_server::Handle (const char** parameters, int pcnt, userrec *user)
+{
+       user->WriteServ("666 %s :You cannot identify as a server, you are a USER. IRC Operators informed.",user->nick);
+       ServerInstance->WriteOpers("*** WARNING: %s attempted to issue a SERVER command and is registered as a user!",user->nick);
+       return CMD_FAILURE;
+}
index d6fe63c949b2c38a0913c68466bbe7edfbd351f5..57105109b270cc7622a272b96360b9cbed22d148 100644 (file)
@@ -1 +1,32 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "commands/cmd_squit.h"\r\r/*\r * This is handled by the server linking module, if necessary. Do not remove this stub.\r */\r\r\rextern "C" DllExport command_t* init_command(InspIRCd* Instance)\r{\r     return new cmd_squit(Instance);\r}\r\rCmdResult cmd_squit::Handle (const char** parameters, int pcnt, userrec *user)\r{\r    user->WriteServ( "NOTICE %s :You are a nub. Load a linking module.", user->nick);\r      return CMD_FAILURE;\r}\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "commands/cmd_squit.h"
+
+/*
+ * This is handled by the server linking module, if necessary. Do not remove this stub.
+ */
+
+
+extern "C" DllExport command_t* init_command(InspIRCd* Instance)
+{
+       return new cmd_squit(Instance);
+}
+
+CmdResult cmd_squit::Handle (const char** parameters, int pcnt, userrec *user)
+{
+       user->WriteServ( "NOTICE %s :You are a nub. Load a linking module.", user->nick);
+       return CMD_FAILURE;
+}
index 4bf87298158a422a8ae68b480e2c5010957f6b15..98b2c63ddcf3d082fe53bf8be2db025e617a80e4 100644 (file)
@@ -1 +1,318 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "configreader.h"\r#ifndef WIN32\r#include <sys/resource.h>\r\r/* This is just to be completely certain that the change which fixed getrusage on RH7 doesn't break anything else -- Om */\r#ifndef RUSAGE_SELF\r#define RUSAGE_SELF 0\r#endif\r\r#endif\r#include "users.h"\r#include "modules.h"\r#include "xline.h"\r#include "commands/cmd_stats.h"\r#include "commands/cmd_whowas.h"\r\r\rextern "C" DllExport command_t* init_command(InspIRCd* Instance)\r{\r     return new cmd_stats(Instance);\r}\r\rCmdResult cmd_stats::Handle (const char** parameters, int pcnt, userrec *user)\r{\r    if (IS_LOCAL(user))\r    {\r              string_list values;\r            DoStats(this->ServerInstance, *parameters[0], user, values);\r           for (size_t i = 0; i < values.size(); i++)\r                     user->Write(":%s", values[i].c_str());\r }\r\r     return CMD_SUCCESS;\r}\r\rDllExport void DoStats(InspIRCd* ServerInstance, char statschar, userrec* user, string_list &results)\r{\r std::string sn = ServerInstance->Config->ServerName;\r\r  if ((*ServerInstance->Config->UserStats) && !IS_OPER(user) && !strchr(ServerInstance->Config->UserStats,statschar))\r    {\r              results.push_back(sn+std::string(" 481 ")+user->nick+" :Permission denied - STATS "+statschar+" is oper-only");\r                return;\r        }\r      \r       int MOD_RESULT = 0;\r    FOREACH_RESULT(I_OnStats,OnStats(statschar,user,results));\r     if (MOD_RESULT)\r                return;\r\r       switch (statschar)\r     {\r              /* stats p (show listening ports and registered clients on each) */\r            case 'p':\r              {\r                      for (size_t i = 0; i < ServerInstance->Config->ports.size(); i++)\r                      {\r                              std::string ip = ServerInstance->Config->ports[i]->GetIP();\r                            if (ip.empty())\r                                        ip.assign("*");\r\r                               results.push_back(sn+" 249 "+user->nick+" :"+ ip + ":"+ConvToStr(ServerInstance->Config->ports[i]->GetPort())+" (client, " +\r                                           ServerInstance->Config->ports[i]->GetDescription() + ")");\r                     }\r              }\r              break;\r\r                case 'n':\r              case 'c':\r              {\r                      /* This stats symbol must be handled by a linking module */\r            }\r              break;\r \r               case 'i':\r              {\r                      int idx = 0;\r                   for (ClassVector::iterator i = ServerInstance->Config->Classes.begin(); i != ServerInstance->Config->Classes.end(); i++)\r                       {\r                              results.push_back(sn+" 215 "+user->nick+" I NOMATCH * "+i->GetHost()+" "+ConvToStr(MAXCLIENTS)+" "+ConvToStr(idx)+" "+ServerInstance->Config->ServerName+" *");\r                                idx++;\r                 }\r              }\r              break;\r \r               case 'Y':\r              {\r                      int idx = 0;\r                   for (ClassVector::iterator i = ServerInstance->Config->Classes.begin(); i != ServerInstance->Config->Classes.end(); i++)\r                       {\r                              results.push_back(sn+" 218 "+user->nick+" Y "+ConvToStr(idx)+" "+ConvToStr(i->GetPingTime())+" 0 "+ConvToStr(i->GetSendqMax())+" :"+\r                                           ConvToStr(i->GetFlood())+" "+ConvToStr(i->GetRegTimeout()));\r                           idx++;\r                 }\r              }\r              break;\r\r                case 'U':\r              {\r                      char ulined[MAXBUF];\r                   for (int i = 0; i < ServerInstance->Config->ConfValueEnum(ServerInstance->Config->config_data, "uline"); i++)\r                  {\r                              ServerInstance->Config->ConfValue(ServerInstance->Config->config_data, "uline","server", i, ulined, MAXBUF);\r                                   results.push_back(sn+" 248 "+user->nick+" U "+std::string(ulined));\r                    }\r              }\r              break;\r \r               case 'P':\r              {\r                      int idx = 0;\r                   for (user_hash::iterator i = ServerInstance->clientlist->begin(); i != ServerInstance->clientlist->end(); i++)\r                 {\r                              if (IS_OPER(i->second) && !ServerInstance->ULine(i->second->server))\r                           {\r                                      results.push_back(sn+" 249 "+user->nick+" :"+i->second->nick+" ("+i->second->ident+"@"+i->second->dhost+") Idle: "+\r                                                    (IS_LOCAL(i->second) ? ConvToStr(ServerInstance->Time() - i->second->idle_lastmsg) + " secs" : "unavailable"));\r                                        idx++;\r                         }\r                      }\r                      results.push_back(sn+" 249 "+user->nick+" :"+ConvToStr(idx)+" OPER(s)");\r               }\r              break;\r \r               case 'k':\r                      ServerInstance->XLines->stats_k(user,results);\r         break;\r\r                case 'g':\r                      ServerInstance->XLines->stats_g(user,results);\r         break;\r\r                case 'q':\r                      ServerInstance->XLines->stats_q(user,results);\r         break;\r\r                case 'Z':\r                      ServerInstance->XLines->stats_z(user,results);\r         break;\r\r                case 'e':\r                      ServerInstance->XLines->stats_e(user,results);\r         break;\r\r                /* stats m (list number of times each command has been used, plus bytecount) */\r                case 'm':\r                      for (command_table::iterator i = ServerInstance->Parser->cmdlist.begin(); i != ServerInstance->Parser->cmdlist.end(); i++)\r                     {\r                              if (i->second->use_count)\r                              {\r                                      /* RPL_STATSCOMMANDS */\r                                        results.push_back(sn+" 212 "+user->nick+" "+i->second->command+" "+ConvToStr(i->second->use_count)+" "+ConvToStr(i->second->total_bytes));\r                             }\r                      }\r              break;\r\r                /* stats z (debug and memory info) */\r          case 'z':\r              {\r                      results.push_back(sn+" 240 "+user->nick+" :InspIRCd(CLASS) "+ConvToStr(sizeof(InspIRCd))+" bytes");\r                    results.push_back(sn+" 249 "+user->nick+" :Users(HASH_MAP) "+ConvToStr(ServerInstance->clientlist->size())+" ("+ConvToStr(ServerInstance->clientlist->size()*sizeof(userrec))+" bytes)");\r                      results.push_back(sn+" 249 "+user->nick+" :Channels(HASH_MAP) "+ConvToStr(ServerInstance->chanlist->size())+" ("+ConvToStr(ServerInstance->chanlist->size()*sizeof(chanrec))+" bytes)");\r                       results.push_back(sn+" 249 "+user->nick+" :Commands(VECTOR) "+ConvToStr(ServerInstance->Parser->cmdlist.size())+" ("+ConvToStr(ServerInstance->Parser->cmdlist.size()*sizeof(command_t))+" bytes)");\r\r                  if (!ServerInstance->Config->WhoWasGroupSize == 0 && !ServerInstance->Config->WhoWasMaxGroups == 0)\r                    {\r                              command_t* whowas_command = ServerInstance->Parser->GetHandler("WHOWAS");\r                              if (whowas_command)\r                            {\r                                      std::deque<classbase*> params;\r                                 Extensible whowas_stats;\r                                       params.push_back(&whowas_stats);\r                                       whowas_command->HandleInternal(WHOWAS_STATS, params);\r                                  if (whowas_stats.GetExt("stats"))\r                                      {\r                                              char* stats;\r                                           whowas_stats.GetExt("stats", stats);\r                                           results.push_back(sn+" 249 "+user->nick+" :"+ConvToStr(stats));\r                                        }\r                              }\r                      }\r\r                     results.push_back(sn+" 249 "+user->nick+" :MOTD(VECTOR) "+ConvToStr(ServerInstance->Config->MOTD.size())+", RULES(VECTOR) "+ConvToStr(ServerInstance->Config->RULES.size()));\r                  results.push_back(sn+" 249 "+user->nick+" :Modules(VECTOR) "+ConvToStr(ServerInstance->modules.size())+" ("+ConvToStr(ServerInstance->modules.size()*sizeof(Module))+" bytes)");\r                       results.push_back(sn+" 249 "+user->nick+" :ClassFactories(VECTOR) "+ConvToStr(ServerInstance->factory.size())+" ("+ConvToStr(ServerInstance->factory.size()*sizeof(ircd_module))+" bytes)");\r\r#ifndef WIN32\r                    /* Moved this down here so all the not-windows stuff (look w00tie, I didn't say win32!) is in one ifndef.\r                       * Also cuts out some identical code in both branches of the ifndef. -- Om\r                      */\r                    rusage R;\r\r                     /* Not sure why we were doing '0' with a RUSAGE_SELF comment rather than just using RUSAGE_SELF -- Om */\r                       if (!getrusage(RUSAGE_SELF,&R)) /* RUSAGE_SELF */\r                      {\r                              results.push_back(sn+" 249 "+user->nick+" :Total allocation: "+ConvToStr(R.ru_maxrss)+"K");\r                            results.push_back(sn+" 249 "+user->nick+" :Signals:          "+ConvToStr(R.ru_nsignals));\r                              results.push_back(sn+" 249 "+user->nick+" :Page faults:      "+ConvToStr(R.ru_majflt));\r                                results.push_back(sn+" 249 "+user->nick+" :Swaps:            "+ConvToStr(R.ru_nswap));\r                         results.push_back(sn+" 249 "+user->nick+" :Context Switches: Voluntary; "+ConvToStr(R.ru_nvcsw)+" Involuntary; "+ConvToStr(R.ru_nivcsw));\r\r                             timeval tv;\r                            char percent[30];\r                              gettimeofday(&tv, NULL);\r                       \r                               float n_elapsed = ((tv.tv_sec - ServerInstance->stats->LastSampled.tv_sec) * 1000000 + tv.tv_usec - ServerInstance->stats->LastSampled.tv_usec);\r                               float n_eaten = ((R.ru_utime.tv_sec - ServerInstance->stats->LastCPU.tv_sec) * 1000000 + R.ru_utime.tv_usec - ServerInstance->stats->LastCPU.tv_usec);\r                         float per = (n_eaten / n_elapsed) * 100;\r\r                              snprintf(percent, 30, "%03.5f%%", per);\r                                results.push_back(sn+" 249 "+user->nick+" :CPU Usage: "+percent);\r                      }\r#endif\r               }\r              break;\r \r               case 'T':\r              {\r                      char buffer[MAXBUF];\r                   results.push_back(sn+" 249 "+user->nick+" :accepts "+ConvToStr(ServerInstance->stats->statsAccept)+" refused "+ConvToStr(ServerInstance->stats->statsRefused));\r                        results.push_back(sn+" 249 "+user->nick+" :unknown commands "+ConvToStr(ServerInstance->stats->statsUnknown));\r                 results.push_back(sn+" 249 "+user->nick+" :nick collisions "+ConvToStr(ServerInstance->stats->statsCollisions));\r                       results.push_back(sn+" 249 "+user->nick+" :dns requests "+ConvToStr(ServerInstance->stats->statsDnsGood+ServerInstance->stats->statsDnsBad)+" succeeded "+ConvToStr(ServerInstance->stats->statsDnsGood)+" failed "+ConvToStr(ServerInstance->stats->statsDnsBad));\r                    results.push_back(sn+" 249 "+user->nick+" :connection count "+ConvToStr(ServerInstance->stats->statsConnects));\r                        snprintf(buffer,MAXBUF," 249 %s :bytes sent %5.2fK recv %5.2fK",user->nick,ServerInstance->stats->statsSent / 1024,ServerInstance->stats->statsRecv / 1024);\r                   results.push_back(sn+buffer);\r          }\r              break;\r\r                /* stats o */\r          case 'o':\r                      for (int i = 0; i < ServerInstance->Config->ConfValueEnum(ServerInstance->Config->config_data, "oper"); i++)\r                   {\r                              char LoginName[MAXBUF];\r                                char HostName[MAXBUF];\r                         char OperType[MAXBUF];\r                         ServerInstance->Config->ConfValue(ServerInstance->Config->config_data, "oper","name", i, LoginName, MAXBUF);\r                           ServerInstance->Config->ConfValue(ServerInstance->Config->config_data, "oper","host", i, HostName, MAXBUF);\r                            ServerInstance->Config->ConfValue(ServerInstance->Config->config_data, "oper","type", i, OperType, MAXBUF);\r                            results.push_back(sn+" 243 "+user->nick+" O "+HostName+" * "+LoginName+" "+OperType+" 0");\r                     }\r              break;\r\r                /* stats l (show user I/O stats) */\r            case 'l':\r                      results.push_back(sn+" 211 "+user->nick+" :nick[ident@host] sendq cmds_out bytes_out cmds_in bytes_in time_open");\r                     for (std::vector<userrec*>::iterator n = ServerInstance->local_users.begin(); n != ServerInstance->local_users.end(); n++)\r                     {\r                              userrec* i = *n;\r                               if (ServerInstance->IsNick(i->nick))\r                           {\r                                      results.push_back(sn+" 211 "+user->nick+" "+i->nick+"["+i->ident+"@"+i->dhost+"] "+ConvToStr(i->sendq.length())+" "+ConvToStr(i->cmds_out)+" "+ConvToStr(i->bytes_out)+" "+ConvToStr(i->cmds_in)+" "+ConvToStr(i->bytes_in)+" "+ConvToStr(ServerInstance->Time() - i->age));\r                           }\r                      }\r              break;\r\r        /* stats L (show user I/O stats with IP addresses) */\r          case 'L':\r                      results.push_back(sn+" 211 "+user->nick+" :nick[ident@ip] sendq cmds_out bytes_out cmds_in bytes_in time_open");\r                       for (std::vector<userrec*>::iterator n = ServerInstance->local_users.begin(); n != ServerInstance->local_users.end(); n++)\r                     {\r                              userrec* i = *n;\r                               if (ServerInstance->IsNick(i->nick))\r                           {\r                                      results.push_back(sn+" 211 "+user->nick+" "+i->nick+"["+i->ident+"@"+i->GetIPString()+"] "+ConvToStr(i->sendq.length())+" "+ConvToStr(i->cmds_out)+" "+ConvToStr(i->bytes_out)+" "+ConvToStr(i->cmds_in)+" "+ConvToStr(i->bytes_in)+" "+ConvToStr(ServerInstance->Time() - i->age));\r                           }\r                      }\r              break;\r\r                /* stats u (show server uptime) */\r             case 'u':\r              {\r                      time_t current_time = 0;\r                       current_time = ServerInstance->Time();\r                 time_t server_uptime = current_time - ServerInstance->startup_time;\r                    struct tm* stime;\r                      stime = gmtime(&server_uptime);\r                        /* i dont know who the hell would have an ircd running for over a year nonstop, but\r                     * Craig suggested this, and it seemed a good idea so in it went */\r                    if (stime->tm_year > 70)\r                       {\r                              char buffer[MAXBUF];\r                           snprintf(buffer,MAXBUF," 242 %s :Server up %d years, %d days, %.2d:%.2d:%.2d",user->nick,(stime->tm_year-70),stime->tm_yday,stime->tm_hour,stime->tm_min,stime->tm_sec);\r                               results.push_back(sn+buffer);\r                  }\r                      else\r                   {\r                              char buffer[MAXBUF];\r                           snprintf(buffer,MAXBUF," 242 %s :Server up %d days, %.2d:%.2d:%.2d",user->nick,stime->tm_yday,stime->tm_hour,stime->tm_min,stime->tm_sec);\r                             results.push_back(sn+buffer);\r                  }\r              }\r              break;\r\r                default:\r               break;\r }\r\r     results.push_back(sn+" 219 "+user->nick+" "+statschar+" :End of /STATS report");\r       ServerInstance->SNO->WriteToSnoMask('t',"%s '%c' requested by %s (%s@%s)",(!strcmp(user->server,ServerInstance->Config->ServerName) ? "Stats" : "Remote stats"),statschar,user->nick,user->ident,user->host);\r\r return;\r}\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "configreader.h"
+#ifndef WIN32
+#include <sys/resource.h>
+
+/* This is just to be completely certain that the change which fixed getrusage on RH7 doesn't break anything else -- Om */
+#ifndef RUSAGE_SELF
+#define RUSAGE_SELF 0
+#endif
+
+#endif
+#include "users.h"
+#include "modules.h"
+#include "xline.h"
+#include "commands/cmd_stats.h"
+#include "commands/cmd_whowas.h"
+
+
+extern "C" DllExport command_t* init_command(InspIRCd* Instance)
+{
+       return new cmd_stats(Instance);
+}
+
+CmdResult cmd_stats::Handle (const char** parameters, int pcnt, userrec *user)
+{
+       if (IS_LOCAL(user))
+       {
+               string_list values;
+               DoStats(this->ServerInstance, *parameters[0], user, values);
+               for (size_t i = 0; i < values.size(); i++)
+                       user->Write(":%s", values[i].c_str());
+       }
+
+       return CMD_SUCCESS;
+}
+
+DllExport void DoStats(InspIRCd* ServerInstance, char statschar, userrec* user, string_list &results)
+{
+       std::string sn = ServerInstance->Config->ServerName;
+
+       if ((*ServerInstance->Config->UserStats) && !IS_OPER(user) && !strchr(ServerInstance->Config->UserStats,statschar))
+       {
+               results.push_back(sn+std::string(" 481 ")+user->nick+" :Permission denied - STATS "+statschar+" is oper-only");
+               return;
+       }
+       
+       int MOD_RESULT = 0;
+       FOREACH_RESULT(I_OnStats,OnStats(statschar,user,results));
+       if (MOD_RESULT)
+               return;
+
+       switch (statschar)
+       {
+               /* stats p (show listening ports and registered clients on each) */
+               case 'p':
+               {
+                       for (size_t i = 0; i < ServerInstance->Config->ports.size(); i++)
+                       {
+                               std::string ip = ServerInstance->Config->ports[i]->GetIP();
+                               if (ip.empty())
+                                       ip.assign("*");
+
+                               results.push_back(sn+" 249 "+user->nick+" :"+ ip + ":"+ConvToStr(ServerInstance->Config->ports[i]->GetPort())+" (client, " +
+                                               ServerInstance->Config->ports[i]->GetDescription() + ")");
+                       }
+               }
+               break;
+
+               case 'n':
+               case 'c':
+               {
+                       /* This stats symbol must be handled by a linking module */
+               }
+               break;
+       
+               case 'i':
+               {
+                       int idx = 0;
+                       for (ClassVector::iterator i = ServerInstance->Config->Classes.begin(); i != ServerInstance->Config->Classes.end(); i++)
+                       {
+                               results.push_back(sn+" 215 "+user->nick+" I NOMATCH * "+i->GetHost()+" "+ConvToStr(MAXCLIENTS)+" "+ConvToStr(idx)+" "+ServerInstance->Config->ServerName+" *");
+                               idx++;
+                       }
+               }
+               break;
+       
+               case 'Y':
+               {
+                       int idx = 0;
+                       for (ClassVector::iterator i = ServerInstance->Config->Classes.begin(); i != ServerInstance->Config->Classes.end(); i++)
+                       {
+                               results.push_back(sn+" 218 "+user->nick+" Y "+ConvToStr(idx)+" "+ConvToStr(i->GetPingTime())+" 0 "+ConvToStr(i->GetSendqMax())+" :"+
+                                               ConvToStr(i->GetFlood())+" "+ConvToStr(i->GetRegTimeout()));
+                               idx++;
+                       }
+               }
+               break;
+
+               case 'U':
+               {
+                       char ulined[MAXBUF];
+                       for (int i = 0; i < ServerInstance->Config->ConfValueEnum(ServerInstance->Config->config_data, "uline"); i++)
+                       {
+                               ServerInstance->Config->ConfValue(ServerInstance->Config->config_data, "uline","server", i, ulined, MAXBUF);
+                                       results.push_back(sn+" 248 "+user->nick+" U "+std::string(ulined));
+                       }
+               }
+               break;
+       
+               case 'P':
+               {
+                       int idx = 0;
+                       for (user_hash::iterator i = ServerInstance->clientlist->begin(); i != ServerInstance->clientlist->end(); i++)
+                       {
+                               if (IS_OPER(i->second) && !ServerInstance->ULine(i->second->server))
+                               {
+                                       results.push_back(sn+" 249 "+user->nick+" :"+i->second->nick+" ("+i->second->ident+"@"+i->second->dhost+") Idle: "+
+                                                       (IS_LOCAL(i->second) ? ConvToStr(ServerInstance->Time() - i->second->idle_lastmsg) + " secs" : "unavailable"));
+                                       idx++;
+                               }
+                       }
+                       results.push_back(sn+" 249 "+user->nick+" :"+ConvToStr(idx)+" OPER(s)");
+               }
+               break;
+               case 'k':
+                       ServerInstance->XLines->stats_k(user,results);
+               break;
+
+               case 'g':
+                       ServerInstance->XLines->stats_g(user,results);
+               break;
+
+               case 'q':
+                       ServerInstance->XLines->stats_q(user,results);
+               break;
+
+               case 'Z':
+                       ServerInstance->XLines->stats_z(user,results);
+               break;
+
+               case 'e':
+                       ServerInstance->XLines->stats_e(user,results);
+               break;
+
+               /* stats m (list number of times each command has been used, plus bytecount) */
+               case 'm':
+                       for (command_table::iterator i = ServerInstance->Parser->cmdlist.begin(); i != ServerInstance->Parser->cmdlist.end(); i++)
+                       {
+                               if (i->second->use_count)
+                               {
+                                       /* RPL_STATSCOMMANDS */
+                                       results.push_back(sn+" 212 "+user->nick+" "+i->second->command+" "+ConvToStr(i->second->use_count)+" "+ConvToStr(i->second->total_bytes));
+                               }
+                       }
+               break;
+
+               /* stats z (debug and memory info) */
+               case 'z':
+               {
+                       results.push_back(sn+" 240 "+user->nick+" :InspIRCd(CLASS) "+ConvToStr(sizeof(InspIRCd))+" bytes");
+                       results.push_back(sn+" 249 "+user->nick+" :Users(HASH_MAP) "+ConvToStr(ServerInstance->clientlist->size())+" ("+ConvToStr(ServerInstance->clientlist->size()*sizeof(userrec))+" bytes)");
+                       results.push_back(sn+" 249 "+user->nick+" :Channels(HASH_MAP) "+ConvToStr(ServerInstance->chanlist->size())+" ("+ConvToStr(ServerInstance->chanlist->size()*sizeof(chanrec))+" bytes)");
+                       results.push_back(sn+" 249 "+user->nick+" :Commands(VECTOR) "+ConvToStr(ServerInstance->Parser->cmdlist.size())+" ("+ConvToStr(ServerInstance->Parser->cmdlist.size()*sizeof(command_t))+" bytes)");
+
+                       if (!ServerInstance->Config->WhoWasGroupSize == 0 && !ServerInstance->Config->WhoWasMaxGroups == 0)
+                       {
+                               command_t* whowas_command = ServerInstance->Parser->GetHandler("WHOWAS");
+                               if (whowas_command)
+                               {
+                                       std::deque<classbase*> params;
+                                       Extensible whowas_stats;
+                                       params.push_back(&whowas_stats);
+                                       whowas_command->HandleInternal(WHOWAS_STATS, params);
+                                       if (whowas_stats.GetExt("stats"))
+                                       {
+                                               char* stats;
+                                               whowas_stats.GetExt("stats", stats);
+                                               results.push_back(sn+" 249 "+user->nick+" :"+ConvToStr(stats));
+                                       }
+                               }
+                       }
+
+                       results.push_back(sn+" 249 "+user->nick+" :MOTD(VECTOR) "+ConvToStr(ServerInstance->Config->MOTD.size())+", RULES(VECTOR) "+ConvToStr(ServerInstance->Config->RULES.size()));
+                       results.push_back(sn+" 249 "+user->nick+" :Modules(VECTOR) "+ConvToStr(ServerInstance->modules.size())+" ("+ConvToStr(ServerInstance->modules.size()*sizeof(Module))+" bytes)");
+                       results.push_back(sn+" 249 "+user->nick+" :ClassFactories(VECTOR) "+ConvToStr(ServerInstance->factory.size())+" ("+ConvToStr(ServerInstance->factory.size()*sizeof(ircd_module))+" bytes)");
+
+#ifndef WIN32
+                       /* Moved this down here so all the not-windows stuff (look w00tie, I didn't say win32!) is in one ifndef.
+                        * Also cuts out some identical code in both branches of the ifndef. -- Om
+                        */
+                       rusage R;
+
+                       /* Not sure why we were doing '0' with a RUSAGE_SELF comment rather than just using RUSAGE_SELF -- Om */
+                       if (!getrusage(RUSAGE_SELF,&R)) /* RUSAGE_SELF */
+                       {
+                               results.push_back(sn+" 249 "+user->nick+" :Total allocation: "+ConvToStr(R.ru_maxrss)+"K");
+                               results.push_back(sn+" 249 "+user->nick+" :Signals:          "+ConvToStr(R.ru_nsignals));
+                               results.push_back(sn+" 249 "+user->nick+" :Page faults:      "+ConvToStr(R.ru_majflt));
+                               results.push_back(sn+" 249 "+user->nick+" :Swaps:            "+ConvToStr(R.ru_nswap));
+                               results.push_back(sn+" 249 "+user->nick+" :Context Switches: Voluntary; "+ConvToStr(R.ru_nvcsw)+" Involuntary; "+ConvToStr(R.ru_nivcsw));
+
+                               timeval tv;
+                               char percent[30];
+                               gettimeofday(&tv, NULL);
+                       
+                               float n_elapsed = ((tv.tv_sec - ServerInstance->stats->LastSampled.tv_sec) * 1000000 + tv.tv_usec - ServerInstance->stats->LastSampled.tv_usec);
+                               float n_eaten = ((R.ru_utime.tv_sec - ServerInstance->stats->LastCPU.tv_sec) * 1000000 + R.ru_utime.tv_usec - ServerInstance->stats->LastCPU.tv_usec);
+                               float per = (n_eaten / n_elapsed) * 100;
+
+                               snprintf(percent, 30, "%03.5f%%", per);
+                               results.push_back(sn+" 249 "+user->nick+" :CPU Usage: "+percent);
+                       }
+#endif
+               }
+               break;
+       
+               case 'T':
+               {
+                       char buffer[MAXBUF];
+                       results.push_back(sn+" 249 "+user->nick+" :accepts "+ConvToStr(ServerInstance->stats->statsAccept)+" refused "+ConvToStr(ServerInstance->stats->statsRefused));
+                       results.push_back(sn+" 249 "+user->nick+" :unknown commands "+ConvToStr(ServerInstance->stats->statsUnknown));
+                       results.push_back(sn+" 249 "+user->nick+" :nick collisions "+ConvToStr(ServerInstance->stats->statsCollisions));
+                       results.push_back(sn+" 249 "+user->nick+" :dns requests "+ConvToStr(ServerInstance->stats->statsDnsGood+ServerInstance->stats->statsDnsBad)+" succeeded "+ConvToStr(ServerInstance->stats->statsDnsGood)+" failed "+ConvToStr(ServerInstance->stats->statsDnsBad));
+                       results.push_back(sn+" 249 "+user->nick+" :connection count "+ConvToStr(ServerInstance->stats->statsConnects));
+                       snprintf(buffer,MAXBUF," 249 %s :bytes sent %5.2fK recv %5.2fK",user->nick,ServerInstance->stats->statsSent / 1024,ServerInstance->stats->statsRecv / 1024);
+                       results.push_back(sn+buffer);
+               }
+               break;
+
+               /* stats o */
+               case 'o':
+                       for (int i = 0; i < ServerInstance->Config->ConfValueEnum(ServerInstance->Config->config_data, "oper"); i++)
+                       {
+                               char LoginName[MAXBUF];
+                               char HostName[MAXBUF];
+                               char OperType[MAXBUF];
+                               ServerInstance->Config->ConfValue(ServerInstance->Config->config_data, "oper","name", i, LoginName, MAXBUF);
+                               ServerInstance->Config->ConfValue(ServerInstance->Config->config_data, "oper","host", i, HostName, MAXBUF);
+                               ServerInstance->Config->ConfValue(ServerInstance->Config->config_data, "oper","type", i, OperType, MAXBUF);
+                               results.push_back(sn+" 243 "+user->nick+" O "+HostName+" * "+LoginName+" "+OperType+" 0");
+                       }
+               break;
+
+               /* stats l (show user I/O stats) */
+               case 'l':
+                       results.push_back(sn+" 211 "+user->nick+" :nick[ident@host] sendq cmds_out bytes_out cmds_in bytes_in time_open");
+                       for (std::vector<userrec*>::iterator n = ServerInstance->local_users.begin(); n != ServerInstance->local_users.end(); n++)
+                       {
+                               userrec* i = *n;
+                               if (ServerInstance->IsNick(i->nick))
+                               {
+                                       results.push_back(sn+" 211 "+user->nick+" "+i->nick+"["+i->ident+"@"+i->dhost+"] "+ConvToStr(i->sendq.length())+" "+ConvToStr(i->cmds_out)+" "+ConvToStr(i->bytes_out)+" "+ConvToStr(i->cmds_in)+" "+ConvToStr(i->bytes_in)+" "+ConvToStr(ServerInstance->Time() - i->age));
+                               }
+                       }
+               break;
+
+       /* stats L (show user I/O stats with IP addresses) */
+               case 'L':
+                       results.push_back(sn+" 211 "+user->nick+" :nick[ident@ip] sendq cmds_out bytes_out cmds_in bytes_in time_open");
+                       for (std::vector<userrec*>::iterator n = ServerInstance->local_users.begin(); n != ServerInstance->local_users.end(); n++)
+                       {
+                               userrec* i = *n;
+                               if (ServerInstance->IsNick(i->nick))
+                               {
+                                       results.push_back(sn+" 211 "+user->nick+" "+i->nick+"["+i->ident+"@"+i->GetIPString()+"] "+ConvToStr(i->sendq.length())+" "+ConvToStr(i->cmds_out)+" "+ConvToStr(i->bytes_out)+" "+ConvToStr(i->cmds_in)+" "+ConvToStr(i->bytes_in)+" "+ConvToStr(ServerInstance->Time() - i->age));
+                               }
+                       }
+               break;
+
+               /* stats u (show server uptime) */
+               case 'u':
+               {
+                       time_t current_time = 0;
+                       current_time = ServerInstance->Time();
+                       time_t server_uptime = current_time - ServerInstance->startup_time;
+                       struct tm* stime;
+                       stime = gmtime(&server_uptime);
+                       /* i dont know who the hell would have an ircd running for over a year nonstop, but
+                        * Craig suggested this, and it seemed a good idea so in it went */
+                       if (stime->tm_year > 70)
+                       {
+                               char buffer[MAXBUF];
+                               snprintf(buffer,MAXBUF," 242 %s :Server up %d years, %d days, %.2d:%.2d:%.2d",user->nick,(stime->tm_year-70),stime->tm_yday,stime->tm_hour,stime->tm_min,stime->tm_sec);
+                               results.push_back(sn+buffer);
+                       }
+                       else
+                       {
+                               char buffer[MAXBUF];
+                               snprintf(buffer,MAXBUF," 242 %s :Server up %d days, %.2d:%.2d:%.2d",user->nick,stime->tm_yday,stime->tm_hour,stime->tm_min,stime->tm_sec);
+                               results.push_back(sn+buffer);
+                       }
+               }
+               break;
+
+               default:
+               break;
+       }
+
+       results.push_back(sn+" 219 "+user->nick+" "+statschar+" :End of /STATS report");
+       ServerInstance->SNO->WriteToSnoMask('t',"%s '%c' requested by %s (%s@%s)",(!strcmp(user->server,ServerInstance->Config->ServerName) ? "Stats" : "Remote stats"),statschar,user->nick,user->ident,user->host);
+
+       return;
+}
+
index 134ac9f2f817a9f395d64d5306b7a9ce306331ed..520bdf0903382ff539da1bb21bd634db5cfaa1bc 100644 (file)
@@ -1 +1,27 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "commands/cmd_summon.h"\r\rextern "C" DllExport command_t* init_command(InspIRCd* Instance)\r{\r     return new cmd_summon(Instance);\r}\r\rCmdResult cmd_summon::Handle (const char** parameters, int pcnt, userrec *user)\r{\r  user->WriteServ("445 %s :SUMMON has been disabled (depreciated command)",user->nick);\r  return CMD_FAILURE;\r}\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "commands/cmd_summon.h"
+
+extern "C" DllExport command_t* init_command(InspIRCd* Instance)
+{
+       return new cmd_summon(Instance);
+}
+
+CmdResult cmd_summon::Handle (const char** parameters, int pcnt, userrec *user)
+{
+       user->WriteServ("445 %s :SUMMON has been disabled (depreciated command)",user->nick);
+       return CMD_FAILURE;
+}
index 272a0ce820035513cc79655eafb047fc9ecfd104..cd0f0e1c7bf4706a40a0031a68a7cf2905779b50 100644 (file)
@@ -1 +1,40 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "configreader.h"\r#include "users.h"\r#include "commands/cmd_time.h"\r\r\r\rextern "C" DllExport command_t* init_command(InspIRCd* Instance)\r{\r   return new cmd_time(Instance);\r}\r\rCmdResult cmd_time::Handle (const char** parameters, int pcnt, userrec *user)\r{\r      struct tm* timeinfo;\r   time_t local = ServerInstance->Time();\r\r        timeinfo = localtime(&local);\r\r char tms[26];\r  snprintf(tms,26,"%s",asctime(timeinfo));\r       tms[24] = 0;\r\r  user->WriteServ("391 %s %s :%s",user->nick,ServerInstance->Config->ServerName,tms);\r\r   return CMD_SUCCESS;\r}\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "configreader.h"
+#include "users.h"
+#include "commands/cmd_time.h"
+
+
+
+extern "C" DllExport command_t* init_command(InspIRCd* Instance)
+{
+       return new cmd_time(Instance);
+}
+
+CmdResult cmd_time::Handle (const char** parameters, int pcnt, userrec *user)
+{
+       struct tm* timeinfo;
+       time_t local = ServerInstance->Time();
+
+       timeinfo = localtime(&local);
+
+       char tms[26];
+       snprintf(tms,26,"%s",asctime(timeinfo));
+       tms[24] = 0;
+
+       user->WriteServ("391 %s %s :%s",user->nick,ServerInstance->Config->ServerName,tms);
+
+       return CMD_SUCCESS;
+}
index 82f21b24e2d0c5d4d63837b0222e8f5f29812eac..741558282cf03777587a6fc6ff50ff7459e0e1ba 100644 (file)
@@ -1 +1,118 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "configreader.h"\r#include "users.h"\r#include "modules.h"\r#include "commands/cmd_topic.h"\r\r\rextern "C" DllExport command_t* init_command(InspIRCd* Instance)\r{\r      return new cmd_topic(Instance);\r}\r\rCmdResult cmd_topic::Handle (const char** parameters, int pcnt, userrec *user)\r{\r    chanrec* Ptr;\r\r if (pcnt == 1)\r {\r              Ptr = ServerInstance->FindChan(parameters[0]);\r         if (Ptr)\r               {\r                      if ((Ptr->modes[CM_SECRET]) && (!Ptr->HasUser(user)))\r                  {\r                              user->WriteServ("401 %s %s :No such nick/channel",user->nick, Ptr->name);\r                              return CMD_FAILURE;\r                    }\r                      if (Ptr->topicset)\r                     {\r                              user->WriteServ("332 %s %s :%s", user->nick, Ptr->name, Ptr->topic);\r                           user->WriteServ("333 %s %s %s %d", user->nick, Ptr->name, Ptr->setby, Ptr->topicset);\r                  }\r                      else\r                   {\r                              user->WriteServ("331 %s %s :No topic is set.", user->nick, Ptr->name);\r                 }\r              }\r              else\r           {\r                      user->WriteServ("401 %s %s :No such nick/channel",user->nick, parameters[0]);\r                  return CMD_FAILURE;\r            }\r              return CMD_SUCCESS;\r    }\r      else if (pcnt>1)\r       {\r              Ptr = ServerInstance->FindChan(parameters[0]);\r         if (Ptr)\r               {\r                      if (IS_LOCAL(user))\r                    {\r                              if (!Ptr->HasUser(user))\r                               {\r                                      user->WriteServ("442 %s %s :You're not on that channel!",user->nick, Ptr->name);\r                                       return CMD_FAILURE;\r                            }\r                              if ((Ptr->modes[CM_TOPICLOCK]) && (Ptr->GetStatus(user) < STATUS_HOP))\r                         {\r                                      user->WriteServ("482 %s %s :You must be at least a half-operator to change the topic on this channel", user->nick, Ptr->name);\r                                 return CMD_FAILURE;\r                            }\r                      }\r\r                     char topic[MAXTOPIC];\r\r                 if (IS_LOCAL(user))\r                    {\r                              /* XXX: we need two string copies for a local topic, because we cant\r                            * let a module see the topic as longer than it actually is\r                             */\r                            int MOD_RESULT = 0;\r\r                           strlcpy(topic,parameters[1],MAXTOPIC-1);\r                               FOREACH_RESULT(I_OnLocalTopicChange,OnLocalTopicChange(user,Ptr,topic));\r                               if (MOD_RESULT)\r                                        return CMD_FAILURE;\r\r                           strlcpy(Ptr->topic,topic,MAXTOPIC-1);\r                  }\r                      else\r                   {\r                              /* Sneaky shortcut, one string copy for a remote topic */\r                              strlcpy(Ptr->topic, parameters[1], MAXTOPIC-1);\r                        }\r\r                     if (ServerInstance->Config->FullHostInTopic)\r                           strlcpy(Ptr->setby,user->GetFullHost(),127);\r                   else\r                           strlcpy(Ptr->setby,user->nick,127);\r\r                   Ptr->topicset = ServerInstance->Time();\r                        Ptr->WriteChannel(user, "TOPIC %s :%s", Ptr->name, Ptr->topic);\r\r                       if (IS_LOCAL(user))\r                            /* We know 'topic' will contain valid data here */\r                             FOREACH_MOD(I_OnPostLocalTopicChange,OnPostLocalTopicChange(user, Ptr, topic));\r                }\r              else\r           {\r                      user->WriteServ("401 %s %s :No such nick/channel",user->nick, parameters[0]);\r                  return CMD_FAILURE;\r            }\r      }\r      return CMD_SUCCESS;\r}\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "configreader.h"
+#include "users.h"
+#include "modules.h"
+#include "commands/cmd_topic.h"
+
+
+extern "C" DllExport command_t* init_command(InspIRCd* Instance)
+{
+       return new cmd_topic(Instance);
+}
+
+CmdResult cmd_topic::Handle (const char** parameters, int pcnt, userrec *user)
+{
+       chanrec* Ptr;
+
+       if (pcnt == 1)
+       {
+               Ptr = ServerInstance->FindChan(parameters[0]);
+               if (Ptr)
+               {
+                       if ((Ptr->modes[CM_SECRET]) && (!Ptr->HasUser(user)))
+                       {
+                               user->WriteServ("401 %s %s :No such nick/channel",user->nick, Ptr->name);
+                               return CMD_FAILURE;
+                       }
+                       if (Ptr->topicset)
+                       {
+                               user->WriteServ("332 %s %s :%s", user->nick, Ptr->name, Ptr->topic);
+                               user->WriteServ("333 %s %s %s %d", user->nick, Ptr->name, Ptr->setby, Ptr->topicset);
+                       }
+                       else
+                       {
+                               user->WriteServ("331 %s %s :No topic is set.", user->nick, Ptr->name);
+                       }
+               }
+               else
+               {
+                       user->WriteServ("401 %s %s :No such nick/channel",user->nick, parameters[0]);
+                       return CMD_FAILURE;
+               }
+               return CMD_SUCCESS;
+       }
+       else if (pcnt>1)
+       {
+               Ptr = ServerInstance->FindChan(parameters[0]);
+               if (Ptr)
+               {
+                       if (IS_LOCAL(user))
+                       {
+                               if (!Ptr->HasUser(user))
+                               {
+                                       user->WriteServ("442 %s %s :You're not on that channel!",user->nick, Ptr->name);
+                                       return CMD_FAILURE;
+                               }
+                               if ((Ptr->modes[CM_TOPICLOCK]) && (Ptr->GetStatus(user) < STATUS_HOP))
+                               {
+                                       user->WriteServ("482 %s %s :You must be at least a half-operator to change the topic on this channel", user->nick, Ptr->name);
+                                       return CMD_FAILURE;
+                               }
+                       }
+
+                       char topic[MAXTOPIC];
+
+                       if (IS_LOCAL(user))
+                       {
+                               /* XXX: we need two string copies for a local topic, because we cant
+                                * let a module see the topic as longer than it actually is
+                                */
+                               int MOD_RESULT = 0;
+
+                               strlcpy(topic,parameters[1],MAXTOPIC-1);
+                               FOREACH_RESULT(I_OnLocalTopicChange,OnLocalTopicChange(user,Ptr,topic));
+                               if (MOD_RESULT)
+                                       return CMD_FAILURE;
+
+                               strlcpy(Ptr->topic,topic,MAXTOPIC-1);
+                       }
+                       else
+                       {
+                               /* Sneaky shortcut, one string copy for a remote topic */
+                               strlcpy(Ptr->topic, parameters[1], MAXTOPIC-1);
+                       }
+
+                       if (ServerInstance->Config->FullHostInTopic)
+                               strlcpy(Ptr->setby,user->GetFullHost(),127);
+                       else
+                               strlcpy(Ptr->setby,user->nick,127);
+
+                       Ptr->topicset = ServerInstance->Time();
+                       Ptr->WriteChannel(user, "TOPIC %s :%s", Ptr->name, Ptr->topic);
+
+                       if (IS_LOCAL(user))
+                               /* We know 'topic' will contain valid data here */
+                               FOREACH_MOD(I_OnPostLocalTopicChange,OnPostLocalTopicChange(user, Ptr, topic));
+               }
+               else
+               {
+                       user->WriteServ("401 %s %s :No such nick/channel",user->nick, parameters[0]);
+                       return CMD_FAILURE;
+               }
+       }
+       return CMD_SUCCESS;
+}
+
index 9cb58e8eeb2400fff65cc9b8fa51093dc76241b9..42105df98c8a62619c51030ceec5ed3a4d5dcb95 100644 (file)
@@ -1 +1,46 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "commands/cmd_trace.h"\r\rextern "C" DllExport command_t* init_command(InspIRCd* Instance)\r{\r      return new cmd_trace(Instance);\r}\r\r/** XXX: This is crap. someone fix this when you have time, to be more useful.\r */\rCmdResult cmd_trace::Handle (const char** parameters, int pcnt, userrec *user)\r{\r for (user_hash::iterator i = ServerInstance->clientlist->begin(); i != ServerInstance->clientlist->end(); i++)\r {\r              if (i->second->registered == REG_ALL)\r          {\r                      if (IS_OPER(i->second))\r                        {\r                              user->WriteServ("205 %s :Oper 0 %s",user->nick,i->second->nick);\r                       }\r                      else\r                   {\r                              user->WriteServ("204 %s :User 0 %s",user->nick,i->second->nick);\r                       }\r              }\r              else\r           {\r                      user->WriteServ("203 %s :???? 0 [%s]",user->nick,i->second->host);\r             }\r      }\r      return CMD_SUCCESS;\r}\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "commands/cmd_trace.h"
+
+extern "C" DllExport command_t* init_command(InspIRCd* Instance)
+{
+       return new cmd_trace(Instance);
+}
+
+/** XXX: This is crap. someone fix this when you have time, to be more useful.
+ */
+CmdResult cmd_trace::Handle (const char** parameters, int pcnt, userrec *user)
+{
+       for (user_hash::iterator i = ServerInstance->clientlist->begin(); i != ServerInstance->clientlist->end(); i++)
+       {
+               if (i->second->registered == REG_ALL)
+               {
+                       if (IS_OPER(i->second))
+                       {
+                               user->WriteServ("205 %s :Oper 0 %s",user->nick,i->second->nick);
+                       }
+                       else
+                       {
+                               user->WriteServ("204 %s :User 0 %s",user->nick,i->second->nick);
+                       }
+               }
+               else
+               {
+                       user->WriteServ("203 %s :???? 0 [%s]",user->nick,i->second->host);
+               }
+       }
+       return CMD_SUCCESS;
+}
index 51192aa7a9ab5eccb2e598c63a5ebe9b590d323a..44c2133e7005ebc2e817ce5a3cb5767e1026c2d5 100644 (file)
@@ -1 +1,39 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "commands/cmd_unloadmodule.h"\r\r\r\rextern "C" DllExport command_t* init_command(InspIRCd* Instance)\r{\r     return new cmd_unloadmodule(Instance);\r}\r\rCmdResult cmd_unloadmodule::Handle (const char** parameters, int pcnt, userrec *user)\r{\r      if (ServerInstance->UnloadModule(parameters[0]))\r       {\r              ServerInstance->WriteOpers("*** MODULE UNLOADED: %s unloaded %s", user->nick, parameters[0]);\r          user->WriteServ("973 %s %s :Module successfully unloaded.",user->nick, parameters[0]);\r }\r      else\r   {\r              user->WriteServ("972 %s %s :Failed to unload module: %s",user->nick, parameters[0],ServerInstance->ModuleError());\r             return CMD_FAILURE;\r    }\r\r     return CMD_SUCCESS;\r}\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "commands/cmd_unloadmodule.h"
+
+
+
+extern "C" DllExport command_t* init_command(InspIRCd* Instance)
+{
+       return new cmd_unloadmodule(Instance);
+}
+
+CmdResult cmd_unloadmodule::Handle (const char** parameters, int pcnt, userrec *user)
+{
+       if (ServerInstance->UnloadModule(parameters[0]))
+       {
+               ServerInstance->WriteOpers("*** MODULE UNLOADED: %s unloaded %s", user->nick, parameters[0]);
+               user->WriteServ("973 %s %s :Module successfully unloaded.",user->nick, parameters[0]);
+       }
+       else
+       {
+               user->WriteServ("972 %s %s :Failed to unload module: %s",user->nick, parameters[0],ServerInstance->ModuleError());
+               return CMD_FAILURE;
+       }
+
+       return CMD_SUCCESS;
+}
index aa9e3d3219449825bd372d42adf2b139835ccd65..dc224db76d88ba2e94fab58a540c804ddd7e78a0 100644 (file)
@@ -1 +1,69 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "configreader.h"\r#include "users.h"\r#include "commands/cmd_user.h"\r\rextern "C" DllExport command_t* init_command(InspIRCd* Instance)\r{\r     return new cmd_user(Instance);\r}\r\rCmdResult cmd_user::Handle (const char** parameters, int pcnt, userrec *user)\r{\r      /* A user may only send the USER command once */\r       if (!(user->registered & REG_USER))\r    {\r              if (!ServerInstance->IsIdent(parameters[0]))\r           {\r                      /*\r                      * RFC says we must use this numeric, so we do. Let's make it a little more nub friendly though. :)\r                     *  -- Craig, and then w00t.\r                    */\r                    user->WriteServ("461 %s USER :Your username is not valid",user->nick);\r                 return CMD_FAILURE;\r            }\r              else\r           {\r                      /* We're not checking ident, but I'm not sure I like the idea of '~' prefixing.. */\r                    /* XXX - The ident field is IDENTMAX+2 in size to account for +1 for the optional\r                       * ~ character, and +1 for null termination, therefore we can safely use up to\r                  * IDENTMAX here.\r                       */\r                    strlcpy(user->ident, parameters[0], IDENTMAX);\r                 strlcpy(user->fullname, *parameters[3] ? parameters[3] : "No info", MAXGECOS);\r                 user->registered = (user->registered | REG_USER);\r              }\r      }\r      else\r   {\r              user->WriteServ("462 %s :You may not reregister",user->nick);\r          return CMD_FAILURE;\r    }\r      /* parameters 2 and 3 are local and remote hosts, ignored when sent by client connection */\r    if (user->registered == REG_NICKUSER)\r  {\r              int MOD_RESULT = 0;\r            /* user is registered now, bit 0 = USER command, bit 1 = sent a NICK command */\r                if (ServerInstance->next_call > ServerInstance->Time() + ServerInstance->Config->dns_timeout)\r                  ServerInstance->next_call = ServerInstance->Time() + ServerInstance->Config->dns_timeout;\r              FOREACH_RESULT(I_OnUserRegister,OnUserRegister(user));\r         if (MOD_RESULT > 0)\r                    return CMD_FAILURE;\r\r   }\r\r     return CMD_SUCCESS;\r}\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "configreader.h"
+#include "users.h"
+#include "commands/cmd_user.h"
+
+extern "C" DllExport command_t* init_command(InspIRCd* Instance)
+{
+       return new cmd_user(Instance);
+}
+
+CmdResult cmd_user::Handle (const char** parameters, int pcnt, userrec *user)
+{
+       /* A user may only send the USER command once */
+       if (!(user->registered & REG_USER))
+       {
+               if (!ServerInstance->IsIdent(parameters[0]))
+               {
+                       /*
+                        * RFC says we must use this numeric, so we do. Let's make it a little more nub friendly though. :)
+                        *  -- Craig, and then w00t.
+                        */
+                       user->WriteServ("461 %s USER :Your username is not valid",user->nick);
+                       return CMD_FAILURE;
+               }
+               else
+               {
+                       /* We're not checking ident, but I'm not sure I like the idea of '~' prefixing.. */
+                       /* XXX - The ident field is IDENTMAX+2 in size to account for +1 for the optional
+                        * ~ character, and +1 for null termination, therefore we can safely use up to
+                        * IDENTMAX here.
+                        */
+                       strlcpy(user->ident, parameters[0], IDENTMAX);
+                       strlcpy(user->fullname, *parameters[3] ? parameters[3] : "No info", MAXGECOS);
+                       user->registered = (user->registered | REG_USER);
+               }
+       }
+       else
+       {
+               user->WriteServ("462 %s :You may not reregister",user->nick);
+               return CMD_FAILURE;
+       }
+       /* parameters 2 and 3 are local and remote hosts, ignored when sent by client connection */
+       if (user->registered == REG_NICKUSER)
+       {
+               int MOD_RESULT = 0;
+               /* user is registered now, bit 0 = USER command, bit 1 = sent a NICK command */
+               if (ServerInstance->next_call > ServerInstance->Time() + ServerInstance->Config->dns_timeout)
+                       ServerInstance->next_call = ServerInstance->Time() + ServerInstance->Config->dns_timeout;
+               FOREACH_RESULT(I_OnUserRegister,OnUserRegister(user));
+               if (MOD_RESULT > 0)
+                       return CMD_FAILURE;
+
+       }
+
+       return CMD_SUCCESS;
+}
index c0a2362cd607919364baf4736be8f8ba19e39d9f..9e644bdd1083e25dce90bd66c051819f65b0f153 100644 (file)
@@ -1 +1,63 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "commands/cmd_userhost.h"\r\rextern "C" DllExport command_t* init_command(InspIRCd* Instance)\r{\r   return new cmd_userhost(Instance);\r}\r\rCmdResult cmd_userhost::Handle (const char** parameters, int pcnt, userrec *user)\r{\r      std::string retbuf = std::string("302 ") + user->nick + " :";\r\r \r       for (int i = 0; i < pcnt; i++)\r {\r              userrec *u = ServerInstance->FindNick(parameters[i]);\r\r         if ((u) && (u->registered == REG_ALL))\r         {\r                      retbuf = retbuf + u->nick;\r\r                    if (IS_OPER(u))\r                        {\r                              retbuf = retbuf + "*=+";\r                       }\r                      else\r                   {\r                              retbuf = retbuf + "=+";\r                        }\r\r                     retbuf = retbuf + u->ident + "@";\r\r                     if (IS_OPER(user))\r                     {\r                              retbuf = retbuf + u->host;\r                     }\r                      else\r                   {\r                              retbuf = retbuf + u->dhost;\r                    }\r\r                     retbuf = retbuf + " ";\r         }\r      }\r\r     user->WriteServ(retbuf);\r\r      return CMD_SUCCESS;\r}\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "commands/cmd_userhost.h"
+
+extern "C" DllExport command_t* init_command(InspIRCd* Instance)
+{
+       return new cmd_userhost(Instance);
+}
+
+CmdResult cmd_userhost::Handle (const char** parameters, int pcnt, userrec *user)
+{
+       std::string retbuf = std::string("302 ") + user->nick + " :";
+
+       
+       for (int i = 0; i < pcnt; i++)
+       {
+               userrec *u = ServerInstance->FindNick(parameters[i]);
+
+               if ((u) && (u->registered == REG_ALL))
+               {
+                       retbuf = retbuf + u->nick;
+
+                       if (IS_OPER(u))
+                       {
+                               retbuf = retbuf + "*=+";
+                       }
+                       else
+                       {
+                               retbuf = retbuf + "=+";
+                       }
+
+                       retbuf = retbuf + u->ident + "@";
+
+                       if (IS_OPER(user))
+                       {
+                               retbuf = retbuf + u->host;
+                       }
+                       else
+                       {
+                               retbuf = retbuf + u->dhost;
+                       }
+
+                       retbuf = retbuf + " ";
+               }
+       }
+
+       user->WriteServ(retbuf);
+
+       return CMD_SUCCESS;
+}
index c3cb02075514f5e5595434958e8e6323df30fa2e..97b9b247d5270ef17a11da0511cdf743ca05d845 100644 (file)
@@ -1 +1,27 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "commands/cmd_users.h"\r\rextern "C" DllExport command_t* init_command(InspIRCd* Instance)\r{\r      return new cmd_users(Instance);\r}\r\rCmdResult cmd_users::Handle (const char** parameters, int pcnt, userrec *user)\r{\r    user->WriteServ("445 %s :USERS has been disabled (depreciated command)",user->nick);\r   return CMD_FAILURE;\r}\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "commands/cmd_users.h"
+
+extern "C" DllExport command_t* init_command(InspIRCd* Instance)
+{
+       return new cmd_users(Instance);
+}
+
+CmdResult cmd_users::Handle (const char** parameters, int pcnt, userrec *user)
+{
+       user->WriteServ("445 %s :USERS has been disabled (depreciated command)",user->nick);
+       return CMD_FAILURE;
+}
index a33dd5bd03123cdd2ea11c7bbf39766c16c13205..599b7bf75aaf6f2ab777561e941bebf7dd70d5d9 100644 (file)
@@ -1 +1,31 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "configreader.h"\r#include "users.h"\r#include "commands/cmd_version.h"\r\r\r\rextern "C" DllExport command_t* init_command(InspIRCd* Instance)\r{\r        return new cmd_version(Instance);\r}\r\rCmdResult cmd_version::Handle (const char** parameters, int pcnt, userrec *user)\r{\r        user->WriteServ("351 %s :%s",user->nick,ServerInstance->GetVersionString().c_str());\r   ServerInstance->Config->Send005(user);\r return CMD_SUCCESS;\r}\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "configreader.h"
+#include "users.h"
+#include "commands/cmd_version.h"
+
+
+
+extern "C" DllExport command_t* init_command(InspIRCd* Instance)
+{
+       return new cmd_version(Instance);
+}
+
+CmdResult cmd_version::Handle (const char** parameters, int pcnt, userrec *user)
+{
+       user->WriteServ("351 %s :%s",user->nick,ServerInstance->GetVersionString().c_str());
+       ServerInstance->Config->Send005(user);
+       return CMD_SUCCESS;
+}
index 88c8fccf524b7d0617e91c4aebf5a4157eb98997..d32b19ebd4294ee50daf1e437d837fa84cbf1478 100644 (file)
@@ -1 +1,31 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "configreader.h"\r#include "modules.h"\r#include "commands/cmd_wallops.h"\r\r\r\rextern "C" DllExport command_t* init_command(InspIRCd* Instance)\r{\r      return new cmd_wallops(Instance);\r}\r\rCmdResult cmd_wallops::Handle (const char** parameters, int pcnt, userrec *user)\r{\r        user->WriteWallOps(std::string(parameters[0]));\r        FOREACH_MOD(I_OnWallops,OnWallops(user,parameters[0]));\r        return CMD_SUCCESS;\r}\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "configreader.h"
+#include "modules.h"
+#include "commands/cmd_wallops.h"
+
+
+
+extern "C" DllExport command_t* init_command(InspIRCd* Instance)
+{
+       return new cmd_wallops(Instance);
+}
+
+CmdResult cmd_wallops::Handle (const char** parameters, int pcnt, userrec *user)
+{
+       user->WriteWallOps(std::string(parameters[0]));
+       FOREACH_MOD(I_OnWallops,OnWallops(user,parameters[0]));
+       return CMD_SUCCESS;
+}
index 6054351d9819191d4f04bc86c736afdd3a63b3f5..31e8030f5d0fc470396fdaf95e8c098f8c7ea3a1 100644 (file)
@@ -1 +1,328 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *        the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "configreader.h"\r#include "users.h"\r#include "modules.h"\r#include "wildcard.h"\r#include "commands/cmd_who.h"\r\r/* get the last 'visible' chan of a user */\rstatic char *getlastchanname(userrec *u)\r{\r   UCListIter i = u->chans.begin();\r       if (i != u->chans.end())\r       {\r              if (!i->first->IsModeSet('s'))\r                 return i->first->name;\r }\r\r     return "*";\r}\r\rbool cmd_who::whomatch(userrec* user, const char* matchtext)\r{\r  bool realhost = false;\r bool realname = false;\r bool positive = true;\r  bool metadata = false;\r bool ident = false;\r    bool away = false;\r     bool port = false;\r     char* dummy = NULL;\r\r   if (user->registered != REG_ALL)\r               return false;\r\r if (opt_local && !IS_LOCAL(user))\r              return false;\r  else if (opt_far && IS_LOCAL(user))\r            return false;\r\r if (opt_mode)\r  {\r              for (const char* n = matchtext; *n; n++)\r               {\r                      if (*n == '+')\r                 {\r                              positive = true;\r                               continue;\r                      }\r                      else if (*n == '-')\r                    {\r                              positive = false;\r                              continue;\r                      }\r                      if (user->IsModeSet(*n) != positive)\r                           return false;\r          }\r              return true;\r   }\r      else\r   {\r\r             if (opt_metadata)\r                      metadata = user->GetExt(matchtext, dummy);\r             else\r           {\r                      if (opt_realname)\r                              realname = match(user->fullname, matchtext);\r                   else\r                   {\r                              if (opt_showrealhost)\r                                  realhost = match(user->host, matchtext);\r                               else\r                           {\r                                      if (opt_ident)\r                                         ident = match(user->ident, matchtext);\r                                 else\r                                   {\r                                              if (opt_port)\r                                          {\r                                                      irc::portparser portrange(matchtext, false);\r                                                   long portno = -1;\r                                                      while ((portno = portrange.GetToken()))\r                                                                if (portno == user->GetPort())\r                                                                 port = true;\r                                           }\r                                              else\r                                           {\r                                                      if (opt_away)\r                                                          away = match(user->awaymsg, matchtext);\r                                                }\r                                      }\r                              }\r                      }\r              }\r              return ((port) || (away) || (ident) || (metadata) || (realname) || (realhost) || (match(user->dhost, matchtext)) || (match(user->nick, matchtext)) || (match(user->server, matchtext)));\r       }\r}\r\r\r\rextern "C" DllExport command_t* init_command(InspIRCd* Instance)\r{\r      return new cmd_who(Instance);\r}\r\rbool cmd_who::CanView(chanrec* chan, userrec* user)\r{\r if (!user || !chan)\r            return false;\r\r /* Execute items in fastest-to-execute first order */\r\r /* Opers see all */\r    if (IS_OPER(user))\r             return true;\r   else if (!chan->IsModeSet('s') && !chan->IsModeSet('p'))\r               return true;\r   else if (chan->HasUser(user))\r          return true;\r\r  return false;\r}\r\rvoid cmd_who::SendWhoLine(userrec* user, const std::string &initial, chanrec* ch, userrec* u, std::vector<std::string> &whoresults)\r{\r std::string lcn = getlastchanname(u);\r  chanrec* chlast = ServerInstance->FindChan(lcn);\r\r      /* Not visible to this user */\r if (u->Visibility && !u->Visibility->VisibleTo(user))\r          return;\r\r       std::string wholine =   initial + (ch ? ch->name : lcn) + " " + u->ident + " " + (opt_showrealhost ? u->host : u->dhost) + " " +\r                               ((*ServerInstance->Config->HideWhoisServer && !IS_OPER(user)) ? ServerInstance->Config->HideWhoisServer : u->server) +\r                         " " + u->nick + " ";\r\r  /* away? */\r    if (IS_AWAY(u))\r        {\r              wholine.append("G");\r   }\r      else\r   {\r              wholine.append("H");\r   }\r\r     /* oper? */\r    if (IS_OPER(u))\r        {\r              wholine.append("*");\r   }\r\r     wholine = wholine + (ch ? ch->GetPrefixChar(u) : (chlast ? chlast->GetPrefixChar(u) : "")) + " :0 " + u->fullname;\r     whoresults.push_back(wholine);\r}\r\rCmdResult cmd_who::Handle (const char** parameters, int pcnt, userrec *user)\r{\r       /*\r      * XXX - RFC says:\r      *   The <name> passed to WHO is matched against users' host, server, real\r      *   name and nickname\r  * Currently, we support WHO #chan, WHO nick, WHO 0, WHO *, and the addition of a 'o' flag, as per RFC.\r         */\r\r   /* WHO options */\r      opt_viewopersonly = false;\r     opt_showrealhost = false;\r      opt_unlimit = false;\r   opt_realname = false;\r  opt_mode = false;\r      opt_ident = false;\r     opt_metadata = false;\r  opt_port = false;\r      opt_away = false;\r      opt_local = false;\r     opt_far = false;\r\r      chanrec *ch = NULL;\r    std::vector<std::string> whoresults;\r   std::string initial = "352 " + std::string(user->nick) + " ";\r\r const char* matchtext = NULL;\r\r /* Change '0' into '*' so the wildcard matcher can grok it */\r  matchtext = parameters[0];\r     if (!strcmp(matchtext,"0"))\r            matchtext = "*";\r\r      if (pcnt > 1)\r  {\r              /* parse flags */\r              const char *iter = parameters[1];\r\r             while (*iter)\r          {\r                      switch (*iter)\r                 {\r                              case 'o':\r                                      opt_viewopersonly = true;\r                              break;\r                         case 'h':\r                                      if (IS_OPER(user))\r                                             opt_showrealhost = true;\r                               break;\r                         case 'u':\r                                      if (IS_OPER(user))\r                                             opt_unlimit = true;\r                            break;\r                         case 'r':\r                                      opt_realname = true;\r                           break;\r                         case 'm':\r                                      opt_mode = true;\r                               break;\r                         case 'M':\r                                      opt_metadata = true;\r                           break;\r                         case 'i':\r                                      opt_ident = true;\r                              break;\r                         case 'p':\r                                      opt_port = true;\r                               break;\r                         case 'a':\r                                      opt_away = true;\r                               break;\r                         case 'l':\r                                      opt_local = true;\r                              break;\r                         case 'f':\r                                      opt_far = true;\r                                break;\r                 }\r\r                     *iter++;\r               }\r      }\r\r\r    /* who on a channel? */\r        ch = ServerInstance->FindChan(matchtext);\r\r     if (ch)\r        {\r              if (CanView(ch,user))\r          {\r                      bool inside = ch->HasUser(user);\r       \r                       /* who on a channel. */\r                        CUList *cu = ch->GetUsers();\r   \r                       for (CUList::iterator i = cu->begin(); i != cu->end(); i++)\r                    {\r                              /* opers only, please */\r                               if (opt_viewopersonly && !IS_OPER(i->first))\r                                   continue;\r      \r                               /* If we're not inside the channel, hide +i users */\r                           if (i->first->IsModeSet('i') && !inside)\r                                       continue;\r      \r                               SendWhoLine(user, initial, ch, i->first, whoresults);\r                  }\r              }\r      }\r      else\r   {\r              /* Match against wildcard of nick, server or host */\r\r          if (opt_viewopersonly)\r         {\r                      /* Showing only opers */\r                       for (std::vector<userrec*>::iterator i = ServerInstance->all_opers.begin(); i != ServerInstance->all_opers.end(); i++)\r                 {\r                              userrec* oper = *i;\r\r                           if (whomatch(oper, matchtext))\r                         {\r                                      if ((!oper->IsModeSet('i')) && (!IS_OPER(user)))\r                                               continue;\r\r                                     SendWhoLine(user, initial, NULL, oper, whoresults);\r                            }\r                      }\r              }\r              else\r           {\r                      for (user_hash::iterator i = ServerInstance->clientlist->begin(); i != ServerInstance->clientlist->end(); i++)\r                 {\r                              if (whomatch(i->second, matchtext))\r                            {\r                                      if ((i->second->IsModeSet('i')) && (!IS_OPER(user)))\r                                           continue;\r\r                                     SendWhoLine(user, initial, NULL, i->second, whoresults);\r                               }\r                      }\r              }\r      }\r      /* Send the results out */\r     if ((ServerInstance->Config->MaxWhoResults && (whoresults.size() <= (size_t)ServerInstance->Config->MaxWhoResults)) || opt_unlimit)\r    {\r              for (std::vector<std::string>::const_iterator n = whoresults.begin(); n != whoresults.end(); n++)\r                      user->WriteServ(*n);\r           user->WriteServ("315 %s %s :End of /WHO list.",user->nick, *parameters[0] ? parameters[0] : "*");\r              return CMD_SUCCESS;\r    }\r      else\r   {\r              /* BZZT! Too many results. */\r          user->WriteServ("315 %s %s :Too many results",user->nick, parameters[0]);\r              return CMD_FAILURE;\r    }\r}\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *         the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "configreader.h"
+#include "users.h"
+#include "modules.h"
+#include "wildcard.h"
+#include "commands/cmd_who.h"
+
+/* get the last 'visible' chan of a user */
+static char *getlastchanname(userrec *u)
+{
+       UCListIter i = u->chans.begin();
+       if (i != u->chans.end())
+       {
+               if (!i->first->IsModeSet('s'))
+                       return i->first->name;
+       }
+
+       return "*";
+}
+
+bool cmd_who::whomatch(userrec* user, const char* matchtext)
+{
+       bool realhost = false;
+       bool realname = false;
+       bool positive = true;
+       bool metadata = false;
+       bool ident = false;
+       bool away = false;
+       bool port = false;
+       char* dummy = NULL;
+
+       if (user->registered != REG_ALL)
+               return false;
+
+       if (opt_local && !IS_LOCAL(user))
+               return false;
+       else if (opt_far && IS_LOCAL(user))
+               return false;
+
+       if (opt_mode)
+       {
+               for (const char* n = matchtext; *n; n++)
+               {
+                       if (*n == '+')
+                       {
+                               positive = true;
+                               continue;
+                       }
+                       else if (*n == '-')
+                       {
+                               positive = false;
+                               continue;
+                       }
+                       if (user->IsModeSet(*n) != positive)
+                               return false;
+               }
+               return true;
+       }
+       else
+       {
+
+               if (opt_metadata)
+                       metadata = user->GetExt(matchtext, dummy);
+               else
+               {
+                       if (opt_realname)
+                               realname = match(user->fullname, matchtext);
+                       else
+                       {
+                               if (opt_showrealhost)
+                                       realhost = match(user->host, matchtext);
+                               else
+                               {
+                                       if (opt_ident)
+                                               ident = match(user->ident, matchtext);
+                                       else
+                                       {
+                                               if (opt_port)
+                                               {
+                                                       irc::portparser portrange(matchtext, false);
+                                                       long portno = -1;
+                                                       while ((portno = portrange.GetToken()))
+                                                               if (portno == user->GetPort())
+                                                                       port = true;
+                                               }
+                                               else
+                                               {
+                                                       if (opt_away)
+                                                               away = match(user->awaymsg, matchtext);
+                                               }
+                                       }
+                               }
+                       }
+               }
+               return ((port) || (away) || (ident) || (metadata) || (realname) || (realhost) || (match(user->dhost, matchtext)) || (match(user->nick, matchtext)) || (match(user->server, matchtext)));
+       }
+}
+
+
+
+extern "C" DllExport command_t* init_command(InspIRCd* Instance)
+{
+       return new cmd_who(Instance);
+}
+
+bool cmd_who::CanView(chanrec* chan, userrec* user)
+{
+       if (!user || !chan)
+               return false;
+
+       /* Execute items in fastest-to-execute first order */
+
+       /* Opers see all */
+       if (IS_OPER(user))
+               return true;
+       else if (!chan->IsModeSet('s') && !chan->IsModeSet('p'))
+               return true;
+       else if (chan->HasUser(user))
+               return true;
+
+       return false;
+}
+
+void cmd_who::SendWhoLine(userrec* user, const std::string &initial, chanrec* ch, userrec* u, std::vector<std::string> &whoresults)
+{
+       std::string lcn = getlastchanname(u);
+       chanrec* chlast = ServerInstance->FindChan(lcn);
+
+       /* Not visible to this user */
+       if (u->Visibility && !u->Visibility->VisibleTo(user))
+               return;
+
+       std::string wholine =   initial + (ch ? ch->name : lcn) + " " + u->ident + " " + (opt_showrealhost ? u->host : u->dhost) + " " +
+                               ((*ServerInstance->Config->HideWhoisServer && !IS_OPER(user)) ? ServerInstance->Config->HideWhoisServer : u->server) +
+                               " " + u->nick + " ";
+
+       /* away? */
+       if (IS_AWAY(u))
+       {
+               wholine.append("G");
+       }
+       else
+       {
+               wholine.append("H");
+       }
+
+       /* oper? */
+       if (IS_OPER(u))
+       {
+               wholine.append("*");
+       }
+
+       wholine = wholine + (ch ? ch->GetPrefixChar(u) : (chlast ? chlast->GetPrefixChar(u) : "")) + " :0 " + u->fullname;
+       whoresults.push_back(wholine);
+}
+
+CmdResult cmd_who::Handle (const char** parameters, int pcnt, userrec *user)
+{
+       /*
+        * XXX - RFC says:
+        *   The <name> passed to WHO is matched against users' host, server, real
+        *   name and nickname
+        * Currently, we support WHO #chan, WHO nick, WHO 0, WHO *, and the addition of a 'o' flag, as per RFC.
+        */
+
+       /* WHO options */
+       opt_viewopersonly = false;
+       opt_showrealhost = false;
+       opt_unlimit = false;
+       opt_realname = false;
+       opt_mode = false;
+       opt_ident = false;
+       opt_metadata = false;
+       opt_port = false;
+       opt_away = false;
+       opt_local = false;
+       opt_far = false;
+
+       chanrec *ch = NULL;
+       std::vector<std::string> whoresults;
+       std::string initial = "352 " + std::string(user->nick) + " ";
+
+       const char* matchtext = NULL;
+
+       /* Change '0' into '*' so the wildcard matcher can grok it */
+       matchtext = parameters[0];
+       if (!strcmp(matchtext,"0"))
+               matchtext = "*";
+
+       if (pcnt > 1)
+       {
+               /* parse flags */
+               const char *iter = parameters[1];
+
+               while (*iter)
+               {
+                       switch (*iter)
+                       {
+                               case 'o':
+                                       opt_viewopersonly = true;
+                               break;
+                               case 'h':
+                                       if (IS_OPER(user))
+                                               opt_showrealhost = true;
+                               break;
+                               case 'u':
+                                       if (IS_OPER(user))
+                                               opt_unlimit = true;
+                               break;
+                               case 'r':
+                                       opt_realname = true;
+                               break;
+                               case 'm':
+                                       opt_mode = true;
+                               break;
+                               case 'M':
+                                       opt_metadata = true;
+                               break;
+                               case 'i':
+                                       opt_ident = true;
+                               break;
+                               case 'p':
+                                       opt_port = true;
+                               break;
+                               case 'a':
+                                       opt_away = true;
+                               break;
+                               case 'l':
+                                       opt_local = true;
+                               break;
+                               case 'f':
+                                       opt_far = true;
+                               break;
+                       }
+
+                       *iter++;
+               }
+       }
+
+
+       /* who on a channel? */
+       ch = ServerInstance->FindChan(matchtext);
+
+       if (ch)
+       {
+               if (CanView(ch,user))
+               {
+                       bool inside = ch->HasUser(user);
+       
+                       /* who on a channel. */
+                       CUList *cu = ch->GetUsers();
+       
+                       for (CUList::iterator i = cu->begin(); i != cu->end(); i++)
+                       {
+                               /* opers only, please */
+                               if (opt_viewopersonly && !IS_OPER(i->first))
+                                       continue;
+       
+                               /* If we're not inside the channel, hide +i users */
+                               if (i->first->IsModeSet('i') && !inside)
+                                       continue;
+       
+                               SendWhoLine(user, initial, ch, i->first, whoresults);
+                       }
+               }
+       }
+       else
+       {
+               /* Match against wildcard of nick, server or host */
+
+               if (opt_viewopersonly)
+               {
+                       /* Showing only opers */
+                       for (std::vector<userrec*>::iterator i = ServerInstance->all_opers.begin(); i != ServerInstance->all_opers.end(); i++)
+                       {
+                               userrec* oper = *i;
+
+                               if (whomatch(oper, matchtext))
+                               {
+                                       if ((!oper->IsModeSet('i')) && (!IS_OPER(user)))
+                                               continue;
+
+                                       SendWhoLine(user, initial, NULL, oper, whoresults);
+                               }
+                       }
+               }
+               else
+               {
+                       for (user_hash::iterator i = ServerInstance->clientlist->begin(); i != ServerInstance->clientlist->end(); i++)
+                       {
+                               if (whomatch(i->second, matchtext))
+                               {
+                                       if ((i->second->IsModeSet('i')) && (!IS_OPER(user)))
+                                               continue;
+
+                                       SendWhoLine(user, initial, NULL, i->second, whoresults);
+                               }
+                       }
+               }
+       }
+       /* Send the results out */
+       if ((ServerInstance->Config->MaxWhoResults && (whoresults.size() <= (size_t)ServerInstance->Config->MaxWhoResults)) || opt_unlimit)
+       {
+               for (std::vector<std::string>::const_iterator n = whoresults.begin(); n != whoresults.end(); n++)
+                       user->WriteServ(*n);
+               user->WriteServ("315 %s %s :End of /WHO list.",user->nick, *parameters[0] ? parameters[0] : "*");
+               return CMD_SUCCESS;
+       }
+       else
+       {
+               /* BZZT! Too many results. */
+               user->WriteServ("315 %s %s :Too many results",user->nick, parameters[0]);
+               return CMD_FAILURE;
+       }
+}
index 3797efeaa42f07ae712e2a9a0d121c98e636facb..897ec60ac262d313a9b09591538a078c094e0a58 100644 (file)
@@ -1 +1,144 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "configreader.h"\r#include "users.h"\r#include "modules.h"\r#include "commands/cmd_whois.h"\r#include "hashcomp.h"\r\rvoid do_whois(InspIRCd* ServerInstance, userrec* user, userrec* dest,unsigned long signon, unsigned long idle, const char* nick)\r{\r if (dest->Visibility && !dest->Visibility->VisibleTo(user))\r    {\r              ServerInstance->SendWhoisLine(user, dest, 401, "%s %s :No such nick/channel",user->nick, *nick ? nick : "*");\r          ServerInstance->SendWhoisLine(user, dest, 318, "%s %s :End of /WHOIS list.",user->nick, *nick ? nick : "*");\r           return;\r        }\r\r     if (dest->registered == REG_ALL)\r       {\r              ServerInstance->SendWhoisLine(user, dest, 311, "%s %s %s %s * :%s",user->nick, dest->nick, dest->ident, dest->dhost, dest->fullname);\r          if (user == dest || IS_OPER(user))\r             {\r                      ServerInstance->SendWhoisLine(user, dest, 378, "%s %s :is connecting from %s@%s %s", user->nick, dest->nick, dest->ident, dest->host, dest->GetIPString());\r            }\r\r             std::string cl = dest->ChannelList(user);\r\r             if (cl.length())\r               {\r                      if (cl.length() > 400)\r                 {\r                              user->SplitChanList(dest,cl);\r                  }\r                      else\r                   {\r                              ServerInstance->SendWhoisLine(user, dest, 319, "%s %s :%s",user->nick, dest->nick, cl.c_str());\r                        }\r              }\r              if (*ServerInstance->Config->HideWhoisServer && !IS_OPER(user))\r                {\r                      ServerInstance->SendWhoisLine(user, dest, 312, "%s %s %s :%s",user->nick, dest->nick, ServerInstance->Config->HideWhoisServer, ServerInstance->Config->Network);\r               }\r              else\r           {\r                      ServerInstance->SendWhoisLine(user, dest, 312, "%s %s %s :%s",user->nick, dest->nick, dest->server, ServerInstance->GetServerDescription(dest->server).c_str());\r               }\r\r             if (IS_AWAY(dest))\r             {\r                      ServerInstance->SendWhoisLine(user, dest, 301, "%s %s :%s",user->nick, dest->nick, dest->awaymsg);\r             }\r\r             if (IS_OPER(dest))\r             {\r                      ServerInstance->SendWhoisLine(user, dest, 313, "%s %s :is %s %s on %s",user->nick, dest->nick, (strchr("AEIOUaeiou",*dest->oper) ? "an" : "a"),irc::Spacify(dest->oper), ServerInstance->Config->Network);\r             }\r\r             FOREACH_MOD(I_OnWhois,OnWhois(user,dest));\r\r            /*\r              * We only send these if we've been provided them. That is, if hidewhois is turned off, and user is local, or\r           * if remote whois is queried, too. This is to keep the user hidden, and also since you can't reliably tell remote time. -- w00t\r                */\r            if ((idle) || (signon))\r                {\r                      ServerInstance->SendWhoisLine(user, dest, 317, "%s %s %d %d :seconds idle, signon time",user->nick, dest->nick, idle, signon);\r         }\r\r             ServerInstance->SendWhoisLine(user, dest, 318, "%s %s :End of /WHOIS list.",user->nick, dest->nick);\r   }\r      else\r   {\r              ServerInstance->SendWhoisLine(user, dest, 401, "%s %s :No such nick/channel",user->nick, *nick ? nick : "*");\r          ServerInstance->SendWhoisLine(user, dest, 318, "%s %s :End of /WHOIS list.",user->nick, *nick ? nick : "*");\r   }\r}\r\r\r\rextern "C" DllExport command_t* init_command(InspIRCd* Instance)\r{\r      return new cmd_whois(Instance);\r}\r\rCmdResult cmd_whois::Handle (const char** parameters, int pcnt, userrec *user)\r{\r    userrec *dest;\r int userindex = 0;\r     unsigned long idle = 0, signon = 0;\r\r   if (ServerInstance->Parser->LoopCall(user, this, parameters, pcnt, 0))\r         return CMD_SUCCESS;\r\r\r  /*\r      * If 2 paramters are specified (/whois nick nick), ignore the first one like spanningtree\r      * does, and use the second one, otherwise, use the only paramter. -- djGrrr\r    */\r    if (pcnt > 1)\r          userindex = 1;\r\r        dest = ServerInstance->FindNick(parameters[userindex]);\r\r       if (dest)\r      {\r              /*\r              * Okay. Umpteenth attempt at doing this, so let's re-comment...\r                * For local users (/w localuser), we show idletime if hidewhois is disabled\r            * For local users (/w localuser localuser), we always show idletime, hence pcnt > 1 check.\r             * For remote users (/w remoteuser), we do NOT show idletime\r            * For remote users (/w remoteuser remoteuser), spanningtree will handle calling do_whois, so we can ignore this case.\r          * Thanks to djGrrr for not being impatient while I have a crap day coding. :p -- w00t\r          */\r            if (IS_LOCAL(dest) && (!*ServerInstance->Config->HideWhoisServer || pcnt > 1))\r         {\r                      idle = abs((dest->idle_lastmsg)-ServerInstance->Time());\r                       signon = dest->signon;\r         }\r\r             do_whois(this->ServerInstance, user,dest,signon,idle,parameters[userindex]);\r   }\r      else\r   {\r              /* no such nick/channel */\r             user->WriteServ("401 %s %s :No such nick/channel",user->nick, *parameters[userindex] ? parameters[userindex] : "*");\r           user->WriteServ("318 %s %s :End of /WHOIS list.",user->nick, *parameters[userindex] ? parameters[userindex] : "*");\r            return CMD_FAILURE;\r    }\r\r     return CMD_SUCCESS;\r}\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "configreader.h"
+#include "users.h"
+#include "modules.h"
+#include "commands/cmd_whois.h"
+#include "hashcomp.h"
+
+void do_whois(InspIRCd* ServerInstance, userrec* user, userrec* dest,unsigned long signon, unsigned long idle, const char* nick)
+{
+       if (dest->Visibility && !dest->Visibility->VisibleTo(user))
+       {
+               ServerInstance->SendWhoisLine(user, dest, 401, "%s %s :No such nick/channel",user->nick, *nick ? nick : "*");
+               ServerInstance->SendWhoisLine(user, dest, 318, "%s %s :End of /WHOIS list.",user->nick, *nick ? nick : "*");
+               return;
+       }
+
+       if (dest->registered == REG_ALL)
+       {
+               ServerInstance->SendWhoisLine(user, dest, 311, "%s %s %s %s * :%s",user->nick, dest->nick, dest->ident, dest->dhost, dest->fullname);
+               if (user == dest || IS_OPER(user))
+               {
+                       ServerInstance->SendWhoisLine(user, dest, 378, "%s %s :is connecting from %s@%s %s", user->nick, dest->nick, dest->ident, dest->host, dest->GetIPString());
+               }
+
+               std::string cl = dest->ChannelList(user);
+
+               if (cl.length())
+               {
+                       if (cl.length() > 400)
+                       {
+                               user->SplitChanList(dest,cl);
+                       }
+                       else
+                       {
+                               ServerInstance->SendWhoisLine(user, dest, 319, "%s %s :%s",user->nick, dest->nick, cl.c_str());
+                       }
+               }
+               if (*ServerInstance->Config->HideWhoisServer && !IS_OPER(user))
+               {
+                       ServerInstance->SendWhoisLine(user, dest, 312, "%s %s %s :%s",user->nick, dest->nick, ServerInstance->Config->HideWhoisServer, ServerInstance->Config->Network);
+               }
+               else
+               {
+                       ServerInstance->SendWhoisLine(user, dest, 312, "%s %s %s :%s",user->nick, dest->nick, dest->server, ServerInstance->GetServerDescription(dest->server).c_str());
+               }
+
+               if (IS_AWAY(dest))
+               {
+                       ServerInstance->SendWhoisLine(user, dest, 301, "%s %s :%s",user->nick, dest->nick, dest->awaymsg);
+               }
+
+               if (IS_OPER(dest))
+               {
+                       ServerInstance->SendWhoisLine(user, dest, 313, "%s %s :is %s %s on %s",user->nick, dest->nick, (strchr("AEIOUaeiou",*dest->oper) ? "an" : "a"),irc::Spacify(dest->oper), ServerInstance->Config->Network);
+               }
+
+               FOREACH_MOD(I_OnWhois,OnWhois(user,dest));
+
+               /*
+                * We only send these if we've been provided them. That is, if hidewhois is turned off, and user is local, or
+                * if remote whois is queried, too. This is to keep the user hidden, and also since you can't reliably tell remote time. -- w00t
+                */
+               if ((idle) || (signon))
+               {
+                       ServerInstance->SendWhoisLine(user, dest, 317, "%s %s %d %d :seconds idle, signon time",user->nick, dest->nick, idle, signon);
+               }
+
+               ServerInstance->SendWhoisLine(user, dest, 318, "%s %s :End of /WHOIS list.",user->nick, dest->nick);
+       }
+       else
+       {
+               ServerInstance->SendWhoisLine(user, dest, 401, "%s %s :No such nick/channel",user->nick, *nick ? nick : "*");
+               ServerInstance->SendWhoisLine(user, dest, 318, "%s %s :End of /WHOIS list.",user->nick, *nick ? nick : "*");
+       }
+}
+
+
+
+extern "C" DllExport command_t* init_command(InspIRCd* Instance)
+{
+       return new cmd_whois(Instance);
+}
+
+CmdResult cmd_whois::Handle (const char** parameters, int pcnt, userrec *user)
+{
+       userrec *dest;
+       int userindex = 0;
+       unsigned long idle = 0, signon = 0;
+
+       if (ServerInstance->Parser->LoopCall(user, this, parameters, pcnt, 0))
+               return CMD_SUCCESS;
+
+
+       /*
+        * If 2 paramters are specified (/whois nick nick), ignore the first one like spanningtree
+        * does, and use the second one, otherwise, use the only paramter. -- djGrrr
+        */
+       if (pcnt > 1)
+               userindex = 1;
+
+       dest = ServerInstance->FindNick(parameters[userindex]);
+
+       if (dest)
+       {
+               /*
+                * Okay. Umpteenth attempt at doing this, so let's re-comment...
+                * For local users (/w localuser), we show idletime if hidewhois is disabled
+                * For local users (/w localuser localuser), we always show idletime, hence pcnt > 1 check.
+                * For remote users (/w remoteuser), we do NOT show idletime
+                * For remote users (/w remoteuser remoteuser), spanningtree will handle calling do_whois, so we can ignore this case.
+                * Thanks to djGrrr for not being impatient while I have a crap day coding. :p -- w00t
+                */
+               if (IS_LOCAL(dest) && (!*ServerInstance->Config->HideWhoisServer || pcnt > 1))
+               {
+                       idle = abs((dest->idle_lastmsg)-ServerInstance->Time());
+                       signon = dest->signon;
+               }
+
+               do_whois(this->ServerInstance, user,dest,signon,idle,parameters[userindex]);
+       }
+       else
+       {
+               /* no such nick/channel */
+               user->WriteServ("401 %s %s :No such nick/channel",user->nick, *parameters[userindex] ? parameters[userindex] : "*");
+               user->WriteServ("318 %s %s :End of /WHOIS list.",user->nick, *parameters[userindex] ? parameters[userindex] : "*");
+               return CMD_FAILURE;
+       }
+
+       return CMD_SUCCESS;
+}
+
index aab457243fdc5a653a2523abf2093a38519e689c..2d504c47c8f80af9a2fb67122d75ca9c419f14f1 100644 (file)
@@ -1 +1,341 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "configreader.h"\r#include "users.h"\r#include "commands/cmd_whowas.h"\r\rWhoWasMaintainTimer * timer;\r\rextern "C" DllExport command_t* init_command(InspIRCd* Instance)\r{\r     return new cmd_whowas(Instance);\r}\r\rcmd_whowas::cmd_whowas(InspIRCd* Instance)\r: command_t(Instance, "WHOWAS", 0, 1)\r{\r syntax = "<nick>{,<nick>}";\r    timer = new WhoWasMaintainTimer(Instance, 3600);\r       Instance->Timers->AddTimer(timer);\r}\r\rCmdResult cmd_whowas::Handle (const char** parameters, int pcnt, userrec* user)\r{\r        /* if whowas disabled in config */\r     if (ServerInstance->Config->WhoWasGroupSize == 0 || ServerInstance->Config->WhoWasMaxGroups == 0)\r      {\r              user->WriteServ("421 %s %s :This command has been disabled.",user->nick,command.c_str());\r              return CMD_FAILURE;\r    }\r\r     whowas_users::iterator i = whowas.find(parameters[0]);\r\r        if (i == whowas.end())\r {\r              user->WriteServ("406 %s %s :There was no such nickname",user->nick,parameters[0]);\r             user->WriteServ("369 %s %s :End of WHOWAS",user->nick,parameters[0]);\r          return CMD_FAILURE;\r    }\r      else\r   {\r              whowas_set* grp = i->second;\r           if (grp->size())\r               {\r                      for (whowas_set::iterator ux = grp->begin(); ux != grp->end(); ux++)\r                   {\r                              WhoWasGroup* u = *ux;\r                          time_t rawtime = u->signon;\r                            tm *timeinfo;\r                          char b[MAXBUF];\r        \r                               timeinfo = localtime(&rawtime);\r                                \r                               /* XXX - 'b' could be only 25 chars long and then strlcpy() would terminate it for us too? */\r                          strlcpy(b,asctime(timeinfo),MAXBUF);\r                           b[24] = 0;\r\r                            user->WriteServ("314 %s %s %s %s * :%s",user->nick,parameters[0],u->ident,u->dhost,u->gecos);\r                          \r                               if (IS_OPER(user))\r                                     user->WriteServ("379 %s %s :was connecting from *@%s", user->nick, parameters[0], u->host);\r                            \r                               if (*ServerInstance->Config->HideWhoisServer && !IS_OPER(user))\r                                        user->WriteServ("312 %s %s %s :%s",user->nick,parameters[0], ServerInstance->Config->HideWhoisServer, b);\r                              else\r                                   user->WriteServ("312 %s %s %s :%s",user->nick,parameters[0], u->server, b);\r                    }\r              }\r              else\r           {\r                      user->WriteServ("406 %s %s :There was no such nickname",user->nick,parameters[0]);\r                     user->WriteServ("369 %s %s :End of WHOWAS",user->nick,parameters[0]);\r                  return CMD_FAILURE;\r            }\r      }\r\r     user->WriteServ("369 %s %s :End of WHOWAS",user->nick,parameters[0]);\r  return CMD_SUCCESS;\r}\r\rCmdResult cmd_whowas::HandleInternal(const unsigned int id, const std::deque<classbase*> &parameters)\r{\r switch (id)\r    {\r              case WHOWAS_ADD:\r                       AddToWhoWas((userrec*)parameters[0]);\r          break;\r\r                case WHOWAS_STATS:\r                     GetStats((Extensible*)parameters[0]);\r          break;\r\r                case WHOWAS_PRUNE:\r                     PruneWhoWas(ServerInstance->Time());\r           break;\r\r                case WHOWAS_MAINTAIN:\r                  MaintainWhoWas(ServerInstance->Time());\r                break;\r\r                default:\r               break;\r }\r      return CMD_SUCCESS;\r}\r\rvoid cmd_whowas::GetStats(Extensible* ext)\r{\r    int whowas_size = 0;\r   int whowas_bytes = 0;\r  whowas_users_fifo::iterator iter;\r      for (iter = whowas_fifo.begin(); iter != whowas_fifo.end(); iter++)\r    {\r              whowas_set* n = (whowas_set*)whowas.find(iter->second)->second;\r                if (n->size())\r         {\r                      whowas_size += n->size();\r                      whowas_bytes += (sizeof(whowas_set) + ( sizeof(WhoWasGroup) * n->size() ) );\r           }\r      }\r      stats.assign("Whowas(MAPSETS) " +ConvToStr(whowas_size)+" ("+ConvToStr(whowas_bytes)+" bytes)");\r       ext->Extend("stats", stats.c_str());\r}\r\rvoid cmd_whowas::AddToWhoWas(userrec* user)\r{\r  /* if whowas disabled */\r       if (ServerInstance->Config->WhoWasGroupSize == 0 || ServerInstance->Config->WhoWasMaxGroups == 0)\r      {\r              return;\r        }\r\r     whowas_users::iterator iter = whowas.find(user->nick);\r\r        if (iter == whowas.end())\r      {\r              whowas_set* n = new whowas_set;\r                WhoWasGroup *a = new WhoWasGroup(user);\r                n->push_back(a);\r               whowas[user->nick] = n;\r                whowas_fifo.push_back(std::make_pair(ServerInstance->Time(),user->nick));\r\r             if ((int)(whowas.size()) > ServerInstance->Config->WhoWasMaxGroups)\r            {\r                      whowas_users::iterator iter = whowas.find(whowas_fifo[0].second);\r                      if (iter != whowas.end())\r                      {\r                              whowas_set* n = (whowas_set*)iter->second;\r                             if (n->size())\r                         {\r                                      while (n->begin() != n->end())\r                                 {\r                                              WhoWasGroup *a = *(n->begin());\r                                                DELETE(a);\r                                             n->pop_front();\r                                        }\r                              }\r                              DELETE(n);\r                             whowas.erase(iter);\r                    }\r                      whowas_fifo.pop_front();\r               }\r      }\r      else\r   {\r              whowas_set* group = (whowas_set*)iter->second;\r         WhoWasGroup *a = new WhoWasGroup(user);\r                group->push_back(a);\r\r          if ((int)(group->size()) > ServerInstance->Config->WhoWasGroupSize)\r            {\r                      WhoWasGroup *a = (WhoWasGroup*)*(group->begin());\r                      DELETE(a);\r                     group->pop_front();\r            }\r      }\r}\r\r/* on rehash, refactor maps according to new conf values */\rvoid cmd_whowas::PruneWhoWas(time_t t)\r{\r      /* config values */\r    int groupsize = ServerInstance->Config->WhoWasGroupSize;\r       int maxgroups = ServerInstance->Config->WhoWasMaxGroups;\r       int maxkeep =   ServerInstance->Config->WhoWasMaxKeep;\r\r        /* first cut the list to new size (maxgroups) and also prune entries that are timed out. */\r    whowas_users::iterator iter;\r   int fifosize;\r  while ((fifosize = (int)whowas_fifo.size()) > 0)\r       {\r              if (fifosize > maxgroups || whowas_fifo[0].first < t - maxkeep)\r                {\r                      iter = whowas.find(whowas_fifo[0].second);\r                     /* hopefully redundant integrity check, but added while debugging r6216 */\r                     if (iter == whowas.end())\r                      {\r                              /* this should never happen, if it does maps are corrupt */\r                            ServerInstance->Log(DEFAULT, "BUG: Whowas maps got corrupted! (1)");\r                           return;\r                        }\r                      whowas_set* n = (whowas_set*)iter->second;\r                     if (n->size())\r                 {\r                              while (n->begin() != n->end())\r                         {\r                                      WhoWasGroup *a = *(n->begin());\r                                        DELETE(a);\r                                     n->pop_front();\r                                }\r                      }\r                      DELETE(n);\r                     whowas.erase(iter);\r                    whowas_fifo.pop_front();\r               }\r              else\r                   break;\r }\r\r     /* Then cut the whowas sets to new size (groupsize) */\r fifosize = (int)whowas_fifo.size();\r    for (int i = 0; i < fifosize; i++)\r     {\r              iter = whowas.find(whowas_fifo[0].second);\r             /* hopefully redundant integrity check, but added while debugging r6216 */\r             if (iter == whowas.end())\r              {\r                      /* this should never happen, if it does maps are corrupt */\r                    ServerInstance->Log(DEFAULT, "BUG: Whowas maps got corrupted! (2)");\r                   return;\r                }\r              whowas_set* n = (whowas_set*)iter->second;\r             if (n->size())\r         {\r                      int nickcount = n->size();\r                     while (n->begin() != n->end() && nickcount > groupsize)\r                        {\r                              WhoWasGroup *a = *(n->begin());\r                                DELETE(a);\r                             n->pop_front();\r                                nickcount--;\r                   }\r              }\r      }\r}\r\r/* call maintain once an hour to remove expired nicks */\rvoid cmd_whowas::MaintainWhoWas(time_t t)\r{\r      for (whowas_users::iterator iter = whowas.begin(); iter != whowas.end(); iter++)\r       {\r              whowas_set* n = (whowas_set*)iter->second;\r             if (n->size())\r         {\r                      while ((n->begin() != n->end()) && ((*n->begin())->signon < t - ServerInstance->Config->WhoWasMaxKeep))\r                        {\r                              WhoWasGroup *a = *(n->begin());\r                                DELETE(a);\r                             n->erase(n->begin());\r                  }\r              }\r      }\r}\r\rcmd_whowas::~cmd_whowas()\r{\r       if (timer)\r     {\r              ServerInstance->Timers->DelTimer(timer);\r       }\r\r     whowas_users::iterator iter;\r   int fifosize;\r  while ((fifosize = (int)whowas_fifo.size()) > 0)\r       {\r              iter = whowas.find(whowas_fifo[0].second);\r             /* hopefully redundant integrity check, but added while debugging r6216 */\r             if (iter == whowas.end())\r              {\r                      /* this should never happen, if it does maps are corrupt */\r                    ServerInstance->Log(DEFAULT, "BUG: Whowas maps got corrupted! (3)");\r                   return;\r                }\r              whowas_set* n = (whowas_set*)iter->second;\r             if (n->size())\r         {\r                      while (n->begin() != n->end())\r                 {\r                              WhoWasGroup *a = *(n->begin());\r                                DELETE(a);\r                             n->pop_front();\r                        }\r              }\r              DELETE(n);\r             whowas.erase(iter);\r            whowas_fifo.pop_front();\r       }\r}\r\rWhoWasGroup::WhoWasGroup(userrec* user) : host(NULL), dhost(NULL), ident(NULL), server(NULL), gecos(NULL), signon(user->signon)\r{\r this->host = strdup(user->host);\r       this->dhost = strdup(user->dhost);\r     this->ident = strdup(user->ident);\r     this->server = user->server;\r   this->gecos = strdup(user->fullname);\r}\r\rWhoWasGroup::~WhoWasGroup()\r{\r if (host)\r              free(host);\r    if (dhost)\r             free(dhost);\r   if (ident)\r             free(ident);\r   if (gecos)\r             free(gecos);\r}\r\r/* every hour, run this function which removes all entries older than Config->WhoWasMaxKeep */\rvoid WhoWasMaintainTimer::Tick(time_t t)\r{\r      command_t* whowas_command = ServerInstance->Parser->GetHandler("WHOWAS");\r      if (whowas_command)\r    {\r              std::deque<classbase*> params;\r         whowas_command->HandleInternal(WHOWAS_MAINTAIN, params);\r       }\r}\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "configreader.h"
+#include "users.h"
+#include "commands/cmd_whowas.h"
+
+WhoWasMaintainTimer * timer;
+
+extern "C" DllExport command_t* init_command(InspIRCd* Instance)
+{
+       return new cmd_whowas(Instance);
+}
+
+cmd_whowas::cmd_whowas(InspIRCd* Instance)
+: command_t(Instance, "WHOWAS", 0, 1)
+{
+       syntax = "<nick>{,<nick>}";
+       timer = new WhoWasMaintainTimer(Instance, 3600);
+       Instance->Timers->AddTimer(timer);
+}
+
+CmdResult cmd_whowas::Handle (const char** parameters, int pcnt, userrec* user)
+{
+       /* if whowas disabled in config */
+       if (ServerInstance->Config->WhoWasGroupSize == 0 || ServerInstance->Config->WhoWasMaxGroups == 0)
+       {
+               user->WriteServ("421 %s %s :This command has been disabled.",user->nick,command.c_str());
+               return CMD_FAILURE;
+       }
+
+       whowas_users::iterator i = whowas.find(parameters[0]);
+
+       if (i == whowas.end())
+       {
+               user->WriteServ("406 %s %s :There was no such nickname",user->nick,parameters[0]);
+               user->WriteServ("369 %s %s :End of WHOWAS",user->nick,parameters[0]);
+               return CMD_FAILURE;
+       }
+       else
+       {
+               whowas_set* grp = i->second;
+               if (grp->size())
+               {
+                       for (whowas_set::iterator ux = grp->begin(); ux != grp->end(); ux++)
+                       {
+                               WhoWasGroup* u = *ux;
+                               time_t rawtime = u->signon;
+                               tm *timeinfo;
+                               char b[MAXBUF];
+       
+                               timeinfo = localtime(&rawtime);
+                               
+                               /* XXX - 'b' could be only 25 chars long and then strlcpy() would terminate it for us too? */
+                               strlcpy(b,asctime(timeinfo),MAXBUF);
+                               b[24] = 0;
+
+                               user->WriteServ("314 %s %s %s %s * :%s",user->nick,parameters[0],u->ident,u->dhost,u->gecos);
+                               
+                               if (IS_OPER(user))
+                                       user->WriteServ("379 %s %s :was connecting from *@%s", user->nick, parameters[0], u->host);
+                               
+                               if (*ServerInstance->Config->HideWhoisServer && !IS_OPER(user))
+                                       user->WriteServ("312 %s %s %s :%s",user->nick,parameters[0], ServerInstance->Config->HideWhoisServer, b);
+                               else
+                                       user->WriteServ("312 %s %s %s :%s",user->nick,parameters[0], u->server, b);
+                       }
+               }
+               else
+               {
+                       user->WriteServ("406 %s %s :There was no such nickname",user->nick,parameters[0]);
+                       user->WriteServ("369 %s %s :End of WHOWAS",user->nick,parameters[0]);
+                       return CMD_FAILURE;
+               }
+       }
+
+       user->WriteServ("369 %s %s :End of WHOWAS",user->nick,parameters[0]);
+       return CMD_SUCCESS;
+}
+
+CmdResult cmd_whowas::HandleInternal(const unsigned int id, const std::deque<classbase*> &parameters)
+{
+       switch (id)
+       {
+               case WHOWAS_ADD:
+                       AddToWhoWas((userrec*)parameters[0]);
+               break;
+
+               case WHOWAS_STATS:
+                       GetStats((Extensible*)parameters[0]);
+               break;
+
+               case WHOWAS_PRUNE:
+                       PruneWhoWas(ServerInstance->Time());
+               break;
+
+               case WHOWAS_MAINTAIN:
+                       MaintainWhoWas(ServerInstance->Time());
+               break;
+
+               default:
+               break;
+       }
+       return CMD_SUCCESS;
+}
+
+void cmd_whowas::GetStats(Extensible* ext)
+{
+       int whowas_size = 0;
+       int whowas_bytes = 0;
+       whowas_users_fifo::iterator iter;
+       for (iter = whowas_fifo.begin(); iter != whowas_fifo.end(); iter++)
+       {
+               whowas_set* n = (whowas_set*)whowas.find(iter->second)->second;
+               if (n->size())
+               {
+                       whowas_size += n->size();
+                       whowas_bytes += (sizeof(whowas_set) + ( sizeof(WhoWasGroup) * n->size() ) );
+               }
+       }
+       stats.assign("Whowas(MAPSETS) " +ConvToStr(whowas_size)+" ("+ConvToStr(whowas_bytes)+" bytes)");
+       ext->Extend("stats", stats.c_str());
+}
+
+void cmd_whowas::AddToWhoWas(userrec* user)
+{
+       /* if whowas disabled */
+       if (ServerInstance->Config->WhoWasGroupSize == 0 || ServerInstance->Config->WhoWasMaxGroups == 0)
+       {
+               return;
+       }
+
+       whowas_users::iterator iter = whowas.find(user->nick);
+
+       if (iter == whowas.end())
+       {
+               whowas_set* n = new whowas_set;
+               WhoWasGroup *a = new WhoWasGroup(user);
+               n->push_back(a);
+               whowas[user->nick] = n;
+               whowas_fifo.push_back(std::make_pair(ServerInstance->Time(),user->nick));
+
+               if ((int)(whowas.size()) > ServerInstance->Config->WhoWasMaxGroups)
+               {
+                       whowas_users::iterator iter = whowas.find(whowas_fifo[0].second);
+                       if (iter != whowas.end())
+                       {
+                               whowas_set* n = (whowas_set*)iter->second;
+                               if (n->size())
+                               {
+                                       while (n->begin() != n->end())
+                                       {
+                                               WhoWasGroup *a = *(n->begin());
+                                               DELETE(a);
+                                               n->pop_front();
+                                       }
+                               }
+                               DELETE(n);
+                               whowas.erase(iter);
+                       }
+                       whowas_fifo.pop_front();
+               }
+       }
+       else
+       {
+               whowas_set* group = (whowas_set*)iter->second;
+               WhoWasGroup *a = new WhoWasGroup(user);
+               group->push_back(a);
+
+               if ((int)(group->size()) > ServerInstance->Config->WhoWasGroupSize)
+               {
+                       WhoWasGroup *a = (WhoWasGroup*)*(group->begin());
+                       DELETE(a);
+                       group->pop_front();
+               }
+       }
+}
+
+/* on rehash, refactor maps according to new conf values */
+void cmd_whowas::PruneWhoWas(time_t t)
+{
+       /* config values */
+       int groupsize = ServerInstance->Config->WhoWasGroupSize;
+       int maxgroups = ServerInstance->Config->WhoWasMaxGroups;
+       int maxkeep =   ServerInstance->Config->WhoWasMaxKeep;
+
+       /* first cut the list to new size (maxgroups) and also prune entries that are timed out. */
+       whowas_users::iterator iter;
+       int fifosize;
+       while ((fifosize = (int)whowas_fifo.size()) > 0)
+       {
+               if (fifosize > maxgroups || whowas_fifo[0].first < t - maxkeep)
+               {
+                       iter = whowas.find(whowas_fifo[0].second);
+                       /* hopefully redundant integrity check, but added while debugging r6216 */
+                       if (iter == whowas.end())
+                       {
+                               /* this should never happen, if it does maps are corrupt */
+                               ServerInstance->Log(DEFAULT, "BUG: Whowas maps got corrupted! (1)");
+                               return;
+                       }
+                       whowas_set* n = (whowas_set*)iter->second;
+                       if (n->size())
+                       {
+                               while (n->begin() != n->end())
+                               {
+                                       WhoWasGroup *a = *(n->begin());
+                                       DELETE(a);
+                                       n->pop_front();
+                               }
+                       }
+                       DELETE(n);
+                       whowas.erase(iter);
+                       whowas_fifo.pop_front();
+               }
+               else
+                       break;
+       }
+
+       /* Then cut the whowas sets to new size (groupsize) */
+       fifosize = (int)whowas_fifo.size();
+       for (int i = 0; i < fifosize; i++)
+       {
+               iter = whowas.find(whowas_fifo[0].second);
+               /* hopefully redundant integrity check, but added while debugging r6216 */
+               if (iter == whowas.end())
+               {
+                       /* this should never happen, if it does maps are corrupt */
+                       ServerInstance->Log(DEFAULT, "BUG: Whowas maps got corrupted! (2)");
+                       return;
+               }
+               whowas_set* n = (whowas_set*)iter->second;
+               if (n->size())
+               {
+                       int nickcount = n->size();
+                       while (n->begin() != n->end() && nickcount > groupsize)
+                       {
+                               WhoWasGroup *a = *(n->begin());
+                               DELETE(a);
+                               n->pop_front();
+                               nickcount--;
+                       }
+               }
+       }
+}
+
+/* call maintain once an hour to remove expired nicks */
+void cmd_whowas::MaintainWhoWas(time_t t)
+{
+       for (whowas_users::iterator iter = whowas.begin(); iter != whowas.end(); iter++)
+       {
+               whowas_set* n = (whowas_set*)iter->second;
+               if (n->size())
+               {
+                       while ((n->begin() != n->end()) && ((*n->begin())->signon < t - ServerInstance->Config->WhoWasMaxKeep))
+                       {
+                               WhoWasGroup *a = *(n->begin());
+                               DELETE(a);
+                               n->erase(n->begin());
+                       }
+               }
+       }
+}
+
+cmd_whowas::~cmd_whowas()
+{
+       if (timer)
+       {
+               ServerInstance->Timers->DelTimer(timer);
+       }
+
+       whowas_users::iterator iter;
+       int fifosize;
+       while ((fifosize = (int)whowas_fifo.size()) > 0)
+       {
+               iter = whowas.find(whowas_fifo[0].second);
+               /* hopefully redundant integrity check, but added while debugging r6216 */
+               if (iter == whowas.end())
+               {
+                       /* this should never happen, if it does maps are corrupt */
+                       ServerInstance->Log(DEFAULT, "BUG: Whowas maps got corrupted! (3)");
+                       return;
+               }
+               whowas_set* n = (whowas_set*)iter->second;
+               if (n->size())
+               {
+                       while (n->begin() != n->end())
+                       {
+                               WhoWasGroup *a = *(n->begin());
+                               DELETE(a);
+                               n->pop_front();
+                       }
+               }
+               DELETE(n);
+               whowas.erase(iter);
+               whowas_fifo.pop_front();
+       }
+}
+
+WhoWasGroup::WhoWasGroup(userrec* user) : host(NULL), dhost(NULL), ident(NULL), server(NULL), gecos(NULL), signon(user->signon)
+{
+       this->host = strdup(user->host);
+       this->dhost = strdup(user->dhost);
+       this->ident = strdup(user->ident);
+       this->server = user->server;
+       this->gecos = strdup(user->fullname);
+}
+
+WhoWasGroup::~WhoWasGroup()
+{
+       if (host)
+               free(host);
+       if (dhost)
+               free(dhost);
+       if (ident)
+               free(ident);
+       if (gecos)
+               free(gecos);
+}
+
+/* every hour, run this function which removes all entries older than Config->WhoWasMaxKeep */
+void WhoWasMaintainTimer::Tick(time_t t)
+{
+       command_t* whowas_command = ServerInstance->Parser->GetHandler("WHOWAS");
+       if (whowas_command)
+       {
+               std::deque<classbase*> params;
+               whowas_command->HandleInternal(WHOWAS_MAINTAIN, params);
+       }
+}
index 43a0fd0428b6c7a00494b9281319aad621d3a24f..8fea70656e550cd825cad7a4b5ce5cb500ce4293 100644 (file)
@@ -1 +1,80 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "configreader.h"\r#include "users.h"\r#include "modules.h"\r#include "xline.h"\r#include "commands/cmd_zline.h"\r\r\r\rextern "C" DllExport command_t* init_command(InspIRCd* Instance)\r{\r  return new cmd_zline(Instance);\r}\r\rCmdResult cmd_zline::Handle (const char** parameters, int pcnt, userrec *user)\r{\r    if (pcnt >= 3)\r {\r              if (strchr(parameters[0],'@') || strchr(parameters[0],'!'))\r            {\r                      user->WriteServ("NOTICE %s :*** You cannot include a username or nickname in a zline, a zline must ban only an IP mask",user->nick);\r                   return CMD_FAILURE;\r            }\r\r             if (ServerInstance->IPMatchesEveryone(parameters[0],user))\r                     return CMD_FAILURE;\r\r           long duration = ServerInstance->Duration(parameters[1]);\r               if (ServerInstance->XLines->add_zline(duration,user->nick,parameters[2],parameters[0]))\r                {\r                      int to_apply = APPLY_ZLINES;\r\r                  FOREACH_MOD(I_OnAddZLine,OnAddZLine(duration, user, parameters[2], parameters[0]));\r                    if (!duration)\r                 {\r                              to_apply |= APPLY_PERM_ONLY;\r                           ServerInstance->SNO->WriteToSnoMask('x',"%s added permanent Z-line for %s.",user->nick,parameters[0]);\r                 }\r                      else\r                   {\r                              time_t c_requires_crap = duration + ServerInstance->Time();\r                            ServerInstance->SNO->WriteToSnoMask('x',"%s added timed Z-line for %s, expires on %s",user->nick,parameters[0],\r                                                ServerInstance->TimeString(c_requires_crap).c_str());\r                  }\r                      ServerInstance->XLines->apply_lines(to_apply);\r         }\r              else\r           {\r                      user->WriteServ("NOTICE %s :*** Z-Line for %s already exists",user->nick,parameters[0]);\r               }\r      }\r      else\r   {\r              if (ServerInstance->XLines->del_zline(parameters[0]))\r          {\r                      FOREACH_MOD(I_OnDelZLine,OnDelZLine(user, parameters[0]));\r                     ServerInstance->SNO->WriteToSnoMask('x',"%s Removed Z-line on %s.",user->nick,parameters[0]);\r          }\r              else\r           {\r                      user->WriteServ("NOTICE %s :*** Z-Line %s not found in list, try /stats Z.",user->nick,parameters[0]);\r                 return CMD_FAILURE;\r            }\r      }\r\r     return CMD_SUCCESS;\r}\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "configreader.h"
+#include "users.h"
+#include "modules.h"
+#include "xline.h"
+#include "commands/cmd_zline.h"
+
+
+
+extern "C" DllExport command_t* init_command(InspIRCd* Instance)
+{
+       return new cmd_zline(Instance);
+}
+
+CmdResult cmd_zline::Handle (const char** parameters, int pcnt, userrec *user)
+{
+       if (pcnt >= 3)
+       {
+               if (strchr(parameters[0],'@') || strchr(parameters[0],'!'))
+               {
+                       user->WriteServ("NOTICE %s :*** You cannot include a username or nickname in a zline, a zline must ban only an IP mask",user->nick);
+                       return CMD_FAILURE;
+               }
+
+               if (ServerInstance->IPMatchesEveryone(parameters[0],user))
+                       return CMD_FAILURE;
+
+               long duration = ServerInstance->Duration(parameters[1]);
+               if (ServerInstance->XLines->add_zline(duration,user->nick,parameters[2],parameters[0]))
+               {
+                       int to_apply = APPLY_ZLINES;
+
+                       FOREACH_MOD(I_OnAddZLine,OnAddZLine(duration, user, parameters[2], parameters[0]));
+                       if (!duration)
+                       {
+                               to_apply |= APPLY_PERM_ONLY;
+                               ServerInstance->SNO->WriteToSnoMask('x',"%s added permanent Z-line for %s.",user->nick,parameters[0]);
+                       }
+                       else
+                       {
+                               time_t c_requires_crap = duration + ServerInstance->Time();
+                               ServerInstance->SNO->WriteToSnoMask('x',"%s added timed Z-line for %s, expires on %s",user->nick,parameters[0],
+                                               ServerInstance->TimeString(c_requires_crap).c_str());
+                       }
+                       ServerInstance->XLines->apply_lines(to_apply);
+               }
+               else
+               {
+                       user->WriteServ("NOTICE %s :*** Z-Line for %s already exists",user->nick,parameters[0]);
+               }
+       }
+       else
+       {
+               if (ServerInstance->XLines->del_zline(parameters[0]))
+               {
+                       FOREACH_MOD(I_OnDelZLine,OnDelZLine(user, parameters[0]));
+                       ServerInstance->SNO->WriteToSnoMask('x',"%s Removed Z-line on %s.",user->nick,parameters[0]);
+               }
+               else
+               {
+                       user->WriteServ("NOTICE %s :*** Z-Line %s not found in list, try /stats Z.",user->nick,parameters[0]);
+                       return CMD_FAILURE;
+               }
+       }
+
+       return CMD_SUCCESS;
+}
index bf2e61ce974c8f4d79a4dde41d43a0a6e57bf23a..52c58ef999aba743e78506101cd314538479aea6 100644 (file)
@@ -1 +1,563 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "configreader.h"\r#include <algorithm>\r#include "users.h"\r#include "modules.h"\r#include "wildcard.h"\r#include "xline.h"\r#include "socketengine.h"\r#include "socket.h"\r#include "command_parse.h"\r\r/* Directory Searching for Unix-Only */\r#ifndef WIN32\r#include <dirent.h>\r#include <dlfcn.h>\r#endif\r\rbool InspIRCd::ULine(const char* server)\r{\r   if (!server)\r           return false;\r  if (!*server)\r          return true;\r\r  return (Config->ulines.find(server) != Config->ulines.end());\r}\r\rbool InspIRCd::SilentULine(const char* server)\r{\r      std::map<irc::string,bool>::iterator n = Config->ulines.find(server);\r  if (n != Config->ulines.end())\r         return n->second;\r      else return false;\r}\r\rint InspIRCd::OperPassCompare(const char* data,const char* input, int tagnumber)\r{\r       int MOD_RESULT = 0;\r    FOREACH_RESULT_I(this,I_OnOperCompare,OnOperCompare(data, input, tagnumber))\r   if (MOD_RESULT == 1)\r           return 0;\r      if (MOD_RESULT == -1)\r          return 1;\r      return strcmp(data,input);\r}\r\rstd::string InspIRCd::TimeString(time_t curtime)\r{\r       return std::string(ctime(&curtime),24);\r}\r\r/** Refactored by Brain, Jun 2007. Much faster with some clever O(1) array\r * lookups and pointer maths.\r */\rlong InspIRCd::Duration(const std::string &str)\r{\r      unsigned char multiplier = 0;\r  long total = 0;\r        long times = 1;\r        long subtotal = 0;\r\r    /* Iterate each item in the string, looking for number or multiplier */\r        for (std::string::const_reverse_iterator i = str.rbegin(); i != str.rend(); ++i)\r       {\r              /* Found a number, queue it onto the current number */\r         if ((*i >= '0') && (*i <= '9'))\r                {\r                      subtotal = subtotal + ((*i - '0') * times);\r                    times = times * 10;\r            }\r              else\r           {\r                      /* Found something thats not a number, find out how much\r                        * it multiplies the built up number by, multiply the total\r                     * and reset the built up number.\r                       */\r                    if (subtotal)\r                          total += subtotal * duration_multi[multiplier];\r\r                       /* Next subtotal please */\r                     subtotal = 0;\r                  multiplier = *i;\r                       times = 1;\r             }\r      }\r      if (multiplier)\r        {\r              total += subtotal * duration_multi[multiplier];\r                subtotal = 0;\r  }\r      /* Any trailing values built up are treated as raw seconds */\r  return total + subtotal;\r}\r\r/* LoopCall is used to call a command classes handler repeatedly based on the contents of a comma seperated list.\r * There are two overriden versions of this method, one of which takes two potential lists and the other takes one.\r * We need a version which takes two potential lists for JOIN, because a JOIN may contain two lists of items at once,\r * the channel names and their keys as follows:\r * JOIN #chan1,#chan2,#chan3 key1,,key3\r * Therefore, we need to deal with both lists concurrently. The first instance of this method does that by creating\r * two instances of irc::commasepstream and reading them both together until the first runs out of tokens.\r * The second version is much simpler and just has the one stream to read, and is used in NAMES, WHOIS, PRIVMSG etc.\r * Both will only parse until they reach ServerInstance->Config->MaxTargets number of targets, to stop abuse via spam.\r */\rint CommandParser::LoopCall(userrec* user, command_t* CommandObj, const char** parameters, int pcnt, unsigned int splithere, unsigned int extra)\r{\r      /* First check if we have more than one item in the list, if we don't we return zero here and the handler\r       * which called us just carries on as it was.\r   */\r    if (!strchr(parameters[splithere],','))\r                return 0;\r\r     /** Some lame ircds will weed out dupes using some shitty O(n^2) algorithm.\r     * By using std::map (thanks for the idea w00t) we can cut this down a ton.\r     * ...VOOODOOOO!\r        */\r    std::map<irc::string, bool> dupes;\r\r    /* Create two lists, one for channel names, one for keys\r        */\r    irc::commasepstream items1(parameters[splithere]);\r     irc::commasepstream items2(parameters[extra]);\r std::string item("*");\r unsigned int max = 0;\r\r /* Attempt to iterate these lists and call the command objech\r   * which called us, for every parameter pair until there are\r    * no more left to parse.\r       */\r    while (((item = items1.GetToken()) != "") && (max++ < ServerInstance->Config->MaxTargets))\r     {\r              if (dupes.find(item.c_str()) == dupes.end())\r           {\r                      const char* new_parameters[127];\r\r                      for (int t = 0; (t < pcnt) && (t < 127); t++)\r                          new_parameters[t] = parameters[t];\r\r                    std::string extrastuff = items2.GetToken();\r\r                   new_parameters[splithere] = item.c_str();\r                      new_parameters[extra] = extrastuff.c_str();\r\r                   CommandObj->Handle(new_parameters,pcnt,user);\r\r                 dupes[item.c_str()] = true;\r            }\r      }\r      return 1;\r}\r\rint CommandParser::LoopCall(userrec* user, command_t* CommandObj, const char** parameters, int pcnt, unsigned int splithere)\r{\r    /* First check if we have more than one item in the list, if we don't we return zero here and the handler\r       * which called us just carries on as it was.\r   */\r    if (!strchr(parameters[splithere],','))\r                return 0;\r\r     std::map<irc::string, bool> dupes;\r\r    /* Only one commasepstream here */\r     irc::commasepstream items1(parameters[splithere]);\r     std::string item("*");\r unsigned int max = 0;\r\r /* Parse the commasepstream until there are no tokens remaining.\r        * Each token we parse out, call the command handler that called us\r     * with it\r      */\r    while (((item = items1.GetToken()) != "") && (max++ < ServerInstance->Config->MaxTargets))\r     {\r              if (dupes.find(item.c_str()) == dupes.end())\r           {\r                      const char* new_parameters[127];\r\r                      for (int t = 0; (t < pcnt) && (t < 127); t++)\r                          new_parameters[t] = parameters[t];\r\r                    new_parameters[splithere] = item.c_str();\r\r                     parameters[splithere] = item.c_str();\r\r                 /* Execute the command handler over and over. If someone pulls our user\r                         * record out from under us (e.g. if we /kill a comma sep list, and we're\r                       * in that list ourselves) abort if we're gone.\r                         */\r                    CommandObj->Handle(new_parameters,pcnt,user);\r\r                 dupes[item.c_str()] = true;\r            }\r      }\r      /* By returning 1 we tell our caller that nothing is to be done,\r        * as all the previous calls handled the data. This makes the parent\r    * return without doing any processing.\r         */\r    return 1;\r}\r\rbool CommandParser::IsValidCommand(const std::string &commandname, int pcnt, userrec * user)\r{\r    command_table::iterator n = cmdlist.find(commandname);\r\r        if (n != cmdlist.end())\r        {\r              if ((pcnt>=n->second->min_params) && (n->second->source != "<core>"))\r          {\r                      if ((!n->second->flags_needed) || (user->modes[n->second->flags_needed-65]))\r                   {\r                              if (n->second->flags_needed)\r                           {\r                                      return ((user->HasPermission(commandname)) || (ServerInstance->ULine(user->server)));\r                          }\r                              return true;\r                   }\r              }\r      }\r      return false;\r}\r\rcommand_t* CommandParser::GetHandler(const std::string &commandname)\r{\r        command_table::iterator n = cmdlist.find(commandname);\r if (n != cmdlist.end())\r                return n->second;\r\r     return NULL;\r}\r\r// calls a handler function for a command\r\rCmdResult CommandParser::CallHandler(const std::string &commandname,const char** parameters, int pcnt, userrec *user)\r{\r     command_table::iterator n = cmdlist.find(commandname);\r\r        if (n != cmdlist.end())\r        {\r              if (pcnt >= n->second->min_params)\r             {\r                      if ((!n->second->flags_needed) || (user->modes[n->second->flags_needed-65]))\r                   {\r                              if (n->second->flags_needed)\r                           {\r                                      if ((user->HasPermission(commandname)) || (!IS_LOCAL(user)))\r                                   {\r                                              return n->second->Handle(parameters,pcnt,user);\r                                        }\r                              }\r                              else\r                           {\r                                      return n->second->Handle(parameters,pcnt,user);\r                                }\r                      }\r              }\r      }\r      return CMD_INVALID;\r}\r\rvoid CommandParser::ProcessCommand(userrec *user, std::string &cmd)\r{\r   const char *command_p[127];\r    int items = 0;\r irc::tokenstream tokens(cmd);\r  std::string command;\r   tokens.GetToken(command);\r\r     /* A client sent a nick prefix on their command (ick)\r   * rhapsody and some braindead bouncers do this --\r      * the rfc says they shouldnt but also says the ircd should\r     * discard it if they do.\r       */\r    if (*command.c_str() == ':')\r           tokens.GetToken(command);\r\r     while (tokens.GetToken(para[items]) && (items < 127))\r  {\r              command_p[items] = para[items].c_str();\r                items++;\r       }\r\r     std::transform(command.begin(), command.end(), command.begin(), ::toupper);\r            \r       int MOD_RESULT = 0;\r    FOREACH_RESULT(I_OnPreCommand,OnPreCommand(command,command_p,items,user,false,cmd));\r   if (MOD_RESULT == 1) {\r         return;\r        }\r\r     command_table::iterator cm = cmdlist.find(command);\r    \r       if (cm != cmdlist.end())\r       {\r              if (user)\r              {\r                      /* activity resets the ping pending timer */\r                   user->nping = ServerInstance->Time() + user->pingmax;\r                  if (cm->second->flags_needed)\r                  {\r                              if (!user->IsModeSet(cm->second->flags_needed))\r                                {\r                                      user->WriteServ("481 %s :Permission Denied - You do not have the required operator privileges",user->nick);\r                                    return;\r                                }\r                              if (!user->HasPermission(command))\r                             {\r                                      user->WriteServ("481 %s :Permission Denied - Oper type %s does not have access to command %s",user->nick,user->oper,command.c_str());\r                                  return;\r                                }\r                      }\r                      if ((user->registered == REG_ALL) && (!IS_OPER(user)) && (cm->second->IsDisabled()))\r                   {\r                              /* command is disabled! */\r                             user->WriteServ("421 %s %s :This command has been disabled.",user->nick,command.c_str());\r                              return;\r                        }\r                      if (items < cm->second->min_params)\r                    {\r                              user->WriteServ("461 %s %s :Not enough parameters.", user->nick, command.c_str());\r                             /* If syntax is given, display this as the 461 reply */\r                                if ((ServerInstance->Config->SyntaxHints) && (user->registered == REG_ALL) && (cm->second->syntax.length()))\r                                   user->WriteServ("304 %s :SYNTAX %s %s", user->nick, cm->second->command.c_str(), cm->second->syntax.c_str());\r                          return;\r                        }\r                      if ((user->registered == REG_ALL) || (cm->second->WorksBeforeReg()))\r                   {\r                              /* ikky /stats counters */\r                             cm->second->use_count++;\r                               cm->second->total_bytes += cmd.length();\r\r                              int MOD_RESULT = 0;\r                            FOREACH_RESULT(I_OnPreCommand,OnPreCommand(command,command_p,items,user,true,cmd));\r                            if (MOD_RESULT == 1)\r                                   return;\r\r                               /*\r                              * WARNING: nothing may come after the\r                          * command handler call, as the handler\r                                 * may free the user structure!\r                                 */\r                            CmdResult result = cm->second->Handle(command_p,items,user);\r\r                          FOREACH_MOD(I_OnPostCommand,OnPostCommand(command, command_p, items, user, result,cmd));\r                               return;\r                        }\r                      else\r                   {\r                              user->WriteServ("451 %s :You have not registered",command.c_str());\r                            return;\r                        }\r              }\r      }\r      else if (user)\r {\r              ServerInstance->stats->statsUnknown++;\r         user->WriteServ("421 %s %s :Unknown command",user->nick,command.c_str());\r      }\r}\r\rbool CommandParser::RemoveCommands(const char* source)\r{\r  command_table::iterator i,safei;\r       for (i = cmdlist.begin(); i != cmdlist.end(); i++)\r     {\r              safei = i;\r             safei++;\r               if (safei != cmdlist.end())\r            {\r                      RemoveCommand(safei, source);\r          }\r      }\r      safei = cmdlist.begin();\r       if (safei != cmdlist.end())\r    {\r              RemoveCommand(safei, source);\r  }\r      return true;\r}\r\rvoid CommandParser::RemoveCommand(command_table::iterator safei, const char* source)\r{\r command_t* x = safei->second;\r  if (x->source == std::string(source))\r  {\r              cmdlist.erase(safei);\r          delete x;\r      }\r}\r\rvoid CommandParser::ProcessBuffer(std::string &buffer,userrec *user)\r{\r    std::string::size_type a;\r\r     if (!user)\r             return;\r\r       while ((a = buffer.rfind("\n")) != std::string::npos)\r          buffer.erase(a);\r       while ((a = buffer.rfind("\r")) != std::string::npos)\r          buffer.erase(a);\r\r      if (buffer.length())\r   {\r              if (!user->muted)\r              {\r                      ServerInstance->Log(DEBUG,"C[%d] -> :%s %s",user->GetFd(), user->nick, buffer.c_str());\r                        this->ProcessCommand(user,buffer);\r             }\r      }\r}\r\rbool CommandParser::CreateCommand(command_t *f, void* so_handle)\r{\r        if (so_handle)\r {\r              if (RFCCommands.find(f->command) == RFCCommands.end())\r                 RFCCommands[f->command] = so_handle;\r           else\r           {\r                      ServerInstance->Log(DEFAULT,"ERK! Somehow, we loaded a cmd_*.so file twice! Only the first instance is being recorded.");\r                      return false;\r          }\r      }\r\r     /* create the command and push it onto the table */\r    if (cmdlist.find(f->command) == cmdlist.end())\r {\r              cmdlist[f->command] = f;\r               return true;\r   }\r      else return false;\r}\r\rCommandParser::CommandParser(InspIRCd* Instance) : ServerInstance(Instance)\r{\r    para.resize(128);\r      this->SetupCommandTable();\r}\r\rbool CommandParser::FindSym(void** v, void* h)\r{\r *v = dlsym(h, "init_command");\r const char* err = dlerror();\r   if (err && !(*v))\r      {\r              ServerInstance->Log(SPARSE, "Error loading core command: %s\n", err);\r          return false;\r  }\r      return true;\r}\r\rbool CommandParser::ReloadCommand(const char* cmd)\r{\r   char filename[MAXBUF];\r char commandname[MAXBUF];\r      int y = 0;\r\r    for (const char* x = cmd; *x; x++, y++)\r                commandname[y] = toupper(*x);\r\r commandname[y] = 0;\r\r   SharedObjectList::iterator command = RFCCommands.find(commandname);\r\r   if (command != RFCCommands.end())\r      {\r              command_t* cmdptr = cmdlist.find(commandname)->second;\r         cmdlist.erase(cmdlist.find(commandname));\r\r             for (char* x = commandname; *x; x++)\r                   *x = tolower(*x);\r\r\r            delete cmdptr;\r         dlclose(command->second);\r              RFCCommands.erase(command);\r\r           snprintf(filename, MAXBUF, "cmd_%s.so", commandname);\r          this->LoadCommand(filename);\r\r          return true;\r   }\r\r     return false;\r}\r\rCmdResult cmd_reload::Handle(const char** parameters, int pcnt, userrec *user)\r{\r      user->WriteServ("NOTICE %s :*** Reloading command '%s'",user->nick, parameters[0]);\r    if (ServerInstance->Parser->ReloadCommand(parameters[0]))\r      {\r              user->WriteServ("NOTICE %s :*** Successfully reloaded command '%s'", user->nick, parameters[0]);\r               ServerInstance->WriteOpers("*** RELOAD: %s reloaded the '%s' command.", user->nick, parameters[0]);\r            return CMD_SUCCESS;\r    }\r      else\r   {\r              user->WriteServ("NOTICE %s :*** Could not reload command '%s'", user->nick, parameters[0]);\r            return CMD_FAILURE;\r    }\r}\r\rvoid CommandParser::LoadCommand(const char* name)\r{\r       char filename[MAXBUF];\r void* h;\r       command_t* (*cmd_factory_func)(InspIRCd*);\r\r    snprintf(filename, MAXBUF, "%s/%s", LIBRARYDIR, name);\r h = dlopen(filename, RTLD_NOW | RTLD_GLOBAL);\r\r if (!h)\r        {\r              ServerInstance->Log(SPARSE, "Error loading core command: %s", dlerror());\r              return;\r        }\r\r     if (this->FindSym((void **)&cmd_factory_func, h))\r      {\r              command_t* newcommand = cmd_factory_func(ServerInstance);\r              this->CreateCommand(newcommand, h);\r    }\r}\r\rvoid CommandParser::SetupCommandTable()\r{\r RFCCommands.clear();\r\r  printf("\nLoading core commands");\r     fflush(stdout);\r\r       DIR* library = opendir(LIBRARYDIR);\r    if (library)\r   {\r              dirent* entry = NULL;\r          while ((entry = readdir(library)))\r             {\r                      if (match(entry->d_name, "cmd_*.so"))\r                  {\r                              printf(".");\r                           fflush(stdout);\r                                this->LoadCommand(entry->d_name);\r                      }\r              }\r              closedir(library);\r             printf("\n");\r  }\r\r     this->CreateCommand(new cmd_reload(ServerInstance));\r}\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "configreader.h"
+#include <algorithm>
+#include "users.h"
+#include "modules.h"
+#include "wildcard.h"
+#include "xline.h"
+#include "socketengine.h"
+#include "socket.h"
+#include "command_parse.h"
+
+/* Directory Searching for Unix-Only */
+#ifndef WIN32
+#include <dirent.h>
+#include <dlfcn.h>
+#endif
+
+bool InspIRCd::ULine(const char* server)
+{
+       if (!server)
+               return false;
+       if (!*server)
+               return true;
+
+       return (Config->ulines.find(server) != Config->ulines.end());
+}
+
+bool InspIRCd::SilentULine(const char* server)
+{
+       std::map<irc::string,bool>::iterator n = Config->ulines.find(server);
+       if (n != Config->ulines.end())
+               return n->second;
+       else return false;
+}
+
+int InspIRCd::OperPassCompare(const char* data,const char* input, int tagnumber)
+{
+       int MOD_RESULT = 0;
+       FOREACH_RESULT_I(this,I_OnOperCompare,OnOperCompare(data, input, tagnumber))
+       if (MOD_RESULT == 1)
+               return 0;
+       if (MOD_RESULT == -1)
+               return 1;
+       return strcmp(data,input);
+}
+
+std::string InspIRCd::TimeString(time_t curtime)
+{
+       return std::string(ctime(&curtime),24);
+}
+
+/** Refactored by Brain, Jun 2007. Much faster with some clever O(1) array
+ * lookups and pointer maths.
+ */
+long InspIRCd::Duration(const std::string &str)
+{
+       unsigned char multiplier = 0;
+       long total = 0;
+       long times = 1;
+       long subtotal = 0;
+
+       /* Iterate each item in the string, looking for number or multiplier */
+       for (std::string::const_reverse_iterator i = str.rbegin(); i != str.rend(); ++i)
+       {
+               /* Found a number, queue it onto the current number */
+               if ((*i >= '0') && (*i <= '9'))
+               {
+                       subtotal = subtotal + ((*i - '0') * times);
+                       times = times * 10;
+               }
+               else
+               {
+                       /* Found something thats not a number, find out how much
+                        * it multiplies the built up number by, multiply the total
+                        * and reset the built up number.
+                        */
+                       if (subtotal)
+                               total += subtotal * duration_multi[multiplier];
+
+                       /* Next subtotal please */
+                       subtotal = 0;
+                       multiplier = *i;
+                       times = 1;
+               }
+       }
+       if (multiplier)
+       {
+               total += subtotal * duration_multi[multiplier];
+               subtotal = 0;
+       }
+       /* Any trailing values built up are treated as raw seconds */
+       return total + subtotal;
+}
+
+/* LoopCall is used to call a command classes handler repeatedly based on the contents of a comma seperated list.
+ * There are two overriden versions of this method, one of which takes two potential lists and the other takes one.
+ * We need a version which takes two potential lists for JOIN, because a JOIN may contain two lists of items at once,
+ * the channel names and their keys as follows:
+ * JOIN #chan1,#chan2,#chan3 key1,,key3
+ * Therefore, we need to deal with both lists concurrently. The first instance of this method does that by creating
+ * two instances of irc::commasepstream and reading them both together until the first runs out of tokens.
+ * The second version is much simpler and just has the one stream to read, and is used in NAMES, WHOIS, PRIVMSG etc.
+ * Both will only parse until they reach ServerInstance->Config->MaxTargets number of targets, to stop abuse via spam.
+ */
+int CommandParser::LoopCall(userrec* user, command_t* CommandObj, const char** parameters, int pcnt, unsigned int splithere, unsigned int extra)
+{
+       /* First check if we have more than one item in the list, if we don't we return zero here and the handler
+        * which called us just carries on as it was.
+        */
+       if (!strchr(parameters[splithere],','))
+               return 0;
+
+       /** Some lame ircds will weed out dupes using some shitty O(n^2) algorithm.
+        * By using std::map (thanks for the idea w00t) we can cut this down a ton.
+        * ...VOOODOOOO!
+        */
+       std::map<irc::string, bool> dupes;
+
+       /* Create two lists, one for channel names, one for keys
+        */
+       irc::commasepstream items1(parameters[splithere]);
+       irc::commasepstream items2(parameters[extra]);
+       std::string item("*");
+       unsigned int max = 0;
+
+       /* Attempt to iterate these lists and call the command objech
+        * which called us, for every parameter pair until there are
+        * no more left to parse.
+        */
+       while (((item = items1.GetToken()) != "") && (max++ < ServerInstance->Config->MaxTargets))
+       {
+               if (dupes.find(item.c_str()) == dupes.end())
+               {
+                       const char* new_parameters[127];
+
+                       for (int t = 0; (t < pcnt) && (t < 127); t++)
+                               new_parameters[t] = parameters[t];
+
+                       std::string extrastuff = items2.GetToken();
+
+                       new_parameters[splithere] = item.c_str();
+                       new_parameters[extra] = extrastuff.c_str();
+
+                       CommandObj->Handle(new_parameters,pcnt,user);
+
+                       dupes[item.c_str()] = true;
+               }
+       }
+       return 1;
+}
+
+int CommandParser::LoopCall(userrec* user, command_t* CommandObj, const char** parameters, int pcnt, unsigned int splithere)
+{
+       /* First check if we have more than one item in the list, if we don't we return zero here and the handler
+        * which called us just carries on as it was.
+        */
+       if (!strchr(parameters[splithere],','))
+               return 0;
+
+       std::map<irc::string, bool> dupes;
+
+       /* Only one commasepstream here */
+       irc::commasepstream items1(parameters[splithere]);
+       std::string item("*");
+       unsigned int max = 0;
+
+       /* Parse the commasepstream until there are no tokens remaining.
+        * Each token we parse out, call the command handler that called us
+        * with it
+        */
+       while (((item = items1.GetToken()) != "") && (max++ < ServerInstance->Config->MaxTargets))
+       {
+               if (dupes.find(item.c_str()) == dupes.end())
+               {
+                       const char* new_parameters[127];
+
+                       for (int t = 0; (t < pcnt) && (t < 127); t++)
+                               new_parameters[t] = parameters[t];
+
+                       new_parameters[splithere] = item.c_str();
+
+                       parameters[splithere] = item.c_str();
+
+                       /* Execute the command handler over and over. If someone pulls our user
+                        * record out from under us (e.g. if we /kill a comma sep list, and we're
+                        * in that list ourselves) abort if we're gone.
+                        */
+                       CommandObj->Handle(new_parameters,pcnt,user);
+
+                       dupes[item.c_str()] = true;
+               }
+       }
+       /* By returning 1 we tell our caller that nothing is to be done,
+        * as all the previous calls handled the data. This makes the parent
+        * return without doing any processing.
+        */
+       return 1;
+}
+
+bool CommandParser::IsValidCommand(const std::string &commandname, int pcnt, userrec * user)
+{
+       command_table::iterator n = cmdlist.find(commandname);
+
+       if (n != cmdlist.end())
+       {
+               if ((pcnt>=n->second->min_params) && (n->second->source != "<core>"))
+               {
+                       if ((!n->second->flags_needed) || (user->modes[n->second->flags_needed-65]))
+                       {
+                               if (n->second->flags_needed)
+                               {
+                                       return ((user->HasPermission(commandname)) || (ServerInstance->ULine(user->server)));
+                               }
+                               return true;
+                       }
+               }
+       }
+       return false;
+}
+
+command_t* CommandParser::GetHandler(const std::string &commandname)
+{
+       command_table::iterator n = cmdlist.find(commandname);
+       if (n != cmdlist.end())
+               return n->second;
+
+       return NULL;
+}
+
+// calls a handler function for a command
+
+CmdResult CommandParser::CallHandler(const std::string &commandname,const char** parameters, int pcnt, userrec *user)
+{
+       command_table::iterator n = cmdlist.find(commandname);
+
+       if (n != cmdlist.end())
+       {
+               if (pcnt >= n->second->min_params)
+               {
+                       if ((!n->second->flags_needed) || (user->modes[n->second->flags_needed-65]))
+                       {
+                               if (n->second->flags_needed)
+                               {
+                                       if ((user->HasPermission(commandname)) || (!IS_LOCAL(user)))
+                                       {
+                                               return n->second->Handle(parameters,pcnt,user);
+                                       }
+                               }
+                               else
+                               {
+                                       return n->second->Handle(parameters,pcnt,user);
+                               }
+                       }
+               }
+       }
+       return CMD_INVALID;
+}
+
+void CommandParser::ProcessCommand(userrec *user, std::string &cmd)
+{
+       const char *command_p[127];
+       int items = 0;
+       irc::tokenstream tokens(cmd);
+       std::string command;
+       tokens.GetToken(command);
+
+       /* A client sent a nick prefix on their command (ick)
+        * rhapsody and some braindead bouncers do this --
+        * the rfc says they shouldnt but also says the ircd should
+        * discard it if they do.
+        */
+       if (*command.c_str() == ':')
+               tokens.GetToken(command);
+
+       while (tokens.GetToken(para[items]) && (items < 127))
+       {
+               command_p[items] = para[items].c_str();
+               items++;
+       }
+
+       std::transform(command.begin(), command.end(), command.begin(), ::toupper);
+               
+       int MOD_RESULT = 0;
+       FOREACH_RESULT(I_OnPreCommand,OnPreCommand(command,command_p,items,user,false,cmd));
+       if (MOD_RESULT == 1) {
+               return;
+       }
+
+       command_table::iterator cm = cmdlist.find(command);
+       
+       if (cm != cmdlist.end())
+       {
+               if (user)
+               {
+                       /* activity resets the ping pending timer */
+                       user->nping = ServerInstance->Time() + user->pingmax;
+                       if (cm->second->flags_needed)
+                       {
+                               if (!user->IsModeSet(cm->second->flags_needed))
+                               {
+                                       user->WriteServ("481 %s :Permission Denied - You do not have the required operator privileges",user->nick);
+                                       return;
+                               }
+                               if (!user->HasPermission(command))
+                               {
+                                       user->WriteServ("481 %s :Permission Denied - Oper type %s does not have access to command %s",user->nick,user->oper,command.c_str());
+                                       return;
+                               }
+                       }
+                       if ((user->registered == REG_ALL) && (!IS_OPER(user)) && (cm->second->IsDisabled()))
+                       {
+                               /* command is disabled! */
+                               user->WriteServ("421 %s %s :This command has been disabled.",user->nick,command.c_str());
+                               return;
+                       }
+                       if (items < cm->second->min_params)
+                       {
+                               user->WriteServ("461 %s %s :Not enough parameters.", user->nick, command.c_str());
+                               /* If syntax is given, display this as the 461 reply */
+                               if ((ServerInstance->Config->SyntaxHints) && (user->registered == REG_ALL) && (cm->second->syntax.length()))
+                                       user->WriteServ("304 %s :SYNTAX %s %s", user->nick, cm->second->command.c_str(), cm->second->syntax.c_str());
+                               return;
+                       }
+                       if ((user->registered == REG_ALL) || (cm->second->WorksBeforeReg()))
+                       {
+                               /* ikky /stats counters */
+                               cm->second->use_count++;
+                               cm->second->total_bytes += cmd.length();
+
+                               int MOD_RESULT = 0;
+                               FOREACH_RESULT(I_OnPreCommand,OnPreCommand(command,command_p,items,user,true,cmd));
+                               if (MOD_RESULT == 1)
+                                       return;
+
+                               /*
+                                * WARNING: nothing may come after the
+                                * command handler call, as the handler
+                                * may free the user structure!
+                                */
+                               CmdResult result = cm->second->Handle(command_p,items,user);
+
+                               FOREACH_MOD(I_OnPostCommand,OnPostCommand(command, command_p, items, user, result,cmd));
+                               return;
+                       }
+                       else
+                       {
+                               user->WriteServ("451 %s :You have not registered",command.c_str());
+                               return;
+                       }
+               }
+       }
+       else if (user)
+       {
+               ServerInstance->stats->statsUnknown++;
+               user->WriteServ("421 %s %s :Unknown command",user->nick,command.c_str());
+       }
+}
+
+bool CommandParser::RemoveCommands(const char* source)
+{
+       command_table::iterator i,safei;
+       for (i = cmdlist.begin(); i != cmdlist.end(); i++)
+       {
+               safei = i;
+               safei++;
+               if (safei != cmdlist.end())
+               {
+                       RemoveCommand(safei, source);
+               }
+       }
+       safei = cmdlist.begin();
+       if (safei != cmdlist.end())
+       {
+               RemoveCommand(safei, source);
+       }
+       return true;
+}
+
+void CommandParser::RemoveCommand(command_table::iterator safei, const char* source)
+{
+       command_t* x = safei->second;
+       if (x->source == std::string(source))
+       {
+               cmdlist.erase(safei);
+               delete x;
+       }
+}
+
+void CommandParser::ProcessBuffer(std::string &buffer,userrec *user)
+{
+       std::string::size_type a;
+
+       if (!user)
+               return;
+
+       while ((a = buffer.rfind("\n")) != std::string::npos)
+               buffer.erase(a);
+       while ((a = buffer.rfind("\r")) != std::string::npos)
+               buffer.erase(a);
+
+       if (buffer.length())
+       {
+               if (!user->muted)
+               {
+                       ServerInstance->Log(DEBUG,"C[%d] -> :%s %s",user->GetFd(), user->nick, buffer.c_str());
+                       this->ProcessCommand(user,buffer);
+               }
+       }
+}
+
+bool CommandParser::CreateCommand(command_t *f, void* so_handle)
+{
+       if (so_handle)
+       {
+               if (RFCCommands.find(f->command) == RFCCommands.end())
+                       RFCCommands[f->command] = so_handle;
+               else
+               {
+                       ServerInstance->Log(DEFAULT,"ERK! Somehow, we loaded a cmd_*.so file twice! Only the first instance is being recorded.");
+                       return false;
+               }
+       }
+
+       /* create the command and push it onto the table */
+       if (cmdlist.find(f->command) == cmdlist.end())
+       {
+               cmdlist[f->command] = f;
+               return true;
+       }
+       else return false;
+}
+
+CommandParser::CommandParser(InspIRCd* Instance) : ServerInstance(Instance)
+{
+       para.resize(128);
+       this->SetupCommandTable();
+}
+
+bool CommandParser::FindSym(void** v, void* h)
+{
+       *v = dlsym(h, "init_command");
+       const char* err = dlerror();
+       if (err && !(*v))
+       {
+               ServerInstance->Log(SPARSE, "Error loading core command: %s\n", err);
+               return false;
+       }
+       return true;
+}
+
+bool CommandParser::ReloadCommand(const char* cmd)
+{
+       char filename[MAXBUF];
+       char commandname[MAXBUF];
+       int y = 0;
+
+       for (const char* x = cmd; *x; x++, y++)
+               commandname[y] = toupper(*x);
+
+       commandname[y] = 0;
+
+       SharedObjectList::iterator command = RFCCommands.find(commandname);
+
+       if (command != RFCCommands.end())
+       {
+               command_t* cmdptr = cmdlist.find(commandname)->second;
+               cmdlist.erase(cmdlist.find(commandname));
+
+               for (char* x = commandname; *x; x++)
+                       *x = tolower(*x);
+
+
+               delete cmdptr;
+               dlclose(command->second);
+               RFCCommands.erase(command);
+
+               snprintf(filename, MAXBUF, "cmd_%s.so", commandname);
+               this->LoadCommand(filename);
+
+               return true;
+       }
+
+       return false;
+}
+
+CmdResult cmd_reload::Handle(const char** parameters, int pcnt, userrec *user)
+{
+       user->WriteServ("NOTICE %s :*** Reloading command '%s'",user->nick, parameters[0]);
+       if (ServerInstance->Parser->ReloadCommand(parameters[0]))
+       {
+               user->WriteServ("NOTICE %s :*** Successfully reloaded command '%s'", user->nick, parameters[0]);
+               ServerInstance->WriteOpers("*** RELOAD: %s reloaded the '%s' command.", user->nick, parameters[0]);
+               return CMD_SUCCESS;
+       }
+       else
+       {
+               user->WriteServ("NOTICE %s :*** Could not reload command '%s'", user->nick, parameters[0]);
+               return CMD_FAILURE;
+       }
+}
+
+void CommandParser::LoadCommand(const char* name)
+{
+       char filename[MAXBUF];
+       void* h;
+       command_t* (*cmd_factory_func)(InspIRCd*);
+
+       snprintf(filename, MAXBUF, "%s/%s", LIBRARYDIR, name);
+       h = dlopen(filename, RTLD_NOW | RTLD_GLOBAL);
+
+       if (!h)
+       {
+               ServerInstance->Log(SPARSE, "Error loading core command: %s", dlerror());
+               return;
+       }
+
+       if (this->FindSym((void **)&cmd_factory_func, h))
+       {
+               command_t* newcommand = cmd_factory_func(ServerInstance);
+               this->CreateCommand(newcommand, h);
+       }
+}
+
+void CommandParser::SetupCommandTable()
+{
+       RFCCommands.clear();
+
+       printf("\nLoading core commands");
+       fflush(stdout);
+
+       DIR* library = opendir(LIBRARYDIR);
+       if (library)
+       {
+               dirent* entry = NULL;
+               while ((entry = readdir(library)))
+               {
+                       if (match(entry->d_name, "cmd_*.so"))
+                       {
+                               printf(".");
+                               fflush(stdout);
+                               this->LoadCommand(entry->d_name);
+                       }
+               }
+               closedir(library);
+               printf("\n");
+       }
+
+       this->CreateCommand(new cmd_reload(ServerInstance));
+}
+
index 469b4ed74796a9f7ca3a02b14bdb3ca2d7f36db6..65b11e5a027a8091e98c60d836b35df34b8cef7c 100644 (file)
@@ -1 +1,111 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "configreader.h"\r#include "users.h"\r#include "modules.h"\r#include "wildcard.h"\r#include "xline.h"\r#include "command_parse.h"\r\r/* All other ircds when doing this check usually just look for a string of *@* or *. We're smarter than that, though. */\r\rbool InspIRCd::HostMatchesEveryone(const std::string &mask, userrec* user)\r{\r       char itrigger[MAXBUF];\r long matches = 0;\r      \r       if (!Config->ConfValue(Config->config_data, "insane","trigger", 0, itrigger, MAXBUF))\r          strlcpy(itrigger,"95.5",MAXBUF);\r       \r       if (Config->ConfValueBool(Config->config_data, "insane","hostmasks", 0))\r               return false;\r  \r       for (user_hash::iterator u = clientlist->begin(); u != clientlist->end(); u++)\r {\r              if ((match(u->second->MakeHost(),mask.c_str(),true)) || (match(u->second->MakeHostIP(),mask.c_str(),true)))\r            {\r                      matches++;\r             }\r      }\r\r     if (!matches)\r          return false;\r\r float percent = ((float)matches / (float)clientlist->size()) * 100;\r    if (percent > (float)atof(itrigger))\r   {\r              WriteOpers("*** \2WARNING\2: %s tried to set a G/K/E line mask of %s, which covers %.2f%% of the network!",user->nick,mask.c_str(),percent);\r           return true;\r   }\r      return false;\r}\r\rbool InspIRCd::IPMatchesEveryone(const std::string &ip, userrec* user)\r{\r      char itrigger[MAXBUF];\r long matches = 0;\r      \r       if (!Config->ConfValue(Config->config_data, "insane","trigger",0,itrigger,MAXBUF))\r             strlcpy(itrigger,"95.5",MAXBUF);\r       \r       if (Config->ConfValueBool(Config->config_data, "insane","ipmasks",0))\r          return false;\r  \r       for (user_hash::iterator u = clientlist->begin(); u != clientlist->end(); u++)\r {\r              if (match(u->second->GetIPString(),ip.c_str(),true))\r                   matches++;\r     }\r\r     if (!matches)\r          return false;\r\r float percent = ((float)matches / (float)clientlist->size()) * 100;\r    if (percent > (float)atof(itrigger))\r   {\r              WriteOpers("*** \2WARNING\2: %s tried to set a Z line mask of %s, which covers %.2f%% of the network!",user->nick,ip.c_str(),percent);\r         return true;\r   }\r      return false;\r}\r\rbool InspIRCd::NickMatchesEveryone(const std::string &nick, userrec* user)\r{\r  char itrigger[MAXBUF];\r long matches = 0;\r      \r       if (!Config->ConfValue(Config->config_data, "insane","trigger",0,itrigger,MAXBUF))\r             strlcpy(itrigger,"95.5",MAXBUF);\r       \r       if (Config->ConfValueBool(Config->config_data, "insane","nickmasks",0))\r                return false;\r\r for (user_hash::iterator u = clientlist->begin(); u != clientlist->end(); u++)\r {\r              if (match(u->second->nick,nick.c_str()))\r                       matches++;\r     }\r\r     if (!matches)\r          return false;\r\r float percent = ((float)matches / (float)clientlist->size()) * 100;\r    if (percent > (float)atof(itrigger))\r   {\r              WriteOpers("*** \2WARNING\2: %s tried to set a Q line mask of %s, which covers %.2f%% of the network!",user->nick,nick.c_str(),percent);\r               return true;\r   }\r      return false;\r}\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "configreader.h"
+#include "users.h"
+#include "modules.h"
+#include "wildcard.h"
+#include "xline.h"
+#include "command_parse.h"
+
+/* All other ircds when doing this check usually just look for a string of *@* or *. We're smarter than that, though. */
+
+bool InspIRCd::HostMatchesEveryone(const std::string &mask, userrec* user)
+{
+       char itrigger[MAXBUF];
+       long matches = 0;
+       
+       if (!Config->ConfValue(Config->config_data, "insane","trigger", 0, itrigger, MAXBUF))
+               strlcpy(itrigger,"95.5",MAXBUF);
+       
+       if (Config->ConfValueBool(Config->config_data, "insane","hostmasks", 0))
+               return false;
+       
+       for (user_hash::iterator u = clientlist->begin(); u != clientlist->end(); u++)
+       {
+               if ((match(u->second->MakeHost(),mask.c_str(),true)) || (match(u->second->MakeHostIP(),mask.c_str(),true)))
+               {
+                       matches++;
+               }
+       }
+
+       if (!matches)
+               return false;
+
+       float percent = ((float)matches / (float)clientlist->size()) * 100;
+       if (percent > (float)atof(itrigger))
+       {
+               WriteOpers("*** \2WARNING\2: %s tried to set a G/K/E line mask of %s, which covers %.2f%% of the network!",user->nick,mask.c_str(),percent);
+               return true;
+       }
+       return false;
+}
+
+bool InspIRCd::IPMatchesEveryone(const std::string &ip, userrec* user)
+{
+       char itrigger[MAXBUF];
+       long matches = 0;
+       
+       if (!Config->ConfValue(Config->config_data, "insane","trigger",0,itrigger,MAXBUF))
+               strlcpy(itrigger,"95.5",MAXBUF);
+       
+       if (Config->ConfValueBool(Config->config_data, "insane","ipmasks",0))
+               return false;
+       
+       for (user_hash::iterator u = clientlist->begin(); u != clientlist->end(); u++)
+       {
+               if (match(u->second->GetIPString(),ip.c_str(),true))
+                       matches++;
+       }
+
+       if (!matches)
+               return false;
+
+       float percent = ((float)matches / (float)clientlist->size()) * 100;
+       if (percent > (float)atof(itrigger))
+       {
+               WriteOpers("*** \2WARNING\2: %s tried to set a Z line mask of %s, which covers %.2f%% of the network!",user->nick,ip.c_str(),percent);
+               return true;
+       }
+       return false;
+}
+
+bool InspIRCd::NickMatchesEveryone(const std::string &nick, userrec* user)
+{
+       char itrigger[MAXBUF];
+       long matches = 0;
+       
+       if (!Config->ConfValue(Config->config_data, "insane","trigger",0,itrigger,MAXBUF))
+               strlcpy(itrigger,"95.5",MAXBUF);
+       
+       if (Config->ConfValueBool(Config->config_data, "insane","nickmasks",0))
+               return false;
+
+       for (user_hash::iterator u = clientlist->begin(); u != clientlist->end(); u++)
+       {
+               if (match(u->second->nick,nick.c_str()))
+                       matches++;
+       }
+
+       if (!matches)
+               return false;
+
+       float percent = ((float)matches / (float)clientlist->size()) * 100;
+       if (percent > (float)atof(itrigger))
+       {
+               WriteOpers("*** \2WARNING\2: %s tried to set a Q line mask of %s, which covers %.2f%% of the network!",user->nick,nick.c_str(),percent);
+               return true;
+       }
+       return false;
+}
index df15d9a61d7c29bec675aebebc85d61495044fd7..d4291692ff72385585f84090f5b38c3b9a80b022 100644 (file)
@@ -1 +1,1714 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "configreader.h"\r#include <sstream>\r#include <fstream>\r#include "xline.h"\r#include "exitcodes.h"\r#include "commands/cmd_whowas.h"\r\rstd::vector<std::string> old_module_names, new_module_names, added_modules, removed_modules;\r\rServerConfig::ServerConfig(InspIRCd* Instance) : ServerInstance(Instance)\r{\r       this->ClearStack();\r    *ServerName = *Network = *ServerDesc = *AdminName = '\0';\r      *HideWhoisServer = *AdminEmail = *AdminNick = *diepass = *restartpass = *FixedQuit = *HideKillsServer = '\0';\r  *DefaultModes = *CustomVersion = *motd = *rules = *PrefixQuit = *DieValue = *DNSServer = '\0';\r *UserStats = *ModPath = *MyExecutable = *DisabledCommands = *PID = *SuffixQuit = '\0';\r WhoWasGroupSize = WhoWasMaxGroups = WhoWasMaxKeep = 0;\r log_file = NULL;\r       NoUserDns = forcedebug = OperSpyWhois = nofork = HideBans = HideSplits = UndernetMsgPrefix = false;\r    CycleHosts = writelog = AllowHalfop = true;\r    dns_timeout = DieDelay = 5;\r    MaxTargets = 20;\r       NetBufferSize = 10240;\r SoftLimit = MAXCLIENTS;\r        MaxConn = SOMAXCONN;\r   MaxWhoResults = 0;\r     debugging = 0;\r MaxChans = 20;\r OperMaxChans = 30;\r     LogLevel = DEFAULT;\r    maxbans.clear();\r}\r\rvoid ServerConfig::ClearStack()\r{\r  include_stack.clear();\r}\r\rModule* ServerConfig::GetIOHook(int port)\r{\r  std::map<int,Module*>::iterator x = IOHookModule.find(port);\r   return (x != IOHookModule.end() ? x->second : NULL);\r}\r\rModule* ServerConfig::GetIOHook(InspSocket* is)\r{\r      std::map<InspSocket*,Module*>::iterator x = SocketIOHookModule.find(is);\r       return (x != SocketIOHookModule.end() ? x->second : NULL);\r}\r\rbool ServerConfig::AddIOHook(int port, Module* iomod)\r{\r  if (!GetIOHook(port))\r  {\r              IOHookModule[port] = iomod;\r            return true;\r   }\r      else\r   {\r              throw ModuleException("Port already hooked by another module");\r                return false;\r  }\r}\r\rbool ServerConfig::AddIOHook(Module* iomod, InspSocket* is)\r{\r     if (!GetIOHook(is))\r    {\r              SocketIOHookModule[is] = iomod;\r                is->IsIOHooked = true;\r         return true;\r   }\r      else\r   {\r              throw ModuleException("InspSocket derived class already hooked by another module");\r            return false;\r  }\r}\r\rbool ServerConfig::DelIOHook(int port)\r{\r  std::map<int,Module*>::iterator x = IOHookModule.find(port);\r   if (x != IOHookModule.end())\r   {\r              IOHookModule.erase(x);\r         return true;\r   }\r      return false;\r}\r\rbool ServerConfig::DelIOHook(InspSocket* is)\r{\r        std::map<InspSocket*,Module*>::iterator x = SocketIOHookModule.find(is);\r       if (x != SocketIOHookModule.end())\r     {\r              SocketIOHookModule.erase(x);\r           return true;\r   }\r      return false;\r}\r\rvoid ServerConfig::Update005()\r{\r      std::stringstream out(data005);\r        std::string token;\r     std::string line5;\r     int token_counter = 0;\r isupport.clear();\r      while (out >> token)\r   {\r              line5 = line5 + token + " ";\r           token_counter++;\r               if (token_counter >= 13)\r               {\r                      char buf[MAXBUF];\r                      snprintf(buf, MAXBUF, "%s:are supported by this server", line5.c_str());\r                       isupport.push_back(buf);\r                       line5.clear();\r                 token_counter = 0;\r             }\r      }\r      if (!line5.empty())\r    {\r              char buf[MAXBUF];\r              snprintf(buf, MAXBUF, "%s:are supported by this server", line5.c_str());\r               isupport.push_back(buf);\r       }\r}\r\rvoid ServerConfig::Send005(userrec* user)\r{\r       for (std::vector<std::string>::iterator line = ServerInstance->Config->isupport.begin(); line != ServerInstance->Config->isupport.end(); line++)\r               user->WriteServ("005 %s %s", user->nick, line->c_str());\r}\r\rbool ServerConfig::CheckOnce(char* tag, bool bail, userrec* user)\r{\r        int count = ConfValueEnum(this->config_data, tag);\r\r    if (count > 1)\r {\r              throw CoreException("You have more than one <"+std::string(tag)+"> tag, this is not permitted.");\r              return false;\r  }\r      if (count < 1)\r {\r              throw CoreException("You have not defined a <"+std::string(tag)+"> tag, this is required.");\r           return false;\r  }\r      return true;\r}\r\rbool NoValidation(ServerConfig* conf, const char* tag, const char* value, ValueItem &data)\r{\r   return true;\r}\r\rbool ValidateMaxTargets(ServerConfig* conf, const char* tag, const char* value, ValueItem &data)\r{\r     if ((data.GetInteger() < 0) || (data.GetInteger() > 31))\r       {\r              conf->GetInstance()->Log(DEFAULT,"WARNING: <options:maxtargets> value is greater than 31 or less than 0, set to 20.");\r         data.Set(20);\r  }\r      return true;\r}\r\rbool ValidateSoftLimit(ServerConfig* conf, const char* tag, const char* value, ValueItem &data)\r{\r      if ((data.GetInteger() < 1) || (data.GetInteger() > MAXCLIENTS))\r       {\r              conf->GetInstance()->Log(DEFAULT,"WARNING: <options:softlimit> value is greater than %d or less than 0, set to %d.",MAXCLIENTS,MAXCLIENTS);\r            data.Set(MAXCLIENTS);\r  }\r      return true;\r}\r\rbool ValidateMaxConn(ServerConfig* conf, const char* tag, const char* value, ValueItem &data)\r{\r        if (data.GetInteger() > SOMAXCONN)\r             conf->GetInstance()->Log(DEFAULT,"WARNING: <options:somaxconn> value may be higher than the system-defined SOMAXCONN value!");\r return true;\r}\r\rbool InitializeDisabledCommands(const char* data, InspIRCd* ServerInstance)\r{\r  std::stringstream dcmds(data);\r std::string thiscmd;\r\r  /* Enable everything first */\r  for (command_table::iterator x = ServerInstance->Parser->cmdlist.begin(); x != ServerInstance->Parser->cmdlist.end(); x++)\r             x->second->Disable(false);\r\r    /* Now disable all the ones which the user wants disabled */\r   while (dcmds >> thiscmd)\r       {\r              command_table::iterator cm = ServerInstance->Parser->cmdlist.find(thiscmd);\r            if (cm != ServerInstance->Parser->cmdlist.end())\r               {\r                      cm->second->Disable(true);\r             }\r      }\r      return true;\r}\r\rbool ValidateDnsServer(ServerConfig* conf, const char* tag, const char* value, ValueItem &data)\r{\r      if (!*(data.GetString()))\r      {\r              std::string nameserver;\r#ifdef WINDOWS\r         conf->GetInstance()->Log(DEFAULT,"WARNING: <dns:server> not defined, attempting to find working server in the registry...");\r           nameserver = FindNameServerWin();\r              /* Windows stacks multiple nameservers in one registry key, seperated by commas.\r                * Spotted by Cataclysm.\r                */\r            if (nameserver.find(',') != std::string::npos)\r                 nameserver = nameserver.substr(0, nameserver.find(','));\r               data.Set(nameserver.c_str());\r          conf->GetInstance()->Log(DEFAULT,"<dns:server> set to '%s' as first active resolver in registry.", nameserver.c_str());\r#else\r          // attempt to look up their nameserver from /etc/resolv.conf\r           conf->GetInstance()->Log(DEFAULT,"WARNING: <dns:server> not defined, attempting to find working server in /etc/resolv.conf...");\r               ifstream resolv("/etc/resolv.conf");\r           bool found_server = false;\r\r            if (resolv.is_open())\r          {\r                      while (resolv >> nameserver)\r                   {\r                              if ((nameserver == "nameserver") && (!found_server))\r                           {\r                                      resolv >> nameserver;\r                                  data.Set(nameserver.c_str());\r                                  found_server = true;\r                                   conf->GetInstance()->Log(DEFAULT,"<dns:server> set to '%s' as first resolver in /etc/resolv.conf.",nameserver.c_str());\r                                }\r                      }\r\r                     if (!found_server)\r                     {\r                              conf->GetInstance()->Log(DEFAULT,"/etc/resolv.conf contains no viable nameserver entries! Defaulting to nameserver '127.0.0.1'!");\r                             data.Set("127.0.0.1");\r                 }\r              }\r              else\r           {\r                      conf->GetInstance()->Log(DEFAULT,"/etc/resolv.conf can't be opened! Defaulting to nameserver '127.0.0.1'!");\r                   data.Set("127.0.0.1");\r         }\r#endif\r       }\r      return true;\r}\r\rbool ValidateServerName(ServerConfig* conf, const char* tag, const char* value, ValueItem &data)\r{\r     /* If we already have a servername, and they changed it, we should throw an exception. */\r      if ((strcasecmp(conf->ServerName, data.GetString())) && (*conf->ServerName))\r   {\r              throw CoreException("Configuration error: You cannot change your servername at runtime! Please restart your server for this change to be applied.");\r           /* XXX: We don't actually reach this return of course... */\r            return false;\r  }\r      if (!strchr(data.GetString(),'.'))\r     {\r              conf->GetInstance()->Log(DEFAULT,"WARNING: <server:name> '%s' is not a fully-qualified domain name. Changed to '%s%c'",data.GetString(),data.GetString(),'.');\r         std::string moo = std::string(data.GetString()).append(".");\r           data.Set(moo.c_str());\r }\r      return true;\r}\r\rbool ValidateNetBufferSize(ServerConfig* conf, const char* tag, const char* value, ValueItem &data)\r{\r  if ((!data.GetInteger()) || (data.GetInteger() > 65535) || (data.GetInteger() < 1024))\r {\r              conf->GetInstance()->Log(DEFAULT,"No NetBufferSize specified or size out of range, setting to default of 10240.");\r             data.Set(10240);\r       }\r      return true;\r}\r\rbool ValidateMaxWho(ServerConfig* conf, const char* tag, const char* value, ValueItem &data)\r{\r if ((data.GetInteger() > 65535) || (data.GetInteger() < 1))\r    {\r              conf->GetInstance()->Log(DEFAULT,"<options:maxwhoresults> size out of range, setting to default of 128.");\r             data.Set(128);\r }\r      return true;\r}\r\rbool ValidateLogLevel(ServerConfig* conf, const char* tag, const char* value, ValueItem &data)\r{\r       std::string dbg = data.GetString();\r    conf->LogLevel = DEFAULT;\r\r     if (dbg == "debug")\r            conf->LogLevel = DEBUG;\r        else if (dbg  == "verbose")\r            conf->LogLevel = VERBOSE;\r      else if (dbg == "default")\r             conf->LogLevel = DEFAULT;\r      else if (dbg == "sparse")\r              conf->LogLevel = SPARSE;\r       else if (dbg == "none")\r                conf->LogLevel = NONE;\r\r        conf->debugging = (conf->LogLevel == DEBUG);\r\r  return true;\r}\r\rbool ValidateMotd(ServerConfig* conf, const char* tag, const char* value, ValueItem &data)\r{\r   conf->ReadFile(conf->MOTD, data.GetString());\r  return true;\r}\r\rbool ValidateNotEmpty(ServerConfig* conf, const char* tag, const char* value, ValueItem &data)\r{\r       if (!*data.GetString())\r                throw CoreException(std::string("The value for ")+tag+" cannot be empty!");\r    return true;\r}\r\rbool ValidateRules(ServerConfig* conf, const char* tag, const char* value, ValueItem &data)\r{\r  conf->ReadFile(conf->RULES, data.GetString());\r return true;\r}\r\rbool ValidateModeLists(ServerConfig* conf, const char* tag, const char* value, ValueItem &data)\r{\r      memset(conf->HideModeLists, 0, 256);\r   for (const unsigned char* x = (const unsigned char*)data.GetString(); *x; ++x)\r         conf->HideModeLists[*x] = true;\r        return true;\r}\r\rbool ValidateExemptChanOps(ServerConfig* conf, const char* tag, const char* value, ValueItem &data)\r{\r  memset(conf->ExemptChanOps, 0, 256);\r   for (const unsigned char* x = (const unsigned char*)data.GetString(); *x; ++x)\r         conf->ExemptChanOps[*x] = true;\r        return true;\r}\r\rbool ValidateWhoWas(ServerConfig* conf, const char* tag, const char* value, ValueItem &data)\r{\r conf->WhoWasMaxKeep = conf->GetInstance()->Duration(data.GetString());\r\r        if (conf->WhoWasGroupSize < 0)\r         conf->WhoWasGroupSize = 0;\r\r    if (conf->WhoWasMaxGroups < 0)\r         conf->WhoWasMaxGroups = 0;\r\r    if (conf->WhoWasMaxKeep < 3600)\r        {\r              conf->WhoWasMaxKeep = 3600;\r            conf->GetInstance()->Log(DEFAULT,"WARNING: <whowas:maxkeep> value less than 3600, setting to default 3600");\r   }\r\r     command_t* whowas_command = conf->GetInstance()->Parser->GetHandler("WHOWAS");\r if (whowas_command)\r    {\r              std::deque<classbase*> params;\r         whowas_command->HandleInternal(WHOWAS_PRUNE, params);\r  }\r\r     return true;\r}\r\r/* Callback called before processing the first <connect> tag\r */\rbool InitConnect(ServerConfig* conf, const char* tag)\r{\r       conf->GetInstance()->Log(DEFAULT,"Reading connect classes...");\r        conf->Classes.clear();\r return true;\r}\r\r/* Callback called to process a single <connect> tag\r */\rbool DoConnect(ServerConfig* conf, const char* tag, char** entries, ValueList &values, int* types)\r{\r  ConnectClass c;\r        const char* allow = values[0].GetString(); /* Yeah, there are a lot of values. Live with it. */\r        const char* deny = values[1].GetString();\r      const char* password = values[2].GetString();\r  int timeout = values[3].GetInteger();\r  int pingfreq = values[4].GetInteger();\r int flood = values[5].GetInteger();\r    int threshold = values[6].GetInteger();\r        int sendq = values[7].GetInteger();\r    int recvq = values[8].GetInteger();\r    int localmax = values[9].GetInteger();\r int globalmax = values[10].GetInteger();\r\r      if (*allow)\r    {\r              ConnectClass c(timeout, flood, allow, pingfreq, password, threshold, sendq, recvq, localmax, globalmax);\r               conf->Classes.push_back(c);\r    }\r      else\r   {\r              ConnectClass c(deny);\r          conf->Classes.push_back(c);\r    }\r\r     return true;\r}\r\r/* Callback called when there are no more <connect> tags\r */\rbool DoneConnect(ServerConfig* conf, const char* tag)\r{\r   return true;\r}\r\r/* Callback called before processing the first <uline> tag\r */\rbool InitULine(ServerConfig* conf, const char* tag)\r{\r   conf->ulines.clear();\r  return true;\r}\r\r/* Callback called to process a single <uline> tag\r */\rbool DoULine(ServerConfig* conf, const char* tag, char** entries, ValueList &values, int* types)\r{\r      const char* server = values[0].GetString();\r    const bool silent = values[1].GetBool();\r       conf->ulines[server] = silent;\r return true;\r}\r\r/* Callback called when there are no more <uline> tags\r */\rbool DoneULine(ServerConfig* conf, const char* tag)\r{\r       return true;\r}\r\r/* Callback called before processing the first <module> tag\r */\rbool InitModule(ServerConfig* conf, const char* tag)\r{\r old_module_names.clear();\r      new_module_names.clear();\r      added_modules.clear();\r removed_modules.clear();\r       for (std::vector<std::string>::iterator t = conf->module_names.begin(); t != conf->module_names.end(); t++)\r    {\r              old_module_names.push_back(*t);\r        }\r      return true;\r}\r\r/* Callback called to process a single <module> tag\r */\rbool DoModule(ServerConfig* conf, const char* tag, char** entries, ValueList &values, int* types)\r{\r    const char* modname = values[0].GetString();\r   new_module_names.push_back(modname);\r   return true;\r}\r\r/* Callback called when there are no more <module> tags\r */\rbool DoneModule(ServerConfig* conf, const char* tag)\r{\r     // now create a list of new modules that are due to be loaded\r  // and a seperate list of modules which are due to be unloaded\r for (std::vector<std::string>::iterator _new = new_module_names.begin(); _new != new_module_names.end(); _new++)\r       {\r              bool added = true;\r\r            for (std::vector<std::string>::iterator old = old_module_names.begin(); old != old_module_names.end(); old++)\r          {\r                      if (*old == *_new)\r                             added = false;\r         }\r\r             if (added)\r                     added_modules.push_back(*_new);\r        }\r\r     for (std::vector<std::string>::iterator oldm = old_module_names.begin(); oldm != old_module_names.end(); oldm++)\r       {\r              bool removed = true;\r           for (std::vector<std::string>::iterator newm = new_module_names.begin(); newm != new_module_names.end(); newm++)\r               {\r                      if (*newm == *oldm)\r                            removed = false;\r               }\r\r             if (removed)\r                   removed_modules.push_back(*oldm);\r      }\r      return true;\r}\r\r/* Callback called before processing the first <banlist> tag\r */\rbool InitMaxBans(ServerConfig* conf, const char* tag)\r{\r       conf->maxbans.clear();\r return true;\r}\r\r/* Callback called to process a single <banlist> tag\r */\rbool DoMaxBans(ServerConfig* conf, const char* tag, char** entries, ValueList &values, int* types)\r{\r  const char* channel = values[0].GetString();\r   int limit = values[1].GetInteger();\r    conf->maxbans[channel] = limit;\r        return true;\r}\r\r/* Callback called when there are no more <banlist> tags.\r */\rbool DoneMaxBans(ServerConfig* conf, const char* tag)\r{\r  return true;\r}\r\rvoid ServerConfig::ReportConfigError(const std::string &errormessage, bool bail, userrec* user)\r{\r      ServerInstance->Log(DEFAULT, "There were errors in your configuration file: %s", errormessage.c_str());\r        if (bail)\r      {\r              /* Unneeded because of the ServerInstance->Log() aboive? */\r            printf("There were errors in your configuration:\n%s\n\n",errormessage.c_str());\r               InspIRCd::Exit(EXIT_STATUS_CONFIG);\r    }\r      else\r   {\r              std::string errors = errormessage;\r             std::string::size_type start;\r          unsigned int prefixlen;\r                start = 0;\r             /* ":ServerInstance->Config->ServerName NOTICE user->nick :" */\r                if (user)\r              {\r                      prefixlen = strlen(this->ServerName) + strlen(user->nick) + 11;\r                        user->WriteServ("NOTICE %s :There were errors in the configuration file:",user->nick);\r                 while (start < errors.length())\r                        {\r                              user->WriteServ("NOTICE %s :%s",user->nick, errors.substr(start, 510 - prefixlen).c_str());\r                            start += 510 - prefixlen;\r                      }\r              }\r              else\r           {\r                      ServerInstance->WriteOpers("There were errors in the configuration file:");\r                    while (start < errors.length())\r                        {\r                              ServerInstance->WriteOpers(errors.substr(start, 360).c_str());\r                         start += 360;\r                  }\r              }\r              return;\r        }\r}\r\rvoid ServerConfig::Read(bool bail, userrec* user)\r{\r       static char debug[MAXBUF];      /* Temporary buffer for debugging value */\r     static char maxkeep[MAXBUF];    /* Temporary buffer for WhoWasMaxKeep value */\r static char hidemodes[MAXBUF];  /* Modes to not allow listing from users below halfop */\r       static char exemptchanops[MAXBUF];      /* Exempt channel ops from these modes */\r      int rem = 0, add = 0;           /* Number of modules added, number of modules removed */\r       std::ostringstream errstr;      /* String stream containing the error output */\r\r       /* These tags MUST occur and must ONLY occur once in the config file */\r        static char* Once[] = { "server", "admin", "files", "power", "options", NULL };\r\r       /* These tags can occur ONCE or not at all */\r  InitialConfig Values[] = {\r             {"options",     "softlimit",    MAXCLIENTS_S,           new ValueContainerUInt (&this->SoftLimit),              DT_INTEGER, ValidateSoftLimit},\r                {"options",     "somaxconn",    SOMAXCONN_S,            new ValueContainerInt  (&this->MaxConn),                DT_INTEGER, ValidateMaxConn},\r          {"options",     "moronbanner",  "Youre banned!",        new ValueContainerChar (this->MoronBanner),             DT_CHARPTR, NoValidation},\r             {"server",      "name",         "",                     new ValueContainerChar (this->ServerName),              DT_CHARPTR, ValidateServerName},\r               {"server",      "description",  "Configure Me",         new ValueContainerChar (this->ServerDesc),              DT_CHARPTR, NoValidation},\r             {"server",      "network",      "Network",              new ValueContainerChar (this->Network),                 DT_CHARPTR, NoValidation},\r             {"admin",       "name",         "",                     new ValueContainerChar (this->AdminName),               DT_CHARPTR, NoValidation},\r             {"admin",       "email",        "Mis@configu.red",      new ValueContainerChar (this->AdminEmail),              DT_CHARPTR, NoValidation},\r             {"admin",       "nick",         "Misconfigured",        new ValueContainerChar (this->AdminNick),               DT_CHARPTR, NoValidation},\r             {"files",       "motd",         "",                     new ValueContainerChar (this->motd),                    DT_CHARPTR, ValidateMotd},\r             {"files",       "rules",        "",                     new ValueContainerChar (this->rules),                   DT_CHARPTR, ValidateRules},\r            {"power",       "diepass",      "",                     new ValueContainerChar (this->diepass),                 DT_CHARPTR, ValidateNotEmpty},\r         {"power",       "pause",        "",                     new ValueContainerInt  (&this->DieDelay),               DT_INTEGER, NoValidation},\r             {"power",       "restartpass",  "",                     new ValueContainerChar (this->restartpass),             DT_CHARPTR, ValidateNotEmpty},\r         {"options",     "prefixquit",   "",                     new ValueContainerChar (this->PrefixQuit),              DT_CHARPTR, NoValidation},\r             {"options",     "suffixquit",   "",                     new ValueContainerChar (this->SuffixQuit),              DT_CHARPTR, NoValidation},\r             {"options",     "fixedquit",    "",                     new ValueContainerChar (this->FixedQuit),               DT_CHARPTR, NoValidation},\r             {"options",     "loglevel",     "default",              new ValueContainerChar (debug),                         DT_CHARPTR, ValidateLogLevel},\r         {"options",     "netbuffersize","10240",                new ValueContainerInt  (&this->NetBufferSize),          DT_INTEGER, ValidateNetBufferSize},\r            {"options",     "maxwho",       "128",                  new ValueContainerInt  (&this->MaxWhoResults),          DT_INTEGER, ValidateMaxWho},\r           {"options",     "allowhalfop",  "0",                    new ValueContainerBool (&this->AllowHalfop),            DT_BOOLEAN, NoValidation},\r             {"dns",         "server",       "",                     new ValueContainerChar (this->DNSServer),               DT_CHARPTR, ValidateDnsServer},\r                {"dns",         "timeout",      "5",                    new ValueContainerInt  (&this->dns_timeout),            DT_INTEGER, NoValidation},\r             {"options",     "moduledir",    MOD_PATH,               new ValueContainerChar (this->ModPath),                 DT_CHARPTR, NoValidation},\r             {"disabled",    "commands",     "",                     new ValueContainerChar (this->DisabledCommands),        DT_CHARPTR, NoValidation},\r             {"options",     "userstats",    "",                     new ValueContainerChar (this->UserStats),               DT_CHARPTR, NoValidation},\r             {"options",     "customversion","",                     new ValueContainerChar (this->CustomVersion),           DT_CHARPTR, NoValidation},\r             {"options",     "hidesplits",   "0",                    new ValueContainerBool (&this->HideSplits),             DT_BOOLEAN, NoValidation},\r             {"options",     "hidebans",     "0",                    new ValueContainerBool (&this->HideBans),               DT_BOOLEAN, NoValidation},\r             {"options",     "hidewhois",    "",                     new ValueContainerChar (this->HideWhoisServer),         DT_CHARPTR, NoValidation},\r             {"options",     "hidekills",    "",                     new ValueContainerChar (this->HideKillsServer),         DT_CHARPTR, NoValidation},\r             {"options",     "operspywhois", "0",                    new ValueContainerBool (&this->OperSpyWhois),           DT_BOOLEAN, NoValidation},\r             {"options",     "nouserdns",    "0",                    new ValueContainerBool (&this->NoUserDns),              DT_BOOLEAN, NoValidation},\r             {"options",     "syntaxhints",  "0",                    new ValueContainerBool (&this->SyntaxHints),            DT_BOOLEAN, NoValidation},\r             {"options",     "cyclehosts",   "0",                    new ValueContainerBool (&this->CycleHosts),             DT_BOOLEAN, NoValidation},\r             {"options",     "ircumsgprefix","0",                    new ValueContainerBool (&this->UndernetMsgPrefix),      DT_BOOLEAN, NoValidation},\r             {"options",     "announceinvites", "1",                 new ValueContainerBool (&this->AnnounceInvites),        DT_BOOLEAN, NoValidation},\r             {"options",     "hostintopic",  "1",                    new ValueContainerBool (&this->FullHostInTopic),        DT_BOOLEAN, NoValidation},\r             {"options",     "hidemodes",    "",                     new ValueContainerChar (hidemodes),                     DT_CHARPTR, ValidateModeLists},\r                {"options",     "exemptchanops","",                     new ValueContainerChar (exemptchanops),                 DT_CHARPTR, ValidateExemptChanOps},\r            {"options",     "defaultmodes", "nt",                   new ValueContainerChar (this->DefaultModes),            DT_CHARPTR, NoValidation},\r             {"pid",         "file",         "",                     new ValueContainerChar (this->PID),                     DT_CHARPTR, NoValidation},\r             {"whowas",      "groupsize",    "10",                   new ValueContainerInt  (&this->WhoWasGroupSize),        DT_INTEGER, NoValidation},\r             {"whowas",      "maxgroups",    "10240",                new ValueContainerInt  (&this->WhoWasMaxGroups),        DT_INTEGER, NoValidation},\r             {"whowas",      "maxkeep",      "3600",                 new ValueContainerChar (maxkeep),                       DT_CHARPTR, ValidateWhoWas},\r           {"die",         "value",        "",                     new ValueContainerChar (this->DieValue),                DT_CHARPTR, NoValidation},\r             {"channels",    "users",        "20",                   new ValueContainerUInt (&this->MaxChans),               DT_INTEGER, NoValidation},\r             {"channels",    "opers",        "60",                   new ValueContainerUInt (&this->OperMaxChans),           DT_INTEGER, NoValidation},\r             {NULL}\r };\r\r    /* These tags can occur multiple times, and therefore they have special code to read them\r       * which is different to the code for reading the singular tags listed above.\r   */\r    MultiConfig MultiValues[] = {\r\r         {"connect",\r                            {"allow",       "deny",         "password",     "timeout",      "pingfreq",     "flood",\r                               "threshold",    "sendq",        "recvq",        "localmax",     "globalmax",    "port",\r                                NULL},\r                         {"",            "",             "",             "",             "120",          "",\r                             "",            "",             "",             "3",            "3",            "0",\r                            NULL},\r                                {DT_CHARPTR,    DT_CHARPTR,     DT_CHARPTR,     DT_INTEGER,     DT_INTEGER,     DT_INTEGER,\r                             DT_INTEGER,    DT_INTEGER,     DT_INTEGER,     DT_INTEGER,     DT_INTEGER,     DT_INTEGER},\r                           InitConnect, DoConnect, DoneConnect},\r\r         {"uline",\r                              {"server",      "silent",       NULL},\r                         {"",            "0",            NULL},\r                         {DT_CHARPTR,    DT_BOOLEAN},\r                           InitULine,DoULine,DoneULine},\r\r         {"banlist",\r                            {"chan",        "limit",        NULL},\r                         {"",            "",             NULL},\r                         {DT_CHARPTR,    DT_INTEGER},\r                           InitMaxBans, DoMaxBans, DoneMaxBans},\r\r         {"module",\r                             {"name",        NULL},\r                         {"",            NULL},\r                         {DT_CHARPTR},\r                          InitModule, DoModule, DoneModule},\r\r            {"badip",\r                              {"reason",      "ipmask",       NULL},\r                         {"No reason",   "",             NULL},\r                         {DT_CHARPTR,    DT_CHARPTR},\r                           InitXLine, DoZLine, DoneZLine},\r\r               {"badnick",\r                            {"reason",      "nick",         NULL},\r                         {"No reason",   "",             NULL},\r                         {DT_CHARPTR,    DT_CHARPTR},\r                           InitXLine, DoQLine, DoneQLine},\r\r               {"badhost",\r                            {"reason",      "host",         NULL},\r                         {"No reason",   "",             NULL},\r                         {DT_CHARPTR,    DT_CHARPTR},\r                           InitXLine, DoKLine, DoneKLine},\r\r               {"exception",\r                          {"reason",      "host",         NULL},\r                         {"No reason",   "",             NULL},\r                         {DT_CHARPTR,    DT_CHARPTR},\r                           InitXLine, DoELine, DoneELine},\r\r               {"type",\r                               {"name",        "classes",      NULL},\r                         {"",            "",             NULL},\r                         {DT_CHARPTR,    DT_CHARPTR},\r                           InitTypes, DoType, DoneClassesAndTypes},\r\r              {"class",\r                              {"name",        "commands",     NULL},\r                         {"",            "",             NULL},\r                         {DT_CHARPTR,    DT_CHARPTR},\r                           InitClasses, DoClass, DoneClassesAndTypes},\r\r           {NULL}\r };\r\r    include_stack.clear();\r\r        /* Load and parse the config file, if there are any errors then explode */\r\r    /* Make a copy here so if it fails then we can carry on running with an unaffected config */\r   ConfigDataHash newconfig;\r\r     if (this->LoadConf(newconfig, ServerInstance->ConfigFileName, errstr))\r {\r              /* If we succeeded, set the ircd config to the new one */\r              this->config_data = newconfig;\r }\r      else\r   {\r              ReportConfigError(errstr.str(), bail, user);\r           return;\r        }\r\r     /* The stuff in here may throw CoreException, be sure we're in a position to catch it. */\r      try\r    {\r              /* Check we dont have more than one of singular tags, or any of them missing\r            */\r            for (int Index = 0; Once[Index]; Index++)\r                      if (!CheckOnce(Once[Index], bail, user))\r                               return;\r\r               /* Read the values of all the tags which occur once or not at all, and call their callbacks.\r            */\r            for (int Index = 0; Values[Index].tag; Index++)\r                {\r                      char item[MAXBUF];\r                     int dt = Values[Index].datatype;\r                       bool allow_newlines =  ((dt & DT_ALLOW_NEWLINE) > 0);\r                  dt &= ~DT_ALLOW_NEWLINE;\r\r                      ConfValue(this->config_data, Values[Index].tag, Values[Index].value, Values[Index].default_value, 0, item, MAXBUF, allow_newlines);\r                    ValueItem vi(item);\r\r                   if (!Values[Index].validation_function(this, Values[Index].tag, Values[Index].value, vi))\r                              throw CoreException("One or more values in your configuration file failed to validate. Please see your ircd.log for more information.");\r\r                      switch (Values[Index].datatype)\r                        {\r                              case DT_CHARPTR:\r                               {\r                                      ValueContainerChar* vcc = (ValueContainerChar*)Values[Index].val;\r                                      /* Make sure we also copy the null terminator */\r                                       vcc->Set(vi.GetString(), strlen(vi.GetString()) + 1);\r                          }\r                              break;\r                         case DT_INTEGER:\r                               {\r                                      int val = vi.GetInteger();\r                                     ValueContainerInt* vci = (ValueContainerInt*)Values[Index].val;\r                                        vci->Set(&val, sizeof(int));\r                           }\r                              break;\r                         case DT_BOOLEAN:\r                               {\r                                      bool val = vi.GetBool();\r                                       ValueContainerBool* vcb = (ValueContainerBool*)Values[Index].val;\r                                      vcb->Set(&val, sizeof(bool));\r                          }\r                              break;\r                         default:\r                                       /* You don't want to know what happens if someones bad code sends us here. */\r                          break;\r                 }\r\r                     /* We're done with this now */\r                 delete Values[Index].val;\r              }\r\r             /* Read the multiple-tag items (class tags, connect tags, etc)\r          * and call the callbacks associated with them. We have three\r           * callbacks for these, a 'start', 'item' and 'end' callback.\r           */\r            for (int Index = 0; MultiValues[Index].tag; Index++)\r           {\r                      MultiValues[Index].init_function(this, MultiValues[Index].tag);\r\r                       int number_of_tags = ConfValueEnum(this->config_data, MultiValues[Index].tag);\r\r                        for (int tagnum = 0; tagnum < number_of_tags; tagnum++)\r                        {\r                              ValueList vl;\r                          for (int valuenum = 0; MultiValues[Index].items[valuenum]; valuenum++)\r                         {\r                                      int dt = MultiValues[Index].datatype[valuenum];\r                                        bool allow_newlines =  ((dt & DT_ALLOW_NEWLINE) > 0);\r                                  dt &= ~DT_ALLOW_NEWLINE;\r\r                                      switch (dt)\r                                    {\r                                              case DT_CHARPTR:\r                                               {\r                                                      char item[MAXBUF];\r                                                     if (ConfValue(this->config_data, MultiValues[Index].tag, MultiValues[Index].items[valuenum], MultiValues[Index].items_default[valuenum], tagnum, item, MAXBUF, allow_newlines))\r                                                                vl.push_back(ValueItem(item));\r                                                 else\r                                                           vl.push_back(ValueItem(""));\r                                           }\r                                              break;\r                                         case DT_INTEGER:\r                                               {\r                                                      int item = 0;\r                                                  if (ConfValueInteger(this->config_data, MultiValues[Index].tag, MultiValues[Index].items[valuenum], MultiValues[Index].items_default[valuenum], tagnum, item))\r                                                         vl.push_back(ValueItem(item));\r                                                 else\r                                                           vl.push_back(ValueItem(0));\r                                            }\r                                              break;\r                                         case DT_BOOLEAN:\r                                               {\r                                                      bool item = ConfValueBool(this->config_data, MultiValues[Index].tag, MultiValues[Index].items[valuenum], MultiValues[Index].items_default[valuenum], tagnum);\r                                                  vl.push_back(ValueItem(item));\r                                         }\r                                              break;\r                                         default:\r                                                       /* Someone was smoking craq if we got here, and we're all gonna die. */\r                                                break;\r                                 }\r                              }\r\r                             MultiValues[Index].validation_function(this, MultiValues[Index].tag, (char**)MultiValues[Index].items, vl, MultiValues[Index].datatype);\r                       }\r\r                     MultiValues[Index].finish_function(this, MultiValues[Index].tag);\r              }\r\r     }\r\r     catch (CoreException &ce)\r      {\r              ReportConfigError(ce.GetReason(), bail, user);\r         return;\r        }\r\r     // write once here, to try it out and make sure its ok\r ServerInstance->WritePID(this->PID);\r\r  ServerInstance->Log(DEFAULT,"Done reading configuration file.");\r\r      /* If we're rehashing, let's load any new modules, and unload old ones\r  */\r    if (!bail)\r     {\r              int found_ports = 0;\r           FailedPortList pl;\r             ServerInstance->BindPorts(false, found_ports, pl);\r\r            if (pl.size())\r         {\r                      user->WriteServ("NOTICE %s :*** Not all your client ports could be bound.", user->nick);\r                       user->WriteServ("NOTICE %s :*** The following port(s) failed to bind:", user->nick);\r                   int j = 1;\r                     for (FailedPortList::iterator i = pl.begin(); i != pl.end(); i++, j++)\r                 {\r                              user->WriteServ("NOTICE %s :*** %d.   IP: %s     Port: %lu", user->nick, j, i->first.empty() ? "<all>" : i->first.c_str(), (unsigned long)i->second);\r                  }\r              }\r\r             if (!removed_modules.empty())\r          {\r                      for (std::vector<std::string>::iterator removing = removed_modules.begin(); removing != removed_modules.end(); removing++)\r                     {\r                              if (ServerInstance->UnloadModule(removing->c_str()))\r                           {\r                                      ServerInstance->WriteOpers("*** REHASH UNLOADED MODULE: %s",removing->c_str());\r\r                                       if (user)\r                                              user->WriteServ("973 %s %s :Module %s successfully unloaded.",user->nick, removing->c_str(), removing->c_str());\r\r                                      rem++;\r                         }\r                              else\r                           {\r                                      if (user)\r                                              user->WriteServ("972 %s %s :Failed to unload module %s: %s",user->nick, removing->c_str(), removing->c_str(), ServerInstance->ModuleError());\r                          }\r                      }\r              }\r\r             if (!added_modules.empty())\r            {\r                      for (std::vector<std::string>::iterator adding = added_modules.begin(); adding != added_modules.end(); adding++)\r                       {\r                              if (ServerInstance->LoadModule(adding->c_str()))\r                               {\r                                      ServerInstance->WriteOpers("*** REHASH LOADED MODULE: %s",adding->c_str());\r\r                                   if (user)\r                                              user->WriteServ("975 %s %s :Module %s successfully loaded.",user->nick, adding->c_str(), adding->c_str());\r\r                                    add++;\r                         }\r                              else\r                           {\r                                      if (user)\r                                              user->WriteServ("974 %s %s :Failed to load module %s: %s",user->nick, adding->c_str(), adding->c_str(), ServerInstance->ModuleError());\r                                }\r                      }\r              }\r\r             ServerInstance->Log(DEFAULT,"Successfully unloaded %lu of %lu modules and loaded %lu of %lu modules.",(unsigned long)rem,(unsigned long)removed_modules.size(),(unsigned long)add,(unsigned long)added_modules.size());\r        }\r\r     if (user)\r              user->WriteServ("NOTICE %s :*** Successfully rehashed server.", user->nick);\r   else\r           ServerInstance->WriteOpers("*** Successfully rehashed server.");\r}\r\rbool ServerConfig::LoadConf(ConfigDataHash &target, const char* filename, std::ostringstream &errorstream)\r{\r       std::ifstream conf(filename);\r  std::string line;\r      char ch;\r       long linenumber;\r       bool in_tag;\r   bool in_quote;\r bool in_comment;\r       int character_count = 0;\r\r      linenumber = 1;\r        in_tag = false;\r        in_quote = false;\r      in_comment = false;\r\r   /* Check if the file open failed first */\r      if (!conf)\r     {\r              errorstream << "LoadConf: Couldn't open config file: " << filename << std::endl;\r               return false;\r  }\r\r     /* Fix the chmod of the file to restrict it to the current user and group */\r   chmod(filename,0600);\r\r for (unsigned int t = 0; t < include_stack.size(); t++)\r        {\r              if (std::string(filename) == include_stack[t])\r         {\r                      errorstream << "File " << filename << " is included recursively (looped inclusion)." << std::endl;\r                     return false;\r          }\r      }\r\r     /* It's not already included, add it to the list of files we've loaded */\r      include_stack.push_back(filename);\r\r    /* Start reading characters... */\r      while(conf.get(ch))\r    {\r\r             /*\r              * Fix for moronic windows issue spotted by Adremelech.\r                 * Some windows editors save text files as utf-16, which is\r             * a total pain in the ass to parse. Users should save in the\r           * right config format! If we ever see a file where the first\r           * byte is 0xFF or 0xFE, or the second is 0xFF or 0xFE, then\r            * this is most likely a utf-16 file. Bail out and insult user.\r                 */\r            if ((character_count++ < 2) && (ch == '\xFF' || ch == '\xFE'))\r         {\r                      errorstream << "File " << filename << " cannot be read, as it is encoded in braindead UTF-16. Save your file as plain ASCII!" << std::endl;\r                    return false;\r          }\r\r             /*\r              * Here we try and get individual tags on separate lines,\r               * this would be so easy if we just made people format\r          * their config files like that, but they don't so...\r           * We check for a '<' and then know the line is over when\r               * we get a '>' not inside quotes. If we find two '<' and\r               * no '>' then die with an error.\r               */\r\r           if((ch == '#') && !in_quote)\r                   in_comment = true;\r\r            switch(ch)\r             {\r                      case '\n':\r                             if (in_quote)\r                                  line += '\n';\r                          linenumber++;\r                  case '\r':\r                             if (!in_quote)\r                                 in_comment = false;\r                    case '\0':\r                             continue;\r                      case '\t':\r                             ch = ' ';\r              }\r\r             if(in_comment)\r                 continue;\r\r             /* XXX: Added by Brain, May 1st 2006 - Escaping of characters.\r          * Note that this WILL NOT usually allow insertion of newlines,\r                 * because a newline is two characters long. Use it primarily to\r                * insert the " symbol.\r                 *\r              * Note that this also involves a further check when parsing the line,\r          * which can be found below.\r            */\r            if ((ch == '\\') && (in_quote) && (in_tag))\r            {\r                      line += ch;\r                    char real_character;\r                   if (conf.get(real_character))\r                  {\r                              if (real_character == 'n')\r                                     real_character = '\n';\r                         line += real_character;\r                                continue;\r                      }\r                      else\r                   {\r                              errorstream << "End of file after a \\, what did you want to escape?: " << filename << ":" << linenumber << std::endl;\r                         return false;\r                  }\r              }\r\r             if (ch != '\r')\r                        line += ch;\r\r           if(ch == '<')\r          {\r                      if(in_tag)\r                     {\r                              if(!in_quote)\r                          {\r                                      errorstream << "Got another opening < when the first one wasn't closed: " << filename << ":" << linenumber << std::endl;\r                                       return false;\r                          }\r                      }\r                      else\r                   {\r                              if(in_quote)\r                           {\r                                      errorstream << "We're in a quote but outside a tag, interesting. " << filename << ":" << linenumber << std::endl;\r                                      return false;\r                          }\r                              else\r                           {\r                                      // errorstream << "Opening new config tag on line " << linenumber << std::endl;\r                                        in_tag = true;\r                         }\r                      }\r              }\r              else if(ch == '"')\r             {\r                      if(in_tag)\r                     {\r                              if(in_quote)\r                           {\r                                      // errorstream << "Closing quote in config tag on line " << linenumber << std::endl;\r                                   in_quote = false;\r                              }\r                              else\r                           {\r                                      // errorstream << "Opening quote in config tag on line " << linenumber << std::endl;\r                                   in_quote = true;\r                               }\r                      }\r                      else\r                   {\r                              if(in_quote)\r                           {\r                                      errorstream << "Found a (closing) \" outside a tag: " << filename << ":" << linenumber << std::endl;\r                           }\r                              else\r                           {\r                                      errorstream << "Found a (opening) \" outside a tag: " << filename << ":" << linenumber << std::endl;\r                           }\r                      }\r              }\r              else if(ch == '>')\r             {\r                      if(!in_quote)\r                  {\r                              if(in_tag)\r                             {\r                                      // errorstream << "Closing config tag on line " << linenumber << std::endl;\r                                    in_tag = false;\r\r                                       /*\r                                      * If this finds an <include> then ParseLine can simply call\r                                    * LoadConf() and load the included config into the same ConfigDataHash\r                                         */\r\r                                   if(!this->ParseLine(target, line, linenumber, errorstream))\r                                            return false;\r\r                                 line.clear();\r                          }\r                              else\r                           {\r                                      errorstream << "Got a closing > when we weren't inside a tag: " << filename << ":" << linenumber << std::endl;\r                                 return false;\r                          }\r                      }\r              }\r      }\r\r     return true;\r}\r\rbool ServerConfig::LoadConf(ConfigDataHash &target, const std::string &filename, std::ostringstream &errorstream)\r{\r    return this->LoadConf(target, filename.c_str(), errorstream);\r}\r\rbool ServerConfig::ParseLine(ConfigDataHash &target, std::string &line, long linenumber, std::ostringstream &errorstream)\r{\r   std::string tagname;\r   std::string current_key;\r       std::string current_value;\r     KeyValList results;\r    bool got_name;\r bool got_key;\r  bool in_quote;\r\r        got_name = got_key = in_quote = false;\r\r        //std::cout << "ParseLine(data, '" << line << "', " << linenumber << ", stream)" << std::endl;\r\r        for(std::string::iterator c = line.begin(); c != line.end(); c++)\r      {\r              if(!got_name)\r          {\r                      /* We don't know the tag name yet. */\r\r                 if(*c != ' ')\r                  {\r                              if(*c != '<')\r                          {\r                                      tagname += *c;\r                         }\r                      }\r                      else\r                   {\r                              /* We got to a space, we should have the tagname now. */\r                               if(tagname.length())\r                           {\r                                      got_name = true;\r                               }\r                      }\r              }\r              else\r           {\r                      /* We have the tag name */\r                     if (!got_key)\r                  {\r                              /* We're still reading the key name */\r                         if (*c != '=')\r                         {\r                                      if (*c != ' ')\r                                 {\r                                              current_key += *c;\r                                     }\r                              }\r                              else\r                           {\r                                      /* We got an '=', end of the key name. */\r                                      got_key = true;\r                                }\r                      }\r                      else\r                   {\r                              /* We have the key name, now we're looking for quotes and the value */\r\r                                /* Correctly handle escaped characters here.\r                            * See the XXX'ed section above.\r                                */\r                            if ((*c == '\\') && (in_quote))\r                                {\r                                      c++;\r                                   if (*c == 'n')\r                                         current_value += '\n';\r                                 else\r                                           current_value += *c;\r                                   continue;\r                              }\r                              else if ((*c == '\n') && (in_quote))\r                           {\r                                      /* Got a 'real' \n, treat it as part of the value */\r                                   current_value += '\n';\r                                 continue;\r                              }\r                              else if ((*c == '\r') && (in_quote))\r                                   /* Got a \r, drop it */\r                                        continue;\r\r                             if (*c == '"')\r                         {\r                                      if (!in_quote)\r                                 {\r                                              /* We're not already in a quote. */\r                                            in_quote = true;\r                                       }\r                                      else\r                                   {\r                                              /* Leaving quotes, we have the value */\r                                                results.push_back(KeyVal(current_key, current_value));\r\r                                                // std::cout << "<" << tagname << ":" << current_key << "> " << current_value << std::endl;\r\r                                           in_quote = false;\r                                              got_key = false;\r\r                                              if((tagname == "include") && (current_key == "file"))\r                                          {\r                                                      if(!this->DoInclude(target, current_value, errorstream))\r                                                               return false;\r                                          }\r\r                                             current_key.clear();\r                                           current_value.clear();\r                                 }\r                              }\r                              else\r                           {\r                                      if(in_quote)\r                                   {\r                                              current_value += *c;\r                                   }\r                              }\r                      }\r              }\r      }\r\r     /* Finished parsing the tag, add it to the config hash */\r      target.insert(std::pair<std::string, KeyValList > (tagname, results));\r\r        return true;\r}\r\rbool ServerConfig::DoInclude(ConfigDataHash &target, const std::string &file, std::ostringstream &errorstream)\r{\r       std::string confpath;\r  std::string newfile;\r   std::string::size_type pos;\r\r   confpath = ServerInstance->ConfigFileName;\r     newfile = file;\r\r       for (std::string::iterator c = newfile.begin(); c != newfile.end(); c++)\r       {\r              if (*c == '\\')\r                {\r                      *c = '/';\r              }\r      }\r\r     if (file[0] != '/')\r    {\r              if((pos = confpath.rfind("/")) != std::string::npos)\r           {\r                      /* Leaves us with just the path */\r                     newfile = confpath.substr(0, pos) + std::string("/") + newfile;\r                }\r              else\r           {\r                      errorstream << "Couldn't get config path from: " << confpath << std::endl;\r                     return false;\r          }\r      }\r\r     return LoadConf(target, newfile, errorstream);\r}\r\rbool ServerConfig::ConfValue(ConfigDataHash &target, const char* tag, const char* var, int index, char* result, int length, bool allow_linefeeds)\r{\r  return ConfValue(target, tag, var, "", index, result, length, allow_linefeeds);\r}\r\rbool ServerConfig::ConfValue(ConfigDataHash &target, const char* tag, const char* var, const char* default_value, int index, char* result, int length, bool allow_linefeeds)\r{\r      std::string value;\r     bool r = ConfValue(target, std::string(tag), std::string(var), std::string(default_value), index, value, allow_linefeeds);\r     strlcpy(result, value.c_str(), length);\r        return r;\r}\r\rbool ServerConfig::ConfValue(ConfigDataHash &target, const std::string &tag, const std::string &var, int index, std::string &result, bool allow_linefeeds)\r{\r      return ConfValue(target, tag, var, "", index, result, allow_linefeeds);\r}\r\rbool ServerConfig::ConfValue(ConfigDataHash &target, const std::string &tag, const std::string &var, const std::string &default_value, int index, std::string &result, bool allow_linefeeds)\r{\r      ConfigDataHash::size_type pos = index;\r if((pos >= 0) && (pos < target.count(tag)))\r    {\r              ConfigDataHash::iterator iter = target.find(tag);\r\r             for(int i = 0; i < index; i++)\r                 iter++;\r\r               for(KeyValList::iterator j = iter->second.begin(); j != iter->second.end(); j++)\r               {\r                      if(j->first == var)\r                    {\r                              if ((!allow_linefeeds) && (j->second.find('\n') != std::string::npos))\r                         {\r                                      ServerInstance->Log(DEFAULT, "Value of <" + tag + ":" + var+ "> contains a linefeed, and linefeeds in this value are not permitted -- stripped to spaces.");\r                                   for (std::string::iterator n = j->second.begin(); n != j->second.end(); n++)\r                                           if (*n == '\n')\r                                                        *n = ' ';\r                              }\r                              else\r                           {\r                                      result = j->second;\r                                    return true;\r                           }\r                      }\r              }\r              if (!default_value.empty())\r            {\r                      result = default_value;\r                        return true;\r           }\r      }\r      else if(pos == 0)\r      {\r              if (!default_value.empty())\r            {\r                      result = default_value;\r                        return true;\r           }\r      }\r      return false;\r}\r\rbool ServerConfig::ConfValueInteger(ConfigDataHash &target, const char* tag, const char* var, int index, int &result)\r{\r       return ConfValueInteger(target, std::string(tag), std::string(var), "", index, result);\r}\r\rbool ServerConfig::ConfValueInteger(ConfigDataHash &target, const char* tag, const char* var, const char* default_value, int index, int &result)\r{\r  return ConfValueInteger(target, std::string(tag), std::string(var), std::string(default_value), index, result);\r}\r\rbool ServerConfig::ConfValueInteger(ConfigDataHash &target, const std::string &tag, const std::string &var, int index, int &result)\r{\r       return ConfValueInteger(target, tag, var, "", index, result);\r}\r\rbool ServerConfig::ConfValueInteger(ConfigDataHash &target, const std::string &tag, const std::string &var, const std::string &default_value, int index, int &result)\r{\r       std::string value;\r     std::istringstream stream;\r     bool r = ConfValue(target, tag, var, default_value, index, value);\r     stream.str(value);\r     if(!(stream >> result))\r                return false;\r  else\r   {\r              if (!value.empty())\r            {\r                      if (value.substr(0,2) == "0x")\r                 {\r                              char* endptr;\r\r                         value.erase(0,2);\r                              result = strtol(value.c_str(), &endptr, 16);\r\r                          /* No digits found */\r                          if (endptr == value.c_str())\r                                   return false;\r                  }\r                      else\r                   {\r                              char denominator = *(value.end() - 1);\r                         switch (toupper(denominator))\r                          {\r                                      case 'K':\r                                              /* Kilobytes -> bytes */\r                                               result = result * 1024;\r                                        break;\r                                 case 'M':\r                                              /* Megabytes -> bytes */\r                                               result = result * 1024 * 1024;\r                                 break;\r                                 case 'G':\r                                              /* Gigabytes -> bytes */\r                                               result = result * 1024 * 1024 * 1024;\r                                  break;\r                         }\r                      }\r              }\r      }\r      return r;\r}\r\r\rbool ServerConfig::ConfValueBool(ConfigDataHash &target, const char* tag, const char* var, int index)\r{\r  return ConfValueBool(target, std::string(tag), std::string(var), "", index);\r}\r\rbool ServerConfig::ConfValueBool(ConfigDataHash &target, const char* tag, const char* var, const char* default_value, int index)\r{\r     return ConfValueBool(target, std::string(tag), std::string(var), std::string(default_value), index);\r}\r\rbool ServerConfig::ConfValueBool(ConfigDataHash &target, const std::string &tag, const std::string &var, int index)\r{\r  return ConfValueBool(target, tag, var, "", index);\r}\r\rbool ServerConfig::ConfValueBool(ConfigDataHash &target, const std::string &tag, const std::string &var, const std::string &default_value, int index)\r{\r  std::string result;\r    if(!ConfValue(target, tag, var, default_value, index, result))\r         return false;\r\r return ((result == "yes") || (result == "true") || (result == "1"));\r}\r\rint ServerConfig::ConfValueEnum(ConfigDataHash &target, const char* tag)\r{\r     return target.count(tag);\r}\r\rint ServerConfig::ConfValueEnum(ConfigDataHash &target, const std::string &tag)\r{\r return target.count(tag);\r}\r\rint ServerConfig::ConfVarEnum(ConfigDataHash &target, const char* tag, int index)\r{\r       return ConfVarEnum(target, std::string(tag), index);\r}\r\rint ServerConfig::ConfVarEnum(ConfigDataHash &target, const std::string &tag, int index)\r{\r     ConfigDataHash::size_type pos = index;\r\r        if((pos >= 0) && (pos < target.count(tag)))\r    {\r              ConfigDataHash::const_iterator iter = target.find(tag);\r\r               for(int i = 0; i < index; i++)\r                 iter++;\r\r               return iter->second.size();\r    }\r\r     return 0;\r}\r\r/** Read the contents of a file located by `fname' into a file_cache pointed at by `F'.\r */\rbool ServerConfig::ReadFile(file_cache &F, const char* fname)\r{\r       if (!fname || !*fname)\r         return false;\r\r FILE* file = NULL;\r     char linebuf[MAXBUF];\r\r F.clear();\r\r    if ((*fname != '/') && (*fname != '\\'))\r       {\r              std::string::size_type pos;\r            std::string confpath = ServerInstance->ConfigFileName;\r         std::string newfile = fname;\r\r          if ((pos = confpath.rfind("/")) != std::string::npos)\r                  newfile = confpath.substr(0, pos) + std::string("/") + fname;\r          else if ((pos = confpath.rfind("\\")) != std::string::npos)\r                    newfile = confpath.substr(0, pos) + std::string("\\") + fname;\r\r                if (!FileExists(newfile.c_str()))\r                      return false;\r          file =  fopen(newfile.c_str(), "r");\r   }\r      else\r   {\r              if (!FileExists(fname))\r                        return false;\r          file =  fopen(fname, "r");\r     }\r\r     if (file)\r      {\r              while (!feof(file))\r            {\r                      if (fgets(linebuf, sizeof(linebuf), file))\r                             linebuf[strlen(linebuf)-1] = 0;\r                        else\r                           *linebuf = 0;\r\r                 if (!feof(file))\r                       {\r                              F.push_back(*linebuf ? linebuf : " ");\r                 }\r              }\r\r             fclose(file);\r  }\r      else\r           return false;\r\r return true;\r}\r\rbool ServerConfig::FileExists(const char* file)\r{\r      struct stat sb;\r        if (stat(file, &sb) == -1)\r             return false;\r\r if ((sb.st_mode & S_IFDIR) > 0)\r                return false;\r       \r  FILE *input;\r   if ((input = fopen (file, "r")) == NULL)\r               return false;\r  else\r   {\r              fclose(input);\r         return true;\r   }\r}\r\rchar* ServerConfig::CleanFilename(char* name)\r{\r   char* p = name + strlen(name);\r while ((p != name) && (*p != '/') && (*p != '\\')) p--;\r        return (p != name ? ++p : p);\r}\r\r\rbool ServerConfig::DirValid(const char* dirandfile)\r{\r#ifdef WINDOWS\r return true;\r#endif\r\r   char work[1024];\r       char buffer[1024];\r     char otherdir[1024];\r   int p;\r\r        strlcpy(work, dirandfile, 1024);\r       p = strlen(work);\r\r     // we just want the dir\r        while (*work)\r  {\r              if (work[p] == '/')\r            {\r                      work[p] = '\0';\r                        break;\r         }\r\r             work[p--] = '\0';\r      }\r\r     // Get the current working directory\r   if (getcwd(buffer, 1024 ) == NULL )\r            return false;\r\r if (chdir(work) == -1)\r         return false;\r\r if (getcwd(otherdir, 1024 ) == NULL )\r          return false;\r\r if (chdir(buffer) == -1)\r               return false;\r\r size_t t = strlen(work);\r\r      if (strlen(otherdir) >= t)\r     {\r              otherdir[t] = '\0';\r            if (!strcmp(otherdir,work))\r            {\r                      return true;\r           }\r\r             return false;\r  }\r      else\r   {\r              return false;\r  }\r}\r\rstd::string ServerConfig::GetFullProgDir()\r{\r      char buffer[PATH_MAX+1];\r#ifdef WINDOWS\r        /* Windows has specific api calls to get the exe path that never fail.\r  * For once, windows has something of use, compared to the POSIX code\r   * for this, this is positively neato.\r  */\r    if (GetModuleFileName(NULL, buffer, MAX_PATH))\r {\r              std::string fullpath = buffer;\r         std::string::size_type n = fullpath.rfind("\\inspircd.exe");\r           return std::string(fullpath, 0, n);\r    }\r#else\r        // Get the current working directory\r   if (getcwd(buffer, PATH_MAX))\r  {\r              std::string remainder = this->argv[0];\r\r                /* Does argv[0] start with /? its a full path, use it */\r               if (remainder[0] == '/')\r               {\r                      std::string::size_type n = remainder.rfind("/inspircd");\r                       return std::string(remainder, 0, n);\r           }\r\r             std::string fullpath = std::string(buffer) + "/" + remainder;\r          std::string::size_type n = fullpath.rfind("/inspircd");\r                return std::string(fullpath, 0, n);\r    }\r#endif\r       return "/";\r}\r\rInspIRCd* ServerConfig::GetInstance()\r{\r return ServerInstance;\r}\r\r\rValueItem::ValueItem(int value)\r{\r   std::stringstream n;\r   n << value;\r    v = n.str();\r}\r\rValueItem::ValueItem(bool value)\r{\r     std::stringstream n;\r   n << value;\r    v = n.str();\r}\r\rValueItem::ValueItem(char* value)\r{\r    v = value;\r}\r\rvoid ValueItem::Set(char* value)\r{\r       v = value;\r}\r\rvoid ValueItem::Set(const char* value)\r{\r v = value;\r}\r\rvoid ValueItem::Set(int value)\r{\r std::stringstream n;\r   n << value;\r    v = n.str();\r}\r\rint ValueItem::GetInteger()\r{\r  if (v.empty())\r         return 0;\r      return atoi(v.c_str());\r}\r\rchar* ValueItem::GetString()\r{\r      return (char*)v.c_str();\r}\r\rbool ValueItem::GetBool()\r{\r        return (GetInteger() || v == "yes" || v == "true");\r}\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "configreader.h"
+#include <sstream>
+#include <fstream>
+#include "xline.h"
+#include "exitcodes.h"
+#include "commands/cmd_whowas.h"
+
+std::vector<std::string> old_module_names, new_module_names, added_modules, removed_modules;
+
+ServerConfig::ServerConfig(InspIRCd* Instance) : ServerInstance(Instance)
+{
+       this->ClearStack();
+       *ServerName = *Network = *ServerDesc = *AdminName = '\0';
+       *HideWhoisServer = *AdminEmail = *AdminNick = *diepass = *restartpass = *FixedQuit = *HideKillsServer = '\0';
+       *DefaultModes = *CustomVersion = *motd = *rules = *PrefixQuit = *DieValue = *DNSServer = '\0';
+       *UserStats = *ModPath = *MyExecutable = *DisabledCommands = *PID = *SuffixQuit = '\0';
+       WhoWasGroupSize = WhoWasMaxGroups = WhoWasMaxKeep = 0;
+       log_file = NULL;
+       NoUserDns = forcedebug = OperSpyWhois = nofork = HideBans = HideSplits = UndernetMsgPrefix = false;
+       CycleHosts = writelog = AllowHalfop = true;
+       dns_timeout = DieDelay = 5;
+       MaxTargets = 20;
+       NetBufferSize = 10240;
+       SoftLimit = MAXCLIENTS;
+       MaxConn = SOMAXCONN;
+       MaxWhoResults = 0;
+       debugging = 0;
+       MaxChans = 20;
+       OperMaxChans = 30;
+       LogLevel = DEFAULT;
+       maxbans.clear();
+}
+
+void ServerConfig::ClearStack()
+{
+       include_stack.clear();
+}
+
+Module* ServerConfig::GetIOHook(int port)
+{
+       std::map<int,Module*>::iterator x = IOHookModule.find(port);
+       return (x != IOHookModule.end() ? x->second : NULL);
+}
+
+Module* ServerConfig::GetIOHook(InspSocket* is)
+{
+       std::map<InspSocket*,Module*>::iterator x = SocketIOHookModule.find(is);
+       return (x != SocketIOHookModule.end() ? x->second : NULL);
+}
+
+bool ServerConfig::AddIOHook(int port, Module* iomod)
+{
+       if (!GetIOHook(port))
+       {
+               IOHookModule[port] = iomod;
+               return true;
+       }
+       else
+       {
+               throw ModuleException("Port already hooked by another module");
+               return false;
+       }
+}
+
+bool ServerConfig::AddIOHook(Module* iomod, InspSocket* is)
+{
+       if (!GetIOHook(is))
+       {
+               SocketIOHookModule[is] = iomod;
+               is->IsIOHooked = true;
+               return true;
+       }
+       else
+       {
+               throw ModuleException("InspSocket derived class already hooked by another module");
+               return false;
+       }
+}
+
+bool ServerConfig::DelIOHook(int port)
+{
+       std::map<int,Module*>::iterator x = IOHookModule.find(port);
+       if (x != IOHookModule.end())
+       {
+               IOHookModule.erase(x);
+               return true;
+       }
+       return false;
+}
+
+bool ServerConfig::DelIOHook(InspSocket* is)
+{
+       std::map<InspSocket*,Module*>::iterator x = SocketIOHookModule.find(is);
+       if (x != SocketIOHookModule.end())
+       {
+               SocketIOHookModule.erase(x);
+               return true;
+       }
+       return false;
+}
+
+void ServerConfig::Update005()
+{
+       std::stringstream out(data005);
+       std::string token;
+       std::string line5;
+       int token_counter = 0;
+       isupport.clear();
+       while (out >> token)
+       {
+               line5 = line5 + token + " ";
+               token_counter++;
+               if (token_counter >= 13)
+               {
+                       char buf[MAXBUF];
+                       snprintf(buf, MAXBUF, "%s:are supported by this server", line5.c_str());
+                       isupport.push_back(buf);
+                       line5.clear();
+                       token_counter = 0;
+               }
+       }
+       if (!line5.empty())
+       {
+               char buf[MAXBUF];
+               snprintf(buf, MAXBUF, "%s:are supported by this server", line5.c_str());
+               isupport.push_back(buf);
+       }
+}
+
+void ServerConfig::Send005(userrec* user)
+{
+       for (std::vector<std::string>::iterator line = ServerInstance->Config->isupport.begin(); line != ServerInstance->Config->isupport.end(); line++)
+               user->WriteServ("005 %s %s", user->nick, line->c_str());
+}
+
+bool ServerConfig::CheckOnce(char* tag, bool bail, userrec* user)
+{
+       int count = ConfValueEnum(this->config_data, tag);
+
+       if (count > 1)
+       {
+               throw CoreException("You have more than one <"+std::string(tag)+"> tag, this is not permitted.");
+               return false;
+       }
+       if (count < 1)
+       {
+               throw CoreException("You have not defined a <"+std::string(tag)+"> tag, this is required.");
+               return false;
+       }
+       return true;
+}
+
+bool NoValidation(ServerConfig* conf, const char* tag, const char* value, ValueItem &data)
+{
+       return true;
+}
+
+bool ValidateMaxTargets(ServerConfig* conf, const char* tag, const char* value, ValueItem &data)
+{
+       if ((data.GetInteger() < 0) || (data.GetInteger() > 31))
+       {
+               conf->GetInstance()->Log(DEFAULT,"WARNING: <options:maxtargets> value is greater than 31 or less than 0, set to 20.");
+               data.Set(20);
+       }
+       return true;
+}
+
+bool ValidateSoftLimit(ServerConfig* conf, const char* tag, const char* value, ValueItem &data)
+{
+       if ((data.GetInteger() < 1) || (data.GetInteger() > MAXCLIENTS))
+       {
+               conf->GetInstance()->Log(DEFAULT,"WARNING: <options:softlimit> value is greater than %d or less than 0, set to %d.",MAXCLIENTS,MAXCLIENTS);
+               data.Set(MAXCLIENTS);
+       }
+       return true;
+}
+
+bool ValidateMaxConn(ServerConfig* conf, const char* tag, const char* value, ValueItem &data)
+{
+       if (data.GetInteger() > SOMAXCONN)
+               conf->GetInstance()->Log(DEFAULT,"WARNING: <options:somaxconn> value may be higher than the system-defined SOMAXCONN value!");
+       return true;
+}
+
+bool InitializeDisabledCommands(const char* data, InspIRCd* ServerInstance)
+{
+       std::stringstream dcmds(data);
+       std::string thiscmd;
+
+       /* Enable everything first */
+       for (command_table::iterator x = ServerInstance->Parser->cmdlist.begin(); x != ServerInstance->Parser->cmdlist.end(); x++)
+               x->second->Disable(false);
+
+       /* Now disable all the ones which the user wants disabled */
+       while (dcmds >> thiscmd)
+       {
+               command_table::iterator cm = ServerInstance->Parser->cmdlist.find(thiscmd);
+               if (cm != ServerInstance->Parser->cmdlist.end())
+               {
+                       cm->second->Disable(true);
+               }
+       }
+       return true;
+}
+
+bool ValidateDnsServer(ServerConfig* conf, const char* tag, const char* value, ValueItem &data)
+{
+       if (!*(data.GetString()))
+       {
+               std::string nameserver;
+#ifdef WINDOWS
+               conf->GetInstance()->Log(DEFAULT,"WARNING: <dns:server> not defined, attempting to find working server in the registry...");
+               nameserver = FindNameServerWin();
+               /* Windows stacks multiple nameservers in one registry key, seperated by commas.
+                * Spotted by Cataclysm.
+                */
+               if (nameserver.find(',') != std::string::npos)
+                       nameserver = nameserver.substr(0, nameserver.find(','));
+               data.Set(nameserver.c_str());
+               conf->GetInstance()->Log(DEFAULT,"<dns:server> set to '%s' as first active resolver in registry.", nameserver.c_str());
+#else
+               // attempt to look up their nameserver from /etc/resolv.conf
+               conf->GetInstance()->Log(DEFAULT,"WARNING: <dns:server> not defined, attempting to find working server in /etc/resolv.conf...");
+               ifstream resolv("/etc/resolv.conf");
+               bool found_server = false;
+
+               if (resolv.is_open())
+               {
+                       while (resolv >> nameserver)
+                       {
+                               if ((nameserver == "nameserver") && (!found_server))
+                               {
+                                       resolv >> nameserver;
+                                       data.Set(nameserver.c_str());
+                                       found_server = true;
+                                       conf->GetInstance()->Log(DEFAULT,"<dns:server> set to '%s' as first resolver in /etc/resolv.conf.",nameserver.c_str());
+                               }
+                       }
+
+                       if (!found_server)
+                       {
+                               conf->GetInstance()->Log(DEFAULT,"/etc/resolv.conf contains no viable nameserver entries! Defaulting to nameserver '127.0.0.1'!");
+                               data.Set("127.0.0.1");
+                       }
+               }
+               else
+               {
+                       conf->GetInstance()->Log(DEFAULT,"/etc/resolv.conf can't be opened! Defaulting to nameserver '127.0.0.1'!");
+                       data.Set("127.0.0.1");
+               }
+#endif
+       }
+       return true;
+}
+
+bool ValidateServerName(ServerConfig* conf, const char* tag, const char* value, ValueItem &data)
+{
+       /* If we already have a servername, and they changed it, we should throw an exception. */
+       if ((strcasecmp(conf->ServerName, data.GetString())) && (*conf->ServerName))
+       {
+               throw CoreException("Configuration error: You cannot change your servername at runtime! Please restart your server for this change to be applied.");
+               /* XXX: We don't actually reach this return of course... */
+               return false;
+       }
+       if (!strchr(data.GetString(),'.'))
+       {
+               conf->GetInstance()->Log(DEFAULT,"WARNING: <server:name> '%s' is not a fully-qualified domain name. Changed to '%s%c'",data.GetString(),data.GetString(),'.');
+               std::string moo = std::string(data.GetString()).append(".");
+               data.Set(moo.c_str());
+       }
+       return true;
+}
+
+bool ValidateNetBufferSize(ServerConfig* conf, const char* tag, const char* value, ValueItem &data)
+{
+       if ((!data.GetInteger()) || (data.GetInteger() > 65535) || (data.GetInteger() < 1024))
+       {
+               conf->GetInstance()->Log(DEFAULT,"No NetBufferSize specified or size out of range, setting to default of 10240.");
+               data.Set(10240);
+       }
+       return true;
+}
+
+bool ValidateMaxWho(ServerConfig* conf, const char* tag, const char* value, ValueItem &data)
+{
+       if ((data.GetInteger() > 65535) || (data.GetInteger() < 1))
+       {
+               conf->GetInstance()->Log(DEFAULT,"<options:maxwhoresults> size out of range, setting to default of 128.");
+               data.Set(128);
+       }
+       return true;
+}
+
+bool ValidateLogLevel(ServerConfig* conf, const char* tag, const char* value, ValueItem &data)
+{
+       std::string dbg = data.GetString();
+       conf->LogLevel = DEFAULT;
+
+       if (dbg == "debug")
+               conf->LogLevel = DEBUG;
+       else if (dbg  == "verbose")
+               conf->LogLevel = VERBOSE;
+       else if (dbg == "default")
+               conf->LogLevel = DEFAULT;
+       else if (dbg == "sparse")
+               conf->LogLevel = SPARSE;
+       else if (dbg == "none")
+               conf->LogLevel = NONE;
+
+       conf->debugging = (conf->LogLevel == DEBUG);
+
+       return true;
+}
+
+bool ValidateMotd(ServerConfig* conf, const char* tag, const char* value, ValueItem &data)
+{
+       conf->ReadFile(conf->MOTD, data.GetString());
+       return true;
+}
+
+bool ValidateNotEmpty(ServerConfig* conf, const char* tag, const char* value, ValueItem &data)
+{
+       if (!*data.GetString())
+               throw CoreException(std::string("The value for ")+tag+" cannot be empty!");
+       return true;
+}
+
+bool ValidateRules(ServerConfig* conf, const char* tag, const char* value, ValueItem &data)
+{
+       conf->ReadFile(conf->RULES, data.GetString());
+       return true;
+}
+
+bool ValidateModeLists(ServerConfig* conf, const char* tag, const char* value, ValueItem &data)
+{
+       memset(conf->HideModeLists, 0, 256);
+       for (const unsigned char* x = (const unsigned char*)data.GetString(); *x; ++x)
+               conf->HideModeLists[*x] = true;
+       return true;
+}
+
+bool ValidateExemptChanOps(ServerConfig* conf, const char* tag, const char* value, ValueItem &data)
+{
+       memset(conf->ExemptChanOps, 0, 256);
+       for (const unsigned char* x = (const unsigned char*)data.GetString(); *x; ++x)
+               conf->ExemptChanOps[*x] = true;
+       return true;
+}
+
+bool ValidateWhoWas(ServerConfig* conf, const char* tag, const char* value, ValueItem &data)
+{
+       conf->WhoWasMaxKeep = conf->GetInstance()->Duration(data.GetString());
+
+       if (conf->WhoWasGroupSize < 0)
+               conf->WhoWasGroupSize = 0;
+
+       if (conf->WhoWasMaxGroups < 0)
+               conf->WhoWasMaxGroups = 0;
+
+       if (conf->WhoWasMaxKeep < 3600)
+       {
+               conf->WhoWasMaxKeep = 3600;
+               conf->GetInstance()->Log(DEFAULT,"WARNING: <whowas:maxkeep> value less than 3600, setting to default 3600");
+       }
+
+       command_t* whowas_command = conf->GetInstance()->Parser->GetHandler("WHOWAS");
+       if (whowas_command)
+       {
+               std::deque<classbase*> params;
+               whowas_command->HandleInternal(WHOWAS_PRUNE, params);
+       }
+
+       return true;
+}
+
+/* Callback called before processing the first <connect> tag
+ */
+bool InitConnect(ServerConfig* conf, const char* tag)
+{
+       conf->GetInstance()->Log(DEFAULT,"Reading connect classes...");
+       conf->Classes.clear();
+       return true;
+}
+
+/* Callback called to process a single <connect> tag
+ */
+bool DoConnect(ServerConfig* conf, const char* tag, char** entries, ValueList &values, int* types)
+{
+       ConnectClass c;
+       const char* allow = values[0].GetString(); /* Yeah, there are a lot of values. Live with it. */
+       const char* deny = values[1].GetString();
+       const char* password = values[2].GetString();
+       int timeout = values[3].GetInteger();
+       int pingfreq = values[4].GetInteger();
+       int flood = values[5].GetInteger();
+       int threshold = values[6].GetInteger();
+       int sendq = values[7].GetInteger();
+       int recvq = values[8].GetInteger();
+       int localmax = values[9].GetInteger();
+       int globalmax = values[10].GetInteger();
+
+       if (*allow)
+       {
+               ConnectClass c(timeout, flood, allow, pingfreq, password, threshold, sendq, recvq, localmax, globalmax);
+               conf->Classes.push_back(c);
+       }
+       else
+       {
+               ConnectClass c(deny);
+               conf->Classes.push_back(c);
+       }
+
+       return true;
+}
+
+/* Callback called when there are no more <connect> tags
+ */
+bool DoneConnect(ServerConfig* conf, const char* tag)
+{
+       return true;
+}
+
+/* Callback called before processing the first <uline> tag
+ */
+bool InitULine(ServerConfig* conf, const char* tag)
+{
+       conf->ulines.clear();
+       return true;
+}
+
+/* Callback called to process a single <uline> tag
+ */
+bool DoULine(ServerConfig* conf, const char* tag, char** entries, ValueList &values, int* types)
+{
+       const char* server = values[0].GetString();
+       const bool silent = values[1].GetBool();
+       conf->ulines[server] = silent;
+       return true;
+}
+
+/* Callback called when there are no more <uline> tags
+ */
+bool DoneULine(ServerConfig* conf, const char* tag)
+{
+       return true;
+}
+
+/* Callback called before processing the first <module> tag
+ */
+bool InitModule(ServerConfig* conf, const char* tag)
+{
+       old_module_names.clear();
+       new_module_names.clear();
+       added_modules.clear();
+       removed_modules.clear();
+       for (std::vector<std::string>::iterator t = conf->module_names.begin(); t != conf->module_names.end(); t++)
+       {
+               old_module_names.push_back(*t);
+       }
+       return true;
+}
+
+/* Callback called to process a single <module> tag
+ */
+bool DoModule(ServerConfig* conf, const char* tag, char** entries, ValueList &values, int* types)
+{
+       const char* modname = values[0].GetString();
+       new_module_names.push_back(modname);
+       return true;
+}
+
+/* Callback called when there are no more <module> tags
+ */
+bool DoneModule(ServerConfig* conf, const char* tag)
+{
+       // now create a list of new modules that are due to be loaded
+       // and a seperate list of modules which are due to be unloaded
+       for (std::vector<std::string>::iterator _new = new_module_names.begin(); _new != new_module_names.end(); _new++)
+       {
+               bool added = true;
+
+               for (std::vector<std::string>::iterator old = old_module_names.begin(); old != old_module_names.end(); old++)
+               {
+                       if (*old == *_new)
+                               added = false;
+               }
+
+               if (added)
+                       added_modules.push_back(*_new);
+       }
+
+       for (std::vector<std::string>::iterator oldm = old_module_names.begin(); oldm != old_module_names.end(); oldm++)
+       {
+               bool removed = true;
+               for (std::vector<std::string>::iterator newm = new_module_names.begin(); newm != new_module_names.end(); newm++)
+               {
+                       if (*newm == *oldm)
+                               removed = false;
+               }
+
+               if (removed)
+                       removed_modules.push_back(*oldm);
+       }
+       return true;
+}
+
+/* Callback called before processing the first <banlist> tag
+ */
+bool InitMaxBans(ServerConfig* conf, const char* tag)
+{
+       conf->maxbans.clear();
+       return true;
+}
+
+/* Callback called to process a single <banlist> tag
+ */
+bool DoMaxBans(ServerConfig* conf, const char* tag, char** entries, ValueList &values, int* types)
+{
+       const char* channel = values[0].GetString();
+       int limit = values[1].GetInteger();
+       conf->maxbans[channel] = limit;
+       return true;
+}
+
+/* Callback called when there are no more <banlist> tags.
+ */
+bool DoneMaxBans(ServerConfig* conf, const char* tag)
+{
+       return true;
+}
+
+void ServerConfig::ReportConfigError(const std::string &errormessage, bool bail, userrec* user)
+{
+       ServerInstance->Log(DEFAULT, "There were errors in your configuration file: %s", errormessage.c_str());
+       if (bail)
+       {
+               /* Unneeded because of the ServerInstance->Log() aboive? */
+               printf("There were errors in your configuration:\n%s\n\n",errormessage.c_str());
+               InspIRCd::Exit(EXIT_STATUS_CONFIG);
+       }
+       else
+       {
+               std::string errors = errormessage;
+               std::string::size_type start;
+               unsigned int prefixlen;
+               start = 0;
+               /* ":ServerInstance->Config->ServerName NOTICE user->nick :" */
+               if (user)
+               {
+                       prefixlen = strlen(this->ServerName) + strlen(user->nick) + 11;
+                       user->WriteServ("NOTICE %s :There were errors in the configuration file:",user->nick);
+                       while (start < errors.length())
+                       {
+                               user->WriteServ("NOTICE %s :%s",user->nick, errors.substr(start, 510 - prefixlen).c_str());
+                               start += 510 - prefixlen;
+                       }
+               }
+               else
+               {
+                       ServerInstance->WriteOpers("There were errors in the configuration file:");
+                       while (start < errors.length())
+                       {
+                               ServerInstance->WriteOpers(errors.substr(start, 360).c_str());
+                               start += 360;
+                       }
+               }
+               return;
+       }
+}
+
+void ServerConfig::Read(bool bail, userrec* user)
+{
+       static char debug[MAXBUF];      /* Temporary buffer for debugging value */
+       static char maxkeep[MAXBUF];    /* Temporary buffer for WhoWasMaxKeep value */
+       static char hidemodes[MAXBUF];  /* Modes to not allow listing from users below halfop */
+       static char exemptchanops[MAXBUF];      /* Exempt channel ops from these modes */
+       int rem = 0, add = 0;           /* Number of modules added, number of modules removed */
+       std::ostringstream errstr;      /* String stream containing the error output */
+
+       /* These tags MUST occur and must ONLY occur once in the config file */
+       static char* Once[] = { "server", "admin", "files", "power", "options", NULL };
+
+       /* These tags can occur ONCE or not at all */
+       InitialConfig Values[] = {
+               {"options",     "softlimit",    MAXCLIENTS_S,           new ValueContainerUInt (&this->SoftLimit),              DT_INTEGER, ValidateSoftLimit},
+               {"options",     "somaxconn",    SOMAXCONN_S,            new ValueContainerInt  (&this->MaxConn),                DT_INTEGER, ValidateMaxConn},
+               {"options",     "moronbanner",  "Youre banned!",        new ValueContainerChar (this->MoronBanner),             DT_CHARPTR, NoValidation},
+               {"server",      "name",         "",                     new ValueContainerChar (this->ServerName),              DT_CHARPTR, ValidateServerName},
+               {"server",      "description",  "Configure Me",         new ValueContainerChar (this->ServerDesc),              DT_CHARPTR, NoValidation},
+               {"server",      "network",      "Network",              new ValueContainerChar (this->Network),                 DT_CHARPTR, NoValidation},
+               {"admin",       "name",         "",                     new ValueContainerChar (this->AdminName),               DT_CHARPTR, NoValidation},
+               {"admin",       "email",        "Mis@configu.red",      new ValueContainerChar (this->AdminEmail),              DT_CHARPTR, NoValidation},
+               {"admin",       "nick",         "Misconfigured",        new ValueContainerChar (this->AdminNick),               DT_CHARPTR, NoValidation},
+               {"files",       "motd",         "",                     new ValueContainerChar (this->motd),                    DT_CHARPTR, ValidateMotd},
+               {"files",       "rules",        "",                     new ValueContainerChar (this->rules),                   DT_CHARPTR, ValidateRules},
+               {"power",       "diepass",      "",                     new ValueContainerChar (this->diepass),                 DT_CHARPTR, ValidateNotEmpty},
+               {"power",       "pause",        "",                     new ValueContainerInt  (&this->DieDelay),               DT_INTEGER, NoValidation},
+               {"power",       "restartpass",  "",                     new ValueContainerChar (this->restartpass),             DT_CHARPTR, ValidateNotEmpty},
+               {"options",     "prefixquit",   "",                     new ValueContainerChar (this->PrefixQuit),              DT_CHARPTR, NoValidation},
+               {"options",     "suffixquit",   "",                     new ValueContainerChar (this->SuffixQuit),              DT_CHARPTR, NoValidation},
+               {"options",     "fixedquit",    "",                     new ValueContainerChar (this->FixedQuit),               DT_CHARPTR, NoValidation},
+               {"options",     "loglevel",     "default",              new ValueContainerChar (debug),                         DT_CHARPTR, ValidateLogLevel},
+               {"options",     "netbuffersize","10240",                new ValueContainerInt  (&this->NetBufferSize),          DT_INTEGER, ValidateNetBufferSize},
+               {"options",     "maxwho",       "128",                  new ValueContainerInt  (&this->MaxWhoResults),          DT_INTEGER, ValidateMaxWho},
+               {"options",     "allowhalfop",  "0",                    new ValueContainerBool (&this->AllowHalfop),            DT_BOOLEAN, NoValidation},
+               {"dns",         "server",       "",                     new ValueContainerChar (this->DNSServer),               DT_CHARPTR, ValidateDnsServer},
+               {"dns",         "timeout",      "5",                    new ValueContainerInt  (&this->dns_timeout),            DT_INTEGER, NoValidation},
+               {"options",     "moduledir",    MOD_PATH,               new ValueContainerChar (this->ModPath),                 DT_CHARPTR, NoValidation},
+               {"disabled",    "commands",     "",                     new ValueContainerChar (this->DisabledCommands),        DT_CHARPTR, NoValidation},
+               {"options",     "userstats",    "",                     new ValueContainerChar (this->UserStats),               DT_CHARPTR, NoValidation},
+               {"options",     "customversion","",                     new ValueContainerChar (this->CustomVersion),           DT_CHARPTR, NoValidation},
+               {"options",     "hidesplits",   "0",                    new ValueContainerBool (&this->HideSplits),             DT_BOOLEAN, NoValidation},
+               {"options",     "hidebans",     "0",                    new ValueContainerBool (&this->HideBans),               DT_BOOLEAN, NoValidation},
+               {"options",     "hidewhois",    "",                     new ValueContainerChar (this->HideWhoisServer),         DT_CHARPTR, NoValidation},
+               {"options",     "hidekills",    "",                     new ValueContainerChar (this->HideKillsServer),         DT_CHARPTR, NoValidation},
+               {"options",     "operspywhois", "0",                    new ValueContainerBool (&this->OperSpyWhois),           DT_BOOLEAN, NoValidation},
+               {"options",     "nouserdns",    "0",                    new ValueContainerBool (&this->NoUserDns),              DT_BOOLEAN, NoValidation},
+               {"options",     "syntaxhints",  "0",                    new ValueContainerBool (&this->SyntaxHints),            DT_BOOLEAN, NoValidation},
+               {"options",     "cyclehosts",   "0",                    new ValueContainerBool (&this->CycleHosts),             DT_BOOLEAN, NoValidation},
+               {"options",     "ircumsgprefix","0",                    new ValueContainerBool (&this->UndernetMsgPrefix),      DT_BOOLEAN, NoValidation},
+               {"options",     "announceinvites", "1",                 new ValueContainerBool (&this->AnnounceInvites),        DT_BOOLEAN, NoValidation},
+               {"options",     "hostintopic",  "1",                    new ValueContainerBool (&this->FullHostInTopic),        DT_BOOLEAN, NoValidation},
+               {"options",     "hidemodes",    "",                     new ValueContainerChar (hidemodes),                     DT_CHARPTR, ValidateModeLists},
+               {"options",     "exemptchanops","",                     new ValueContainerChar (exemptchanops),                 DT_CHARPTR, ValidateExemptChanOps},
+               {"options",     "defaultmodes", "nt",                   new ValueContainerChar (this->DefaultModes),            DT_CHARPTR, NoValidation},
+               {"pid",         "file",         "",                     new ValueContainerChar (this->PID),                     DT_CHARPTR, NoValidation},
+               {"whowas",      "groupsize",    "10",                   new ValueContainerInt  (&this->WhoWasGroupSize),        DT_INTEGER, NoValidation},
+               {"whowas",      "maxgroups",    "10240",                new ValueContainerInt  (&this->WhoWasMaxGroups),        DT_INTEGER, NoValidation},
+               {"whowas",      "maxkeep",      "3600",                 new ValueContainerChar (maxkeep),                       DT_CHARPTR, ValidateWhoWas},
+               {"die",         "value",        "",                     new ValueContainerChar (this->DieValue),                DT_CHARPTR, NoValidation},
+               {"channels",    "users",        "20",                   new ValueContainerUInt (&this->MaxChans),               DT_INTEGER, NoValidation},
+               {"channels",    "opers",        "60",                   new ValueContainerUInt (&this->OperMaxChans),           DT_INTEGER, NoValidation},
+               {NULL}
+       };
+
+       /* These tags can occur multiple times, and therefore they have special code to read them
+        * which is different to the code for reading the singular tags listed above.
+        */
+       MultiConfig MultiValues[] = {
+
+               {"connect",
+                               {"allow",       "deny",         "password",     "timeout",      "pingfreq",     "flood",
+                               "threshold",    "sendq",        "recvq",        "localmax",     "globalmax",    "port",
+                               NULL},
+                               {"",            "",             "",             "",             "120",          "",
+                                "",            "",             "",             "3",            "3",            "0",
+                                NULL},
+                               {DT_CHARPTR,    DT_CHARPTR,     DT_CHARPTR,     DT_INTEGER,     DT_INTEGER,     DT_INTEGER,
+                                DT_INTEGER,    DT_INTEGER,     DT_INTEGER,     DT_INTEGER,     DT_INTEGER,     DT_INTEGER},
+                               InitConnect, DoConnect, DoneConnect},
+
+               {"uline",
+                               {"server",      "silent",       NULL},
+                               {"",            "0",            NULL},
+                               {DT_CHARPTR,    DT_BOOLEAN},
+                               InitULine,DoULine,DoneULine},
+
+               {"banlist",
+                               {"chan",        "limit",        NULL},
+                               {"",            "",             NULL},
+                               {DT_CHARPTR,    DT_INTEGER},
+                               InitMaxBans, DoMaxBans, DoneMaxBans},
+
+               {"module",
+                               {"name",        NULL},
+                               {"",            NULL},
+                               {DT_CHARPTR},
+                               InitModule, DoModule, DoneModule},
+
+               {"badip",
+                               {"reason",      "ipmask",       NULL},
+                               {"No reason",   "",             NULL},
+                               {DT_CHARPTR,    DT_CHARPTR},
+                               InitXLine, DoZLine, DoneZLine},
+
+               {"badnick",
+                               {"reason",      "nick",         NULL},
+                               {"No reason",   "",             NULL},
+                               {DT_CHARPTR,    DT_CHARPTR},
+                               InitXLine, DoQLine, DoneQLine},
+
+               {"badhost",
+                               {"reason",      "host",         NULL},
+                               {"No reason",   "",             NULL},
+                               {DT_CHARPTR,    DT_CHARPTR},
+                               InitXLine, DoKLine, DoneKLine},
+
+               {"exception",
+                               {"reason",      "host",         NULL},
+                               {"No reason",   "",             NULL},
+                               {DT_CHARPTR,    DT_CHARPTR},
+                               InitXLine, DoELine, DoneELine},
+
+               {"type",
+                               {"name",        "classes",      NULL},
+                               {"",            "",             NULL},
+                               {DT_CHARPTR,    DT_CHARPTR},
+                               InitTypes, DoType, DoneClassesAndTypes},
+
+               {"class",
+                               {"name",        "commands",     NULL},
+                               {"",            "",             NULL},
+                               {DT_CHARPTR,    DT_CHARPTR},
+                               InitClasses, DoClass, DoneClassesAndTypes},
+
+               {NULL}
+       };
+
+       include_stack.clear();
+
+       /* Load and parse the config file, if there are any errors then explode */
+
+       /* Make a copy here so if it fails then we can carry on running with an unaffected config */
+       ConfigDataHash newconfig;
+
+       if (this->LoadConf(newconfig, ServerInstance->ConfigFileName, errstr))
+       {
+               /* If we succeeded, set the ircd config to the new one */
+               this->config_data = newconfig;
+       }
+       else
+       {
+               ReportConfigError(errstr.str(), bail, user);
+               return;
+       }
+
+       /* The stuff in here may throw CoreException, be sure we're in a position to catch it. */
+       try
+       {
+               /* Check we dont have more than one of singular tags, or any of them missing
+                */
+               for (int Index = 0; Once[Index]; Index++)
+                       if (!CheckOnce(Once[Index], bail, user))
+                               return;
+
+               /* Read the values of all the tags which occur once or not at all, and call their callbacks.
+                */
+               for (int Index = 0; Values[Index].tag; Index++)
+               {
+                       char item[MAXBUF];
+                       int dt = Values[Index].datatype;
+                       bool allow_newlines =  ((dt & DT_ALLOW_NEWLINE) > 0);
+                       dt &= ~DT_ALLOW_NEWLINE;
+
+                       ConfValue(this->config_data, Values[Index].tag, Values[Index].value, Values[Index].default_value, 0, item, MAXBUF, allow_newlines);
+                       ValueItem vi(item);
+
+                       if (!Values[Index].validation_function(this, Values[Index].tag, Values[Index].value, vi))
+                               throw CoreException("One or more values in your configuration file failed to validate. Please see your ircd.log for more information.");
+
+                       switch (Values[Index].datatype)
+                       {
+                               case DT_CHARPTR:
+                               {
+                                       ValueContainerChar* vcc = (ValueContainerChar*)Values[Index].val;
+                                       /* Make sure we also copy the null terminator */
+                                       vcc->Set(vi.GetString(), strlen(vi.GetString()) + 1);
+                               }
+                               break;
+                               case DT_INTEGER:
+                               {
+                                       int val = vi.GetInteger();
+                                       ValueContainerInt* vci = (ValueContainerInt*)Values[Index].val;
+                                       vci->Set(&val, sizeof(int));
+                               }
+                               break;
+                               case DT_BOOLEAN:
+                               {
+                                       bool val = vi.GetBool();
+                                       ValueContainerBool* vcb = (ValueContainerBool*)Values[Index].val;
+                                       vcb->Set(&val, sizeof(bool));
+                               }
+                               break;
+                               default:
+                                       /* You don't want to know what happens if someones bad code sends us here. */
+                               break;
+                       }
+
+                       /* We're done with this now */
+                       delete Values[Index].val;
+               }
+
+               /* Read the multiple-tag items (class tags, connect tags, etc)
+                * and call the callbacks associated with them. We have three
+                * callbacks for these, a 'start', 'item' and 'end' callback.
+                */
+               for (int Index = 0; MultiValues[Index].tag; Index++)
+               {
+                       MultiValues[Index].init_function(this, MultiValues[Index].tag);
+
+                       int number_of_tags = ConfValueEnum(this->config_data, MultiValues[Index].tag);
+
+                       for (int tagnum = 0; tagnum < number_of_tags; tagnum++)
+                       {
+                               ValueList vl;
+                               for (int valuenum = 0; MultiValues[Index].items[valuenum]; valuenum++)
+                               {
+                                       int dt = MultiValues[Index].datatype[valuenum];
+                                       bool allow_newlines =  ((dt & DT_ALLOW_NEWLINE) > 0);
+                                       dt &= ~DT_ALLOW_NEWLINE;
+
+                                       switch (dt)
+                                       {
+                                               case DT_CHARPTR:
+                                               {
+                                                       char item[MAXBUF];
+                                                       if (ConfValue(this->config_data, MultiValues[Index].tag, MultiValues[Index].items[valuenum], MultiValues[Index].items_default[valuenum], tagnum, item, MAXBUF, allow_newlines))
+                                                               vl.push_back(ValueItem(item));
+                                                       else
+                                                               vl.push_back(ValueItem(""));
+                                               }
+                                               break;
+                                               case DT_INTEGER:
+                                               {
+                                                       int item = 0;
+                                                       if (ConfValueInteger(this->config_data, MultiValues[Index].tag, MultiValues[Index].items[valuenum], MultiValues[Index].items_default[valuenum], tagnum, item))
+                                                               vl.push_back(ValueItem(item));
+                                                       else
+                                                               vl.push_back(ValueItem(0));
+                                               }
+                                               break;
+                                               case DT_BOOLEAN:
+                                               {
+                                                       bool item = ConfValueBool(this->config_data, MultiValues[Index].tag, MultiValues[Index].items[valuenum], MultiValues[Index].items_default[valuenum], tagnum);
+                                                       vl.push_back(ValueItem(item));
+                                               }
+                                               break;
+                                               default:
+                                                       /* Someone was smoking craq if we got here, and we're all gonna die. */
+                                               break;
+                                       }
+                               }
+
+                               MultiValues[Index].validation_function(this, MultiValues[Index].tag, (char**)MultiValues[Index].items, vl, MultiValues[Index].datatype);
+                       }
+
+                       MultiValues[Index].finish_function(this, MultiValues[Index].tag);
+               }
+
+       }
+
+       catch (CoreException &ce)
+       {
+               ReportConfigError(ce.GetReason(), bail, user);
+               return;
+       }
+
+       // write once here, to try it out and make sure its ok
+       ServerInstance->WritePID(this->PID);
+
+       ServerInstance->Log(DEFAULT,"Done reading configuration file.");
+
+       /* If we're rehashing, let's load any new modules, and unload old ones
+        */
+       if (!bail)
+       {
+               int found_ports = 0;
+               FailedPortList pl;
+               ServerInstance->BindPorts(false, found_ports, pl);
+
+               if (pl.size())
+               {
+                       user->WriteServ("NOTICE %s :*** Not all your client ports could be bound.", user->nick);
+                       user->WriteServ("NOTICE %s :*** The following port(s) failed to bind:", user->nick);
+                       int j = 1;
+                       for (FailedPortList::iterator i = pl.begin(); i != pl.end(); i++, j++)
+                       {
+                               user->WriteServ("NOTICE %s :*** %d.   IP: %s     Port: %lu", user->nick, j, i->first.empty() ? "<all>" : i->first.c_str(), (unsigned long)i->second);
+                       }
+               }
+
+               if (!removed_modules.empty())
+               {
+                       for (std::vector<std::string>::iterator removing = removed_modules.begin(); removing != removed_modules.end(); removing++)
+                       {
+                               if (ServerInstance->UnloadModule(removing->c_str()))
+                               {
+                                       ServerInstance->WriteOpers("*** REHASH UNLOADED MODULE: %s",removing->c_str());
+
+                                       if (user)
+                                               user->WriteServ("973 %s %s :Module %s successfully unloaded.",user->nick, removing->c_str(), removing->c_str());
+
+                                       rem++;
+                               }
+                               else
+                               {
+                                       if (user)
+                                               user->WriteServ("972 %s %s :Failed to unload module %s: %s",user->nick, removing->c_str(), removing->c_str(), ServerInstance->ModuleError());
+                               }
+                       }
+               }
+
+               if (!added_modules.empty())
+               {
+                       for (std::vector<std::string>::iterator adding = added_modules.begin(); adding != added_modules.end(); adding++)
+                       {
+                               if (ServerInstance->LoadModule(adding->c_str()))
+                               {
+                                       ServerInstance->WriteOpers("*** REHASH LOADED MODULE: %s",adding->c_str());
+
+                                       if (user)
+                                               user->WriteServ("975 %s %s :Module %s successfully loaded.",user->nick, adding->c_str(), adding->c_str());
+
+                                       add++;
+                               }
+                               else
+                               {
+                                       if (user)
+                                               user->WriteServ("974 %s %s :Failed to load module %s: %s",user->nick, adding->c_str(), adding->c_str(), ServerInstance->ModuleError());
+                               }
+                       }
+               }
+
+               ServerInstance->Log(DEFAULT,"Successfully unloaded %lu of %lu modules and loaded %lu of %lu modules.",(unsigned long)rem,(unsigned long)removed_modules.size(),(unsigned long)add,(unsigned long)added_modules.size());
+       }
+
+       if (user)
+               user->WriteServ("NOTICE %s :*** Successfully rehashed server.", user->nick);
+       else
+               ServerInstance->WriteOpers("*** Successfully rehashed server.");
+}
+
+bool ServerConfig::LoadConf(ConfigDataHash &target, const char* filename, std::ostringstream &errorstream)
+{
+       std::ifstream conf(filename);
+       std::string line;
+       char ch;
+       long linenumber;
+       bool in_tag;
+       bool in_quote;
+       bool in_comment;
+       int character_count = 0;
+
+       linenumber = 1;
+       in_tag = false;
+       in_quote = false;
+       in_comment = false;
+
+       /* Check if the file open failed first */
+       if (!conf)
+       {
+               errorstream << "LoadConf: Couldn't open config file: " << filename << std::endl;
+               return false;
+       }
+
+       /* Fix the chmod of the file to restrict it to the current user and group */
+       chmod(filename,0600);
+
+       for (unsigned int t = 0; t < include_stack.size(); t++)
+       {
+               if (std::string(filename) == include_stack[t])
+               {
+                       errorstream << "File " << filename << " is included recursively (looped inclusion)." << std::endl;
+                       return false;
+               }
+       }
+
+       /* It's not already included, add it to the list of files we've loaded */
+       include_stack.push_back(filename);
+
+       /* Start reading characters... */
+       while(conf.get(ch))
+       {
+
+               /*
+                * Fix for moronic windows issue spotted by Adremelech.
+                * Some windows editors save text files as utf-16, which is
+                * a total pain in the ass to parse. Users should save in the
+                * right config format! If we ever see a file where the first
+                * byte is 0xFF or 0xFE, or the second is 0xFF or 0xFE, then
+                * this is most likely a utf-16 file. Bail out and insult user.
+                */
+               if ((character_count++ < 2) && (ch == '\xFF' || ch == '\xFE'))
+               {
+                       errorstream << "File " << filename << " cannot be read, as it is encoded in braindead UTF-16. Save your file as plain ASCII!" << std::endl;
+                       return false;
+               }
+
+               /*
+                * Here we try and get individual tags on separate lines,
+                * this would be so easy if we just made people format
+                * their config files like that, but they don't so...
+                * We check for a '<' and then know the line is over when
+                * we get a '>' not inside quotes. If we find two '<' and
+                * no '>' then die with an error.
+                */
+
+               if((ch == '#') && !in_quote)
+                       in_comment = true;
+
+               switch(ch)
+               {
+                       case '\n':
+                               if (in_quote)
+                                       line += '\n';
+                               linenumber++;
+                       case '\r':
+                               if (!in_quote)
+                                       in_comment = false;
+                       case '\0':
+                               continue;
+                       case '\t':
+                               ch = ' ';
+               }
+
+               if(in_comment)
+                       continue;
+
+               /* XXX: Added by Brain, May 1st 2006 - Escaping of characters.
+                * Note that this WILL NOT usually allow insertion of newlines,
+                * because a newline is two characters long. Use it primarily to
+                * insert the " symbol.
+                *
+                * Note that this also involves a further check when parsing the line,
+                * which can be found below.
+                */
+               if ((ch == '\\') && (in_quote) && (in_tag))
+               {
+                       line += ch;
+                       char real_character;
+                       if (conf.get(real_character))
+                       {
+                               if (real_character == 'n')
+                                       real_character = '\n';
+                               line += real_character;
+                               continue;
+                       }
+                       else
+                       {
+                               errorstream << "End of file after a \\, what did you want to escape?: " << filename << ":" << linenumber << std::endl;
+                               return false;
+                       }
+               }
+
+               if (ch != '\r')
+                       line += ch;
+
+               if(ch == '<')
+               {
+                       if(in_tag)
+                       {
+                               if(!in_quote)
+                               {
+                                       errorstream << "Got another opening < when the first one wasn't closed: " << filename << ":" << linenumber << std::endl;
+                                       return false;
+                               }
+                       }
+                       else
+                       {
+                               if(in_quote)
+                               {
+                                       errorstream << "We're in a quote but outside a tag, interesting. " << filename << ":" << linenumber << std::endl;
+                                       return false;
+                               }
+                               else
+                               {
+                                       // errorstream << "Opening new config tag on line " << linenumber << std::endl;
+                                       in_tag = true;
+                               }
+                       }
+               }
+               else if(ch == '"')
+               {
+                       if(in_tag)
+                       {
+                               if(in_quote)
+                               {
+                                       // errorstream << "Closing quote in config tag on line " << linenumber << std::endl;
+                                       in_quote = false;
+                               }
+                               else
+                               {
+                                       // errorstream << "Opening quote in config tag on line " << linenumber << std::endl;
+                                       in_quote = true;
+                               }
+                       }
+                       else
+                       {
+                               if(in_quote)
+                               {
+                                       errorstream << "Found a (closing) \" outside a tag: " << filename << ":" << linenumber << std::endl;
+                               }
+                               else
+                               {
+                                       errorstream << "Found a (opening) \" outside a tag: " << filename << ":" << linenumber << std::endl;
+                               }
+                       }
+               }
+               else if(ch == '>')
+               {
+                       if(!in_quote)
+                       {
+                               if(in_tag)
+                               {
+                                       // errorstream << "Closing config tag on line " << linenumber << std::endl;
+                                       in_tag = false;
+
+                                       /*
+                                        * If this finds an <include> then ParseLine can simply call
+                                        * LoadConf() and load the included config into the same ConfigDataHash
+                                        */
+
+                                       if(!this->ParseLine(target, line, linenumber, errorstream))
+                                               return false;
+
+                                       line.clear();
+                               }
+                               else
+                               {
+                                       errorstream << "Got a closing > when we weren't inside a tag: " << filename << ":" << linenumber << std::endl;
+                                       return false;
+                               }
+                       }
+               }
+       }
+
+       return true;
+}
+
+bool ServerConfig::LoadConf(ConfigDataHash &target, const std::string &filename, std::ostringstream &errorstream)
+{
+       return this->LoadConf(target, filename.c_str(), errorstream);
+}
+
+bool ServerConfig::ParseLine(ConfigDataHash &target, std::string &line, long linenumber, std::ostringstream &errorstream)
+{
+       std::string tagname;
+       std::string current_key;
+       std::string current_value;
+       KeyValList results;
+       bool got_name;
+       bool got_key;
+       bool in_quote;
+
+       got_name = got_key = in_quote = false;
+
+       //std::cout << "ParseLine(data, '" << line << "', " << linenumber << ", stream)" << std::endl;
+
+       for(std::string::iterator c = line.begin(); c != line.end(); c++)
+       {
+               if(!got_name)
+               {
+                       /* We don't know the tag name yet. */
+
+                       if(*c != ' ')
+                       {
+                               if(*c != '<')
+                               {
+                                       tagname += *c;
+                               }
+                       }
+                       else
+                       {
+                               /* We got to a space, we should have the tagname now. */
+                               if(tagname.length())
+                               {
+                                       got_name = true;
+                               }
+                       }
+               }
+               else
+               {
+                       /* We have the tag name */
+                       if (!got_key)
+                       {
+                               /* We're still reading the key name */
+                               if (*c != '=')
+                               {
+                                       if (*c != ' ')
+                                       {
+                                               current_key += *c;
+                                       }
+                               }
+                               else
+                               {
+                                       /* We got an '=', end of the key name. */
+                                       got_key = true;
+                               }
+                       }
+                       else
+                       {
+                               /* We have the key name, now we're looking for quotes and the value */
+
+                               /* Correctly handle escaped characters here.
+                                * See the XXX'ed section above.
+                                */
+                               if ((*c == '\\') && (in_quote))
+                               {
+                                       c++;
+                                       if (*c == 'n')
+                                               current_value += '\n';
+                                       else
+                                               current_value += *c;
+                                       continue;
+                               }
+                               else if ((*c == '\n') && (in_quote))
+                               {
+                                       /* Got a 'real' \n, treat it as part of the value */
+                                       current_value += '\n';
+                                       continue;
+                               }
+                               else if ((*c == '\r') && (in_quote))
+                                       /* Got a \r, drop it */
+                                       continue;
+
+                               if (*c == '"')
+                               {
+                                       if (!in_quote)
+                                       {
+                                               /* We're not already in a quote. */
+                                               in_quote = true;
+                                       }
+                                       else
+                                       {
+                                               /* Leaving quotes, we have the value */
+                                               results.push_back(KeyVal(current_key, current_value));
+
+                                               // std::cout << "<" << tagname << ":" << current_key << "> " << current_value << std::endl;
+
+                                               in_quote = false;
+                                               got_key = false;
+
+                                               if((tagname == "include") && (current_key == "file"))
+                                               {
+                                                       if(!this->DoInclude(target, current_value, errorstream))
+                                                               return false;
+                                               }
+
+                                               current_key.clear();
+                                               current_value.clear();
+                                       }
+                               }
+                               else
+                               {
+                                       if(in_quote)
+                                       {
+                                               current_value += *c;
+                                       }
+                               }
+                       }
+               }
+       }
+
+       /* Finished parsing the tag, add it to the config hash */
+       target.insert(std::pair<std::string, KeyValList > (tagname, results));
+
+       return true;
+}
+
+bool ServerConfig::DoInclude(ConfigDataHash &target, const std::string &file, std::ostringstream &errorstream)
+{
+       std::string confpath;
+       std::string newfile;
+       std::string::size_type pos;
+
+       confpath = ServerInstance->ConfigFileName;
+       newfile = file;
+
+       for (std::string::iterator c = newfile.begin(); c != newfile.end(); c++)
+       {
+               if (*c == '\\')
+               {
+                       *c = '/';
+               }
+       }
+
+       if (file[0] != '/')
+       {
+               if((pos = confpath.rfind("/")) != std::string::npos)
+               {
+                       /* Leaves us with just the path */
+                       newfile = confpath.substr(0, pos) + std::string("/") + newfile;
+               }
+               else
+               {
+                       errorstream << "Couldn't get config path from: " << confpath << std::endl;
+                       return false;
+               }
+       }
+
+       return LoadConf(target, newfile, errorstream);
+}
+
+bool ServerConfig::ConfValue(ConfigDataHash &target, const char* tag, const char* var, int index, char* result, int length, bool allow_linefeeds)
+{
+       return ConfValue(target, tag, var, "", index, result, length, allow_linefeeds);
+}
+
+bool ServerConfig::ConfValue(ConfigDataHash &target, const char* tag, const char* var, const char* default_value, int index, char* result, int length, bool allow_linefeeds)
+{
+       std::string value;
+       bool r = ConfValue(target, std::string(tag), std::string(var), std::string(default_value), index, value, allow_linefeeds);
+       strlcpy(result, value.c_str(), length);
+       return r;
+}
+
+bool ServerConfig::ConfValue(ConfigDataHash &target, const std::string &tag, const std::string &var, int index, std::string &result, bool allow_linefeeds)
+{
+       return ConfValue(target, tag, var, "", index, result, allow_linefeeds);
+}
+
+bool ServerConfig::ConfValue(ConfigDataHash &target, const std::string &tag, const std::string &var, const std::string &default_value, int index, std::string &result, bool allow_linefeeds)
+{
+       ConfigDataHash::size_type pos = index;
+       if((pos >= 0) && (pos < target.count(tag)))
+       {
+               ConfigDataHash::iterator iter = target.find(tag);
+
+               for(int i = 0; i < index; i++)
+                       iter++;
+
+               for(KeyValList::iterator j = iter->second.begin(); j != iter->second.end(); j++)
+               {
+                       if(j->first == var)
+                       {
+                               if ((!allow_linefeeds) && (j->second.find('\n') != std::string::npos))
+                               {
+                                       ServerInstance->Log(DEFAULT, "Value of <" + tag + ":" + var+ "> contains a linefeed, and linefeeds in this value are not permitted -- stripped to spaces.");
+                                       for (std::string::iterator n = j->second.begin(); n != j->second.end(); n++)
+                                               if (*n == '\n')
+                                                       *n = ' ';
+                               }
+                               else
+                               {
+                                       result = j->second;
+                                       return true;
+                               }
+                       }
+               }
+               if (!default_value.empty())
+               {
+                       result = default_value;
+                       return true;
+               }
+       }
+       else if(pos == 0)
+       {
+               if (!default_value.empty())
+               {
+                       result = default_value;
+                       return true;
+               }
+       }
+       return false;
+}
+
+bool ServerConfig::ConfValueInteger(ConfigDataHash &target, const char* tag, const char* var, int index, int &result)
+{
+       return ConfValueInteger(target, std::string(tag), std::string(var), "", index, result);
+}
+
+bool ServerConfig::ConfValueInteger(ConfigDataHash &target, const char* tag, const char* var, const char* default_value, int index, int &result)
+{
+       return ConfValueInteger(target, std::string(tag), std::string(var), std::string(default_value), index, result);
+}
+
+bool ServerConfig::ConfValueInteger(ConfigDataHash &target, const std::string &tag, const std::string &var, int index, int &result)
+{
+       return ConfValueInteger(target, tag, var, "", index, result);
+}
+
+bool ServerConfig::ConfValueInteger(ConfigDataHash &target, const std::string &tag, const std::string &var, const std::string &default_value, int index, int &result)
+{
+       std::string value;
+       std::istringstream stream;
+       bool r = ConfValue(target, tag, var, default_value, index, value);
+       stream.str(value);
+       if(!(stream >> result))
+               return false;
+       else
+       {
+               if (!value.empty())
+               {
+                       if (value.substr(0,2) == "0x")
+                       {
+                               char* endptr;
+
+                               value.erase(0,2);
+                               result = strtol(value.c_str(), &endptr, 16);
+
+                               /* No digits found */
+                               if (endptr == value.c_str())
+                                       return false;
+                       }
+                       else
+                       {
+                               char denominator = *(value.end() - 1);
+                               switch (toupper(denominator))
+                               {
+                                       case 'K':
+                                               /* Kilobytes -> bytes */
+                                               result = result * 1024;
+                                       break;
+                                       case 'M':
+                                               /* Megabytes -> bytes */
+                                               result = result * 1024 * 1024;
+                                       break;
+                                       case 'G':
+                                               /* Gigabytes -> bytes */
+                                               result = result * 1024 * 1024 * 1024;
+                                       break;
+                               }
+                       }
+               }
+       }
+       return r;
+}
+
+
+bool ServerConfig::ConfValueBool(ConfigDataHash &target, const char* tag, const char* var, int index)
+{
+       return ConfValueBool(target, std::string(tag), std::string(var), "", index);
+}
+
+bool ServerConfig::ConfValueBool(ConfigDataHash &target, const char* tag, const char* var, const char* default_value, int index)
+{
+       return ConfValueBool(target, std::string(tag), std::string(var), std::string(default_value), index);
+}
+
+bool ServerConfig::ConfValueBool(ConfigDataHash &target, const std::string &tag, const std::string &var, int index)
+{
+       return ConfValueBool(target, tag, var, "", index);
+}
+
+bool ServerConfig::ConfValueBool(ConfigDataHash &target, const std::string &tag, const std::string &var, const std::string &default_value, int index)
+{
+       std::string result;
+       if(!ConfValue(target, tag, var, default_value, index, result))
+               return false;
+
+       return ((result == "yes") || (result == "true") || (result == "1"));
+}
+
+int ServerConfig::ConfValueEnum(ConfigDataHash &target, const char* tag)
+{
+       return target.count(tag);
+}
+
+int ServerConfig::ConfValueEnum(ConfigDataHash &target, const std::string &tag)
+{
+       return target.count(tag);
+}
+
+int ServerConfig::ConfVarEnum(ConfigDataHash &target, const char* tag, int index)
+{
+       return ConfVarEnum(target, std::string(tag), index);
+}
+
+int ServerConfig::ConfVarEnum(ConfigDataHash &target, const std::string &tag, int index)
+{
+       ConfigDataHash::size_type pos = index;
+
+       if((pos >= 0) && (pos < target.count(tag)))
+       {
+               ConfigDataHash::const_iterator iter = target.find(tag);
+
+               for(int i = 0; i < index; i++)
+                       iter++;
+
+               return iter->second.size();
+       }
+
+       return 0;
+}
+
+/** Read the contents of a file located by `fname' into a file_cache pointed at by `F'.
+ */
+bool ServerConfig::ReadFile(file_cache &F, const char* fname)
+{
+       if (!fname || !*fname)
+               return false;
+
+       FILE* file = NULL;
+       char linebuf[MAXBUF];
+
+       F.clear();
+
+       if ((*fname != '/') && (*fname != '\\'))
+       {
+               std::string::size_type pos;
+               std::string confpath = ServerInstance->ConfigFileName;
+               std::string newfile = fname;
+
+               if ((pos = confpath.rfind("/")) != std::string::npos)
+                       newfile = confpath.substr(0, pos) + std::string("/") + fname;
+               else if ((pos = confpath.rfind("\\")) != std::string::npos)
+                       newfile = confpath.substr(0, pos) + std::string("\\") + fname;
+
+               if (!FileExists(newfile.c_str()))
+                       return false;
+               file =  fopen(newfile.c_str(), "r");
+       }
+       else
+       {
+               if (!FileExists(fname))
+                       return false;
+               file =  fopen(fname, "r");
+       }
+
+       if (file)
+       {
+               while (!feof(file))
+               {
+                       if (fgets(linebuf, sizeof(linebuf), file))
+                               linebuf[strlen(linebuf)-1] = 0;
+                       else
+                               *linebuf = 0;
+
+                       if (!feof(file))
+                       {
+                               F.push_back(*linebuf ? linebuf : " ");
+                       }
+               }
+
+               fclose(file);
+       }
+       else
+               return false;
+
+       return true;
+}
+
+bool ServerConfig::FileExists(const char* file)
+{
+       struct stat sb;
+       if (stat(file, &sb) == -1)
+               return false;
+
+       if ((sb.st_mode & S_IFDIR) > 0)
+               return false;
+            
+       FILE *input;
+       if ((input = fopen (file, "r")) == NULL)
+               return false;
+       else
+       {
+               fclose(input);
+               return true;
+       }
+}
+
+char* ServerConfig::CleanFilename(char* name)
+{
+       char* p = name + strlen(name);
+       while ((p != name) && (*p != '/') && (*p != '\\')) p--;
+       return (p != name ? ++p : p);
+}
+
+
+bool ServerConfig::DirValid(const char* dirandfile)
+{
+#ifdef WINDOWS
+       return true;
+#endif
+
+       char work[1024];
+       char buffer[1024];
+       char otherdir[1024];
+       int p;
+
+       strlcpy(work, dirandfile, 1024);
+       p = strlen(work);
+
+       // we just want the dir
+       while (*work)
+       {
+               if (work[p] == '/')
+               {
+                       work[p] = '\0';
+                       break;
+               }
+
+               work[p--] = '\0';
+       }
+
+       // Get the current working directory
+       if (getcwd(buffer, 1024 ) == NULL )
+               return false;
+
+       if (chdir(work) == -1)
+               return false;
+
+       if (getcwd(otherdir, 1024 ) == NULL )
+               return false;
+
+       if (chdir(buffer) == -1)
+               return false;
+
+       size_t t = strlen(work);
+
+       if (strlen(otherdir) >= t)
+       {
+               otherdir[t] = '\0';
+               if (!strcmp(otherdir,work))
+               {
+                       return true;
+               }
+
+               return false;
+       }
+       else
+       {
+               return false;
+       }
+}
+
+std::string ServerConfig::GetFullProgDir()
+{
+       char buffer[PATH_MAX+1];
+#ifdef WINDOWS
+       /* Windows has specific api calls to get the exe path that never fail.
+        * For once, windows has something of use, compared to the POSIX code
+        * for this, this is positively neato.
+        */
+       if (GetModuleFileName(NULL, buffer, MAX_PATH))
+       {
+               std::string fullpath = buffer;
+               std::string::size_type n = fullpath.rfind("\\inspircd.exe");
+               return std::string(fullpath, 0, n);
+       }
+#else
+       // Get the current working directory
+       if (getcwd(buffer, PATH_MAX))
+       {
+               std::string remainder = this->argv[0];
+
+               /* Does argv[0] start with /? its a full path, use it */
+               if (remainder[0] == '/')
+               {
+                       std::string::size_type n = remainder.rfind("/inspircd");
+                       return std::string(remainder, 0, n);
+               }
+
+               std::string fullpath = std::string(buffer) + "/" + remainder;
+               std::string::size_type n = fullpath.rfind("/inspircd");
+               return std::string(fullpath, 0, n);
+       }
+#endif
+       return "/";
+}
+
+InspIRCd* ServerConfig::GetInstance()
+{
+       return ServerInstance;
+}
+
+
+ValueItem::ValueItem(int value)
+{
+       std::stringstream n;
+       n << value;
+       v = n.str();
+}
+
+ValueItem::ValueItem(bool value)
+{
+       std::stringstream n;
+       n << value;
+       v = n.str();
+}
+
+ValueItem::ValueItem(char* value)
+{
+       v = value;
+}
+
+void ValueItem::Set(char* value)
+{
+       v = value;
+}
+
+void ValueItem::Set(const char* value)
+{
+       v = value;
+}
+
+void ValueItem::Set(int value)
+{
+       std::stringstream n;
+       n << value;
+       v = n.str();
+}
+
+int ValueItem::GetInteger()
+{
+       if (v.empty())
+               return 0;
+       return atoi(v.c_str());
+}
+
+char* ValueItem::GetString()
+{
+       return (char*)v.c_str();
+}
+
+bool ValueItem::GetBool()
+{
+       return (GetInteger() || v == "yes" || v == "true");
+}
+
index 049d2e6baa12e0239a8b07335c7820d2951e9421..ee257350ed523bd3efbde751c25f0af35bebc887 100644 (file)
@@ -1 +1,202 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "cull_list.h"\r\rCullItem::CullItem(userrec* u, std::string &r, const char* o_reason)\r{\r   this->user = u;\r        this->reason = r;\r      this->silent = false;\r  /* Seperate oper reason not set, use the user reason */\r        if (*o_reason)\r         this->oper_reason = o_reason;\r  else\r           this->oper_reason = r;\r}\r\rCullItem::CullItem(userrec* u, const char* r, const char* o_reason)\r{\r        this->user = u;\r        this->reason = r;\r      this->silent = false;\r  /* Seperate oper reason not set, use the user reason */\r        if (*o_reason)\r         this->oper_reason = o_reason;\r  else\r           this->oper_reason = r;\r}\r\rvoid CullItem::MakeSilent()\r{\r        this->silent = true;\r}\r\rbool CullItem::IsSilent()\r{\r    return this->silent;\r}\r\rCullItem::~CullItem()\r{\r}\r\ruserrec* CullItem::GetUser()\r{\r      return this->user;\r}\r\rstd::string& CullItem::GetReason()\r{\r     return this->reason;\r}\r\rstd::string& CullItem::GetOperReason()\r{\r       return this->oper_reason;\r}\r\rCullList::CullList(InspIRCd* Instance) : ServerInstance(Instance)\r{\r       list.clear();\r  exempt.clear();\r}\r\rvoid CullList::AddItem(userrec* user, std::string &reason, const char* o_reason)\r{\r  AddItem(user, reason.c_str(), o_reason);\r}\r\r\rvoid CullList::AddItem(userrec* user, const char* reason, const char* o_reason)\r{\r if (exempt.find(user) == exempt.end())\r {\r              CullItem item(user, reason, o_reason);\r         list.push_back(item);\r          exempt[user] = user;\r   }\r}\r\rvoid CullList::MakeSilent(userrec* user)\r{\r        for (std::vector<CullItem>::iterator a = list.begin(); a != list.end(); ++a)\r   {\r              if (a->GetUser() == user)\r              {\r                      a->MakeSilent();\r                       break;\r         }\r      }\r      return;\r}\r\rint CullList::Apply()\r{\r     int n = list.size();\r   while (list.size())\r    {\r              std::vector<CullItem>::iterator a = list.begin();\r\r             user_hash::iterator iter = ServerInstance->clientlist->find(a->GetUser()->nick);\r               std::map<userrec*, userrec*>::iterator exemptiter = exempt.find(a->GetUser());\r         const char* preset_reason = a->GetUser()->GetOperQuit();\r               std::string reason = a->GetReason();\r           std::string oper_reason = *preset_reason ? preset_reason : a->GetOperReason();\r\r                if (reason.length() > MAXQUIT - 1)\r                     reason.resize(MAXQUIT - 1);\r            if (oper_reason.length() > MAXQUIT - 1)\r                        oper_reason.resize(MAXQUIT - 1);\r\r              if (a->GetUser()->registered != REG_ALL)\r                       if (ServerInstance->unregistered_count)\r                                ServerInstance->unregistered_count--;\r\r         if (IS_LOCAL(a->GetUser()))\r            {\r                      a->GetUser()->Write("ERROR :Closing link (%s@%s) [%s]", a->GetUser()->ident, a->GetUser()->host, oper_reason.c_str());\r                 if ((!a->GetUser()->sendq.empty()) && (!(*a->GetUser()->GetWriteError())))\r                             a->GetUser()->FlushWriteBuf();\r         }\r\r             if (a->GetUser()->registered == REG_ALL)\r               {\r                      FOREACH_MOD_I(ServerInstance,I_OnUserQuit,OnUserQuit(a->GetUser(), reason, oper_reason));\r                      a->GetUser()->PurgeEmptyChannels();\r                    a->GetUser()->WriteCommonQuit(reason, oper_reason);\r            }\r\r             FOREACH_MOD_I(ServerInstance,I_OnUserDisconnect,OnUserDisconnect(a->GetUser()));\r\r              if (IS_LOCAL(a->GetUser()))\r            {\r                      if (ServerInstance->Config->GetIOHook(a->GetUser()->GetPort()))\r                        {\r                              try\r                            {\r                                      ServerInstance->Config->GetIOHook(a->GetUser()->GetPort())->OnRawSocketClose(a->GetUser()->GetFd());\r                           }\r                              catch (CoreException& modexcept)\r                               {\r                                      ServerInstance->Log(DEBUG, "%s threw an exception: %s", modexcept.GetSource(), modexcept.GetReason());\r                         }\r                      }\r\r                     ServerInstance->SE->DelFd(a->GetUser());\r                       a->GetUser()->CloseSocket();\r           }\r\r             /*\r              * this must come before the ServerInstance->SNO->WriteToSnoMaskso that it doesnt try to fill their buffer with anything\r                * if they were an oper with +sn +qQ.\r           */\r            if (a->GetUser()->registered == REG_ALL)\r               {\r                      if (IS_LOCAL(a->GetUser()))\r                    {\r                              if (!a->IsSilent())\r                            {\r                                      ServerInstance->SNO->WriteToSnoMask('q',"Client exiting: %s!%s@%s [%s]",a->GetUser()->nick,a->GetUser()->ident,a->GetUser()->host,oper_reason.c_str());\r                                }\r                      }\r                      else\r                   {\r                              if ((!ServerInstance->SilentULine(a->GetUser()->server)) && (!a->IsSilent()))\r                          {\r                                      ServerInstance->SNO->WriteToSnoMask('Q',"Client exiting on server %s: %s!%s@%s [%s]",a->GetUser()->server,a->GetUser()->nick,a->GetUser()->ident,a->GetUser()->host,oper_reason.c_str());\r                              }\r                      }\r                      a->GetUser()->AddToWhoWas();\r           }\r\r             if (iter != ServerInstance->clientlist->end())\r         {\r                      if (IS_LOCAL(a->GetUser()))\r                    {\r                              std::vector<userrec*>::iterator x = find(ServerInstance->local_users.begin(),ServerInstance->local_users.end(),a->GetUser());\r                          if (x != ServerInstance->local_users.end())\r                                    ServerInstance->local_users.erase(x);\r                  }\r                      ServerInstance->clientlist->erase(iter);\r                       DELETE(a->GetUser());\r          }\r\r             list.erase(list.begin());\r              exempt.erase(exemptiter);\r      }\r      return n;\r}\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "cull_list.h"
+
+CullItem::CullItem(userrec* u, std::string &r, const char* o_reason)
+{
+       this->user = u;
+       this->reason = r;
+       this->silent = false;
+       /* Seperate oper reason not set, use the user reason */
+       if (*o_reason)
+               this->oper_reason = o_reason;
+       else
+               this->oper_reason = r;
+}
+
+CullItem::CullItem(userrec* u, const char* r, const char* o_reason)
+{
+       this->user = u;
+       this->reason = r;
+       this->silent = false;
+       /* Seperate oper reason not set, use the user reason */
+       if (*o_reason)
+               this->oper_reason = o_reason;
+       else
+               this->oper_reason = r;
+}
+
+void CullItem::MakeSilent()
+{
+       this->silent = true;
+}
+
+bool CullItem::IsSilent()
+{
+       return this->silent;
+}
+
+CullItem::~CullItem()
+{
+}
+
+userrec* CullItem::GetUser()
+{
+       return this->user;
+}
+
+std::string& CullItem::GetReason()
+{
+       return this->reason;
+}
+
+std::string& CullItem::GetOperReason()
+{
+       return this->oper_reason;
+}
+
+CullList::CullList(InspIRCd* Instance) : ServerInstance(Instance)
+{
+       list.clear();
+       exempt.clear();
+}
+
+void CullList::AddItem(userrec* user, std::string &reason, const char* o_reason)
+{
+       AddItem(user, reason.c_str(), o_reason);
+}
+
+
+void CullList::AddItem(userrec* user, const char* reason, const char* o_reason)
+{
+       if (exempt.find(user) == exempt.end())
+       {
+               CullItem item(user, reason, o_reason);
+               list.push_back(item);
+               exempt[user] = user;
+       }
+}
+
+void CullList::MakeSilent(userrec* user)
+{
+       for (std::vector<CullItem>::iterator a = list.begin(); a != list.end(); ++a)
+       {
+               if (a->GetUser() == user)
+               {
+                       a->MakeSilent();
+                       break;
+               }
+       }
+       return;
+}
+
+int CullList::Apply()
+{
+       int n = list.size();
+       while (list.size())
+       {
+               std::vector<CullItem>::iterator a = list.begin();
+
+               user_hash::iterator iter = ServerInstance->clientlist->find(a->GetUser()->nick);
+               std::map<userrec*, userrec*>::iterator exemptiter = exempt.find(a->GetUser());
+               const char* preset_reason = a->GetUser()->GetOperQuit();
+               std::string reason = a->GetReason();
+               std::string oper_reason = *preset_reason ? preset_reason : a->GetOperReason();
+
+               if (reason.length() > MAXQUIT - 1)
+                       reason.resize(MAXQUIT - 1);
+               if (oper_reason.length() > MAXQUIT - 1)
+                       oper_reason.resize(MAXQUIT - 1);
+
+               if (a->GetUser()->registered != REG_ALL)
+                       if (ServerInstance->unregistered_count)
+                               ServerInstance->unregistered_count--;
+
+               if (IS_LOCAL(a->GetUser()))
+               {
+                       a->GetUser()->Write("ERROR :Closing link (%s@%s) [%s]", a->GetUser()->ident, a->GetUser()->host, oper_reason.c_str());
+                       if ((!a->GetUser()->sendq.empty()) && (!(*a->GetUser()->GetWriteError())))
+                               a->GetUser()->FlushWriteBuf();
+               }
+
+               if (a->GetUser()->registered == REG_ALL)
+               {
+                       FOREACH_MOD_I(ServerInstance,I_OnUserQuit,OnUserQuit(a->GetUser(), reason, oper_reason));
+                       a->GetUser()->PurgeEmptyChannels();
+                       a->GetUser()->WriteCommonQuit(reason, oper_reason);
+               }
+
+               FOREACH_MOD_I(ServerInstance,I_OnUserDisconnect,OnUserDisconnect(a->GetUser()));
+
+               if (IS_LOCAL(a->GetUser()))
+               {
+                       if (ServerInstance->Config->GetIOHook(a->GetUser()->GetPort()))
+                       {
+                               try
+                               {
+                                       ServerInstance->Config->GetIOHook(a->GetUser()->GetPort())->OnRawSocketClose(a->GetUser()->GetFd());
+                               }
+                               catch (CoreException& modexcept)
+                               {
+                                       ServerInstance->Log(DEBUG, "%s threw an exception: %s", modexcept.GetSource(), modexcept.GetReason());
+                               }
+                       }
+
+                       ServerInstance->SE->DelFd(a->GetUser());
+                       a->GetUser()->CloseSocket();
+               }
+
+               /*
+                * this must come before the ServerInstance->SNO->WriteToSnoMaskso that it doesnt try to fill their buffer with anything
+                * if they were an oper with +sn +qQ.
+                */
+               if (a->GetUser()->registered == REG_ALL)
+               {
+                       if (IS_LOCAL(a->GetUser()))
+                       {
+                               if (!a->IsSilent())
+                               {
+                                       ServerInstance->SNO->WriteToSnoMask('q',"Client exiting: %s!%s@%s [%s]",a->GetUser()->nick,a->GetUser()->ident,a->GetUser()->host,oper_reason.c_str());
+                               }
+                       }
+                       else
+                       {
+                               if ((!ServerInstance->SilentULine(a->GetUser()->server)) && (!a->IsSilent()))
+                               {
+                                       ServerInstance->SNO->WriteToSnoMask('Q',"Client exiting on server %s: %s!%s@%s [%s]",a->GetUser()->server,a->GetUser()->nick,a->GetUser()->ident,a->GetUser()->host,oper_reason.c_str());
+                               }
+                       }
+                       a->GetUser()->AddToWhoWas();
+               }
+
+               if (iter != ServerInstance->clientlist->end())
+               {
+                       if (IS_LOCAL(a->GetUser()))
+                       {
+                               std::vector<userrec*>::iterator x = find(ServerInstance->local_users.begin(),ServerInstance->local_users.end(),a->GetUser());
+                               if (x != ServerInstance->local_users.end())
+                                       ServerInstance->local_users.erase(x);
+                       }
+                       ServerInstance->clientlist->erase(iter);
+                       DELETE(a->GetUser());
+               }
+
+               list.erase(list.begin());
+               exempt.erase(exemptiter);
+       }
+       return n;
+}
+
index 6e12662a786de9b55d824a53513ec1cd103e340a..fab9631b79baca213f072c1307730111b8397ea3 100644 (file)
@@ -1 +1,1169 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r/*\rdns.cpp - Nonblocking DNS functions.\rVery very loosely based on the firedns library,\rCopyright (C) 2002 Ian Gulliver. This file is no\rlonger anything like firedns, there are many major\rdifferences between this code and the original.\rPlease do not assume that firedns works like this,\rlooks like this, walks like this or tastes like this.\r*/\r\r#ifndef WIN32\r#include <sys/types.h>\r#include <sys/socket.h>\r#include <errno.h>\r#include <netinet/in.h>\r#include <arpa/inet.h>\r#else\r#include "inspircd_win32wrapper.h"\r#include "inspircd_se_config.h"\r#endif\r\r#include "dns.h"\r#include "inspircd.h"\r#include "socketengine.h"\r#include "configreader.h"\r#include "socket.h"\r\rusing irc::sockets::insp_inaddr;\rusing irc::sockets::insp_ntoa;\rusing irc::sockets::insp_aton;\rusing irc::sockets::OpenTCPSocket;\r\r/** Masks to mask off the responses we get from the DNSRequest methods\r */\renum QueryInfo\r{\r   ERROR_MASK      = 0x10000       /* Result is an error */\r};\r\r/** Flags which can be ORed into a request or reply for different meanings\r */\renum QueryFlags\r{\r  FLAGS_MASK_RD           = 0x01, /* Recursive */\r        FLAGS_MASK_TC           = 0x02,\r        FLAGS_MASK_AA           = 0x04, /* Authoritative */\r    FLAGS_MASK_OPCODE       = 0x78,\r        FLAGS_MASK_QR           = 0x80,\r        FLAGS_MASK_RCODE        = 0x0F, /* Request */\r  FLAGS_MASK_Z            = 0x70,\r        FLAGS_MASK_RA           = 0x80\r};\r\r\r/** Represents a dns resource record (rr)\r */\rstruct ResourceRecord\r{\r      QueryType       type;           /* Record type */\r      unsigned int    rr_class;       /* Record class */\r     unsigned long   ttl;            /* Time to live */\r     unsigned int    rdlength;       /* Record length */\r};\r\r/** Represents a dns request/reply header, and its payload as opaque data.\r */\rclass DNSHeader\r{\r public:\r      unsigned char   id[2];          /* Request id */\r       unsigned int    flags1;         /* Flags */\r    unsigned int    flags2;         /* Flags */\r    unsigned int    qdcount;\r       unsigned int    ancount;        /* Answer count */\r     unsigned int    nscount;        /* Nameserver count */\r unsigned int    arcount;\r       unsigned char   payload[512];   /* Packet payload */\r};\r\rclass DNSRequest\r{\r public:\r   unsigned char   id[2];          /* Request id */\r       unsigned char*  res;            /* Result processing buffer */\r unsigned int    rr_class;       /* Request class */\r    QueryType       type;           /* Request type */\r     DNS*            dnsobj;         /* DNS caller (where we get our FD from) */\r    unsigned long   ttl;            /* Time to live */\r     std::string     orig;           /* Original requested name/ip */\r\r      DNSRequest(InspIRCd* Instance, DNS* dns, int id, const std::string &original);\r ~DNSRequest();\r DNSInfo ResultIsReady(DNSHeader &h, int length);\r       int SendRequests(const DNSHeader *header, const int length, QueryType qt);\r};\r\rclass CacheTimer : public InspTimer\r{\r private:\r InspIRCd* ServerInstance;\r      DNS* dns;\r public:\r     CacheTimer(InspIRCd* Instance, DNS* thisdns)\r           : InspTimer(3600, Instance->Time(), true), ServerInstance(Instance), dns(thisdns) { }\r\r virtual void Tick(time_t TIME)\r {\r              dns->PruneCache();\r     }\r};\r\rclass RequestTimeout : public InspTimer\r{\r        InspIRCd* ServerInstance;\r      DNSRequest* watch;\r     int watchid;\r public:\r  RequestTimeout(unsigned long n, InspIRCd* SI, DNSRequest* watching, int id) : InspTimer(n, time(NULL)), ServerInstance(SI), watch(watching), watchid(id)\r       {\r      }\r\r     void Tick(time_t TIME)\r {\r              if (ServerInstance->Res->requests[watchid] == watch)\r           {\r                      /* Still exists, whack it */\r                   if (ServerInstance->Res->Classes[watchid])\r                     {\r                              ServerInstance->Res->Classes[watchid]->OnError(RESOLVER_TIMEOUT, "Request timed out");\r                         delete ServerInstance->Res->Classes[watchid];\r                          ServerInstance->Res->Classes[watchid] = NULL;\r                  }\r                      ServerInstance->Res->requests[watchid] = NULL;\r                 DELETE(watch);\r                 return;\r                }\r      }\r};\r\r/* Allocate the processing buffer */\rDNSRequest::DNSRequest(InspIRCd* Instance, DNS* dns, int id, const std::string &original) : dnsobj(dns)\r{\r   res = new unsigned char[512];\r  *res = 0;\r      orig = original;\r       RequestTimeout* RT = new RequestTimeout(Instance->Config->dns_timeout ? Instance->Config->dns_timeout : 5, Instance, this, id);\r        Instance->Timers->AddTimer(RT); /* The timer manager frees this */\r}\r\r/* Deallocate the processing buffer */\rDNSRequest::~DNSRequest()\r{\r       delete[] res;\r}\r\r/** Fill a ResourceRecord class based on raw data input */\rinline void DNS::FillResourceRecord(ResourceRecord* rr, const unsigned char *input)\r{\r      rr->type = (QueryType)((input[0] << 8) + input[1]);\r    rr->rr_class = (input[2] << 8) + input[3];\r     rr->ttl = (input[4] << 24) + (input[5] << 16) + (input[6] << 8) + input[7];\r    rr->rdlength = (input[8] << 8) + input[9];\r}\r\r/** Fill a DNSHeader class based on raw data input of a given length */\rinline void DNS::FillHeader(DNSHeader *header, const unsigned char *input, const int length)\r{\r   header->id[0] = input[0];\r      header->id[1] = input[1];\r      header->flags1 = input[2];\r     header->flags2 = input[3];\r     header->qdcount = (input[4] << 8) + input[5];\r  header->ancount = (input[6] << 8) + input[7];\r  header->nscount = (input[8] << 8) + input[9];\r  header->arcount = (input[10] << 8) + input[11];\r        memcpy(header->payload,&input[12],length);\r}\r\r/** Empty a DNSHeader class out into raw data, ready for transmission */\rinline void DNS::EmptyHeader(unsigned char *output, const DNSHeader *header, const int length)\r{\r        output[0] = header->id[0];\r     output[1] = header->id[1];\r     output[2] = header->flags1;\r    output[3] = header->flags2;\r    output[4] = header->qdcount >> 8;\r      output[5] = header->qdcount & 0xFF;\r    output[6] = header->ancount >> 8;\r      output[7] = header->ancount & 0xFF;\r    output[8] = header->nscount >> 8;\r      output[9] = header->nscount & 0xFF;\r    output[10] = header->arcount >> 8;\r     output[11] = header->arcount & 0xFF;\r   memcpy(&output[12],header->payload,length);\r}\r\r/** Send requests we have previously built down the UDP socket */\rint DNSRequest::SendRequests(const DNSHeader *header, const int length, QueryType qt)\r{\r       unsigned char payload[sizeof(DNSHeader)];\r\r     this->rr_class = 1;\r    this->type = qt;\r               \r       DNS::EmptyHeader(payload,header,length);\r\r#ifdef IPV6\r  if (this->dnsobj->socketfamily == AF_INET6)\r    {\r              sockaddr_in6 addr;\r             memset(&addr,0,sizeof(addr));\r          memcpy(&addr.sin6_addr,&dnsobj->myserver6,sizeof(addr.sin6_addr));\r             addr.sin6_family = AF_INET6;\r           addr.sin6_port = htons(DNS::QUERY_PORT);\r               if (sendto(dnsobj->GetFd(), payload, length + 12, 0, (sockaddr *) &addr, sizeof(addr)) != length+12)\r                   return -1;\r     }\r      else\r   {\r              sockaddr_in addr;\r              memset(&addr,0,sizeof(addr));\r          memcpy(&addr.sin_addr.s_addr,&dnsobj->myserver4,sizeof(addr.sin_addr));\r                addr.sin_family = AF_INET;\r             addr.sin_port = htons(DNS::QUERY_PORT);\r                if (sendto(dnsobj->GetFd(), payload, length + 12, 0, (sockaddr *) &addr, sizeof(addr)) != length+12)\r                   return -1;\r     }\r#else\r        sockaddr_in addr;\r      memset(&addr,0,sizeof(addr));\r  memcpy(&addr.sin_addr.s_addr, &dnsobj->myserver4, sizeof(addr.sin_addr));\r      addr.sin_family = AF_INET;\r     addr.sin_port = htons(DNS::QUERY_PORT);\r        if (sendto(dnsobj->GetFd(), (const char*)payload, length + 12, 0, (sockaddr *) &addr, sizeof(addr)) != length+12)\r              return -1;\r#endif\r\r     return 0;\r}\r\r/** Add a query with a predefined header, and allocate an ID for it. */\rDNSRequest* DNS::AddQuery(DNSHeader *header, int &id, const char* original)\r{\r     /* Is the DNS connection down? */\r      if (this->GetFd() == -1)\r               return NULL;\r   \r       /* Create an id */\r     id = this->PRNG() & DNS::MAX_REQUEST_ID;\r\r      /* If this id is already 'in flight', pick another. */\r while (requests[id])\r           id = this->PRNG() & DNS::MAX_REQUEST_ID;\r\r      DNSRequest* req = new DNSRequest(ServerInstance, this, id, original);\r\r header->id[0] = req->id[0] = id >> 8;\r  header->id[1] = req->id[1] = id & 0xFF;\r        header->flags1 = FLAGS_MASK_RD;\r        header->flags2 = 0;\r    header->qdcount = 1;\r   header->ancount = 0;\r   header->nscount = 0;\r   header->arcount = 0;\r\r  /* At this point we already know the id doesnt exist,\r   * so there needs to be no second check for the ::end()\r         */\r    requests[id] = req;\r\r   /* According to the C++ spec, new never returns NULL. */\r       return req;\r}\r\rint DNS::ClearCache()\r{\r /* This ensures the buckets are reset to sane levels */\r        int rv = this->cache->size();\r  delete this->cache;\r    this->cache = new dnscache();\r  return rv;\r}\r\rint DNS::PruneCache()\r{\r  int n = 0;\r     dnscache* newcache = new dnscache();\r   for (dnscache::iterator i = this->cache->begin(); i != this->cache->end(); i++)\r                /* Dont include expired items (theres no point) */\r             if (i->second.CalcTTLRemaining())\r                      newcache->insert(*i);\r          else\r                   n++;\r\r  delete this->cache;\r    this->cache = newcache;\r        return n;\r}\r\rvoid DNS::Rehash()\r{\r      ip6munge = false;\r      int portpass = 0;\r\r     if (this->GetFd() > -1)\r        {\r              if (ServerInstance && ServerInstance->SE)\r                      ServerInstance->SE->DelFd(this);\r               shutdown(this->GetFd(), 2);\r            close(this->GetFd());\r          this->SetFd(-1);\r\r              /* Rehash the cache */\r         this->PruneCache();\r    }\r      else\r   {\r              /* Create initial dns cache */\r         this->cache = new dnscache();\r  }\r\r     if ((strstr(ServerInstance->Config->DNSServer,"::ffff:") == (char*)&ServerInstance->Config->DNSServer) ||  (strstr(ServerInstance->Config->DNSServer,"::FFFF:") == (char*)&ServerInstance->Config->DNSServer))\r {\r              ServerInstance->Log(DEFAULT,"WARNING: Using IPv4 addresses over IPv6 forces some DNS checks to be disabled.");\r         ServerInstance->Log(DEFAULT,"         This should not cause a problem, however it is recommended you migrate");\r                ServerInstance->Log(DEFAULT,"         to a true IPv6 environment.");\r           this->ip6munge = true;\r }\r\r     this->socketfamily = AF_INET;\r#ifdef IPV6\r      if (strchr(ServerInstance->Config->DNSServer,':'))\r     {\r              this->socketfamily = AF_INET6;\r         inet_pton(AF_INET6, ServerInstance->Config->DNSServer, &this->myserver6);\r      }\r      else\r   {\r              inet_aton(ServerInstance->Config->DNSServer, &this->myserver4);\r                portpass = -1;\r }\r#else\r        inet_aton(ServerInstance->Config->DNSServer, &this->myserver4);\r#endif\r\r        /* Initialize mastersocket */\r  int s = OpenTCPSocket(ServerInstance->Config->DNSServer, SOCK_DGRAM);\r  this->SetFd(s);\r\r       /* Have we got a socket and is it nonblocking? */\r      if (this->GetFd() != -1)\r       {\r              /* Bind the port - port 0 INADDR_ANY */\r                if (!ServerInstance->BindSocket(this->GetFd(), portpass, "", false))\r           {\r                      /* Failed to bind */\r                   shutdown(this->GetFd(),2);\r                     close(this->GetFd());\r                  this->SetFd(-1);\r               }\r\r             if (this->GetFd() >= 0)\r                {\r                      /* Hook the descriptor into the socket engine */\r                       if (ServerInstance && ServerInstance->SE)\r                      {\r                              if (!ServerInstance->SE->AddFd(this))\r                          {\r                                      ServerInstance->Log(DEFAULT,"Internal error starting DNS - hostnames will NOT resolve.");\r                                      shutdown(this->GetFd(),2);\r                                     close(this->GetFd());\r                                  this->SetFd(-1);\r                               }\r                      }\r              }\r      }\r}\r\r/** Initialise the DNS UDP socket so that we can send requests */\rDNS::DNS(InspIRCd* Instance) : ServerInstance(Instance)\r{\r       /* Clear the Resolver class table */\r   memset(Classes,0,sizeof(Classes));\r\r    /* Clear the requests class table */\r   memset(requests,0,sizeof(requests));\r\r  /* Set the id of the next request to 0\r  */\r    currid = 0;\r\r   /* DNS::Rehash() sets this to a valid ptr\r       */\r    this->cache = NULL;\r    \r       /* Again, DNS::Rehash() sets this to a\r  * valid value\r  */\r    this->SetFd(-1);\r\r      /* Actually read the settings\r   */\r    this->Rehash();\r\r       this->PruneTimer = new CacheTimer(ServerInstance, this);\r\r      ServerInstance->Timers->AddTimer(this->PruneTimer);\r}\r\r/** Build a payload to be placed after the header, based upon input data, a resource type, a class and a pointer to a buffer */\rint DNS::MakePayload(const char * const name, const QueryType rr, const unsigned short rr_class, unsigned char * const payload)\r{\r       short payloadpos = 0;\r  const char* tempchr, *tempchr2 = name;\r unsigned short length;\r\r        /* split name up into labels, create query */\r  while ((tempchr = strchr(tempchr2,'.')) != NULL)\r       {\r              length = tempchr - tempchr2;\r           if (payloadpos + length + 1 > 507)\r                     return -1;\r             payload[payloadpos++] = length;\r                memcpy(&payload[payloadpos],tempchr2,length);\r          payloadpos += length;\r          tempchr2 = &tempchr[1];\r        }\r      length = strlen(tempchr2);\r     if (length)\r    {\r              if (payloadpos + length + 2 > 507)\r                     return -1;\r             payload[payloadpos++] = length;\r                memcpy(&payload[payloadpos],tempchr2,length);\r          payloadpos += length;\r          payload[payloadpos++] = 0;\r     }\r      if (payloadpos > 508)\r          return -1;\r     length = htons(rr);\r    memcpy(&payload[payloadpos],&length,2);\r        length = htons(rr_class);\r      memcpy(&payload[payloadpos + 2],&length,2);\r    return payloadpos + 4;\r}\r\r/** Start lookup of an hostname to an IP address */\rint DNS::GetIP(const char *name)\r{\r       DNSHeader h;\r   int id;\r        int length;\r    \r       if ((length = this->MakePayload(name, DNS_QUERY_A, 1, (unsigned char*)&h.payload)) == -1)\r              return -1;\r\r    DNSRequest* req = this->AddQuery(&h, id, name);\r\r       if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_A) == -1))\r              return -1;\r\r    return id;\r}\r\r/** Start lookup of an hostname to an IPv6 address */\rint DNS::GetIP6(const char *name)\r{\r        DNSHeader h;\r   int id;\r        int length;\r\r   if ((length = this->MakePayload(name, DNS_QUERY_AAAA, 1, (unsigned char*)&h.payload)) == -1)\r           return -1;\r\r    DNSRequest* req = this->AddQuery(&h, id, name);\r\r       if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_AAAA) == -1))\r           return -1;\r\r    return id;\r}\r\r/** Start lookup of a cname to another name */\rint DNS::GetCName(const char *alias)\r{\r    DNSHeader h;\r   int id;\r        int length;\r\r   if ((length = this->MakePayload(alias, DNS_QUERY_CNAME, 1, (unsigned char*)&h.payload)) == -1)\r         return -1;\r\r    DNSRequest* req = this->AddQuery(&h, id, alias);\r\r      if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_CNAME) == -1))\r          return -1;\r\r    return id;\r}\r\r/** Start lookup of an IP address to a hostname */\rint DNS::GetName(const insp_inaddr *ip)\r{\r     char query[128];\r       DNSHeader h;\r   int id;\r        int length;\r\r#ifdef IPV6\r       unsigned char* c = (unsigned char*)&ip->s6_addr;\r       if (c[0] == 0 && c[1] == 0 && c[2] == 0 && c[3] == 0 &&\r            c[4] == 0 && c[5] == 0 && c[6] == 0 && c[7] == 0 &&\r            c[8] == 0 && c[9] == 0 && c[10] == 0xFF && c[11] == 0xFF)\r          sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[15],c[14],c[13],c[12]);\r     else\r           DNS::MakeIP6Int(query, (in6_addr*)ip);\r#else\r   unsigned char* c = (unsigned char*)&ip->s_addr;\r        sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[3],c[2],c[1],c[0]);\r#endif\r\r if ((length = this->MakePayload(query, DNS_QUERY_PTR, 1, (unsigned char*)&h.payload)) == -1)\r           return -1;\r\r    DNSRequest* req = this->AddQuery(&h, id, insp_ntoa(*ip));\r\r     if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_PTR) == -1))\r            return -1;\r\r    return id;\r}\r\r/** Start lookup of an IP address to a hostname */\rint DNS::GetNameForce(const char *ip, ForceProtocol fp)\r{\r     char query[128];\r       DNSHeader h;\r   int id;\r        int length;\r#ifdef SUPPORT_IP6LINKS\r    if (fp == PROTOCOL_IPV6)\r       {\r              in6_addr i;\r            if (inet_pton(AF_INET6, ip, &i) > 0)\r           {\r                      DNS::MakeIP6Int(query, &i);\r            }\r              else\r                   /* Invalid IP address */\r                       return -1;\r     }\r      else\r#endif\r    {\r              in_addr i;\r             if (inet_aton(ip, &i))\r         {\r                      unsigned char* c = (unsigned char*)&i.s_addr;\r                  sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[3],c[2],c[1],c[0]);\r         }\r              else\r                   /* Invalid IP address */\r                       return -1;\r     }\r\r     if ((length = this->MakePayload(query, DNS_QUERY_PTR, 1, (unsigned char*)&h.payload)) == -1)\r           return -1;\r\r    DNSRequest* req = this->AddQuery(&h, id, ip);\r\r if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_PTR) == -1))\r            return -1;\r\r    return id;\r}\r\r/** Build an ipv6 reverse domain from an in6_addr\r */\rvoid DNS::MakeIP6Int(char* query, const in6_addr *ip)\r{\r#ifdef SUPPORT_IP6LINKS\r    const char* hex = "0123456789abcdef";\r  for (int index = 31; index >= 0; index--) /* for() loop steps twice per byte */\r        {\r              if (index % 2)\r                 /* low nibble */\r                       *query++ = hex[ip->s6_addr[index / 2] & 0x0F];\r         else\r                   /* high nibble */\r                      *query++ = hex[(ip->s6_addr[index / 2] & 0xF0) >> 4];\r          *query++ = '.'; /* Seperator */\r        }\r      strcpy(query,"ip6.arpa"); /* Suffix the string */\r#else\r        *query = 0;\r#endif\r}\r\r/** Return the next id which is ready, and the result attached to it */\rDNSResult DNS::GetResult()\r{\r     /* Fetch dns query response and decide where it belongs */\r     DNSHeader header;\r      DNSRequest *req;\r       unsigned char buffer[sizeof(DNSHeader)];\r       sockaddr* from = new sockaddr[2];\r#ifdef IPV6\r  socklen_t x = this->socketfamily == AF_INET ? sizeof(sockaddr_in) : sizeof(sockaddr_in6);\r#else\r        socklen_t x = sizeof(sockaddr_in);\r#endif\r      const char* ipaddr_from;\r       unsigned short int port_from = 0;\r      int length = _recvfrom(this->GetFd(),(char*)buffer,sizeof(DNSHeader),0,from,&x);\r\r      /* Did we get the whole header? */\r     if (length < 12)\r       {\r              /* Nope - something screwed up. */\r             delete[] from;\r         return DNSResult(-1,"",0,"");\r  }\r\r     /* Check wether the reply came from a different DNS\r     * server to the one we sent it to, or the source-port\r  * is not 53.\r   * A user could in theory still spoof dns packets anyway\r        * but this is less trivial than just sending garbage\r   * to the client, which is possible without this check.\r         *\r      * -- Thanks jilles for pointing this one out.\r  */\r#ifdef IPV6\r        char nbuf[MAXBUF];\r     if (this->socketfamily == AF_INET6)\r    {\r              ipaddr_from = inet_ntop(AF_INET6, &((sockaddr_in6*)from)->sin6_addr, nbuf, sizeof(nbuf));\r              port_from = ntohs(((sockaddr_in6*)from)->sin6_port);\r   }\r      else\r#endif\r    {\r              ipaddr_from = inet_ntoa(((sockaddr_in*)from)->sin_addr);\r               port_from = ntohs(((sockaddr_in*)from)->sin_port);\r     }\r\r     delete[] from;\r\r        /* We cant perform this security check if you're using 4in6.\r    * Tough luck to you, choose one or't other!\r    */\r    if (!ip6munge)\r {\r              if ((port_from != DNS::QUERY_PORT) || (strcasecmp(ipaddr_from, ServerInstance->Config->DNSServer)))\r            {\r                      return DNSResult(-1,"",0,"");\r          }\r      }\r\r     /* Put the read header info into a header class */\r     DNS::FillHeader(&header,buffer,length - 12);\r\r  /* Get the id of this request.\r  * Its a 16 bit value stored in two char's,\r     * so we use logic shifts to create the value.\r  */\r    unsigned long this_id = header.id[1] + (header.id[0] << 8);\r\r   /* Do we have a pending request matching this id? */\r   if (!requests[this_id])\r        {\r              /* Somehow we got a DNS response for a request we never made... */\r             return DNSResult(-1,"",0,"");\r  }\r      else\r   {\r              /* Remove the query from the list of pending queries */\r                req = requests[this_id];\r               requests[this_id] = NULL;\r      }\r\r     /* Inform the DNSRequest class that it has a result to be read.\r         * When its finished it will return a DNSInfo which is a pair of\r        * unsigned char* resource record data, and an error message.\r   */\r    DNSInfo data = req->ResultIsReady(header, length);\r     std::string resultstr;\r\r        /* Check if we got a result, if we didnt, its an error */\r      if (data.first == NULL)\r        {\r              /* An error.\r            * Mask the ID with the value of ERROR_MASK, so that\r            * the dns_deal_with_classes() function knows that its\r          * an error response and needs to be treated uniquely.\r          * Put the error message in the second field.\r           */\r            std::string ro = req->orig;\r            delete req;\r            return DNSResult(this_id | ERROR_MASK, data.second, 0, ro);\r    }\r      else\r   {\r              unsigned long ttl = req->ttl;\r          char formatted[128];\r\r          /* Forward lookups come back as binary data. We must format them into ascii */\r         switch (req->type)\r             {\r                      case DNS_QUERY_A:\r                              snprintf(formatted,16,"%u.%u.%u.%u",data.first[0],data.first[1],data.first[2],data.first[3]);\r                          resultstr = formatted;\r                 break;\r\r                        case DNS_QUERY_AAAA:\r                   {\r                              snprintf(formatted,40,"%x:%x:%x:%x:%x:%x:%x:%x",\r                                               (ntohs(data.first[0]) + ntohs(data.first[1] << 8)),\r                                            (ntohs(data.first[2]) + ntohs(data.first[3] << 8)),\r                                            (ntohs(data.first[4]) + ntohs(data.first[5] << 8)),\r                                            (ntohs(data.first[6]) + ntohs(data.first[7] << 8)),\r                                            (ntohs(data.first[8]) + ntohs(data.first[9] << 8)),\r                                            (ntohs(data.first[10]) + ntohs(data.first[11] << 8)),\r                                          (ntohs(data.first[12]) + ntohs(data.first[13] << 8)),\r                                          (ntohs(data.first[14]) + ntohs(data.first[15] << 8)));\r                         char* c = strstr(formatted,":0:");\r                             if (c != NULL)\r                         {\r                                      memmove(c+1,c+2,strlen(c+2) + 1);\r                                      c += 2;\r                                        while (memcmp(c,"0:",2) == 0)\r                                          memmove(c,c+2,strlen(c+2) + 1);\r                                        if (memcmp(c,"0",2) == 0)\r                                              *c = 0;\r                                        if (memcmp(formatted,"0::",3) == 0)\r                                            memmove(formatted,formatted + 1, strlen(formatted + 1) + 1);\r                           }\r                              resultstr = formatted;\r\r                                /* Special case. Sending ::1 around between servers\r                             * and to clients is dangerous, because the : on the\r                            * start makes the client or server interpret the IP\r                            * as the last parameter on the line with a value ":1".\r                                 */\r                            if (*formatted == ':')\r                                 resultstr.insert(0, "0");\r                      }\r                      break;\r\r                        case DNS_QUERY_CNAME:\r                          /* Identical handling to PTR */\r\r                       case DNS_QUERY_PTR:\r                            /* Reverse lookups just come back as char* */\r                          resultstr = std::string((const char*)data.first);\r                      break;\r\r                        default:\r                       break;\r                 \r               }\r\r             /* Build the reply with the id and hostname/ip in it */\r                std::string ro = req->orig;\r            delete req;\r            return DNSResult(this_id,resultstr,ttl,ro);\r    }\r}\r\r/** A result is ready, process it */\rDNSInfo DNSRequest::ResultIsReady(DNSHeader &header, int length)\r{\r   int i = 0;\r     int q = 0;\r     int curanswer, o;\r      ResourceRecord rr;\r     unsigned short ptr;\r\r   /* This is just to keep _FORTIFY_SOURCE happy */\r       rr.type = DNS_QUERY_NONE;\r      rr.rdlength = 0;\r       rr.ttl = 1;     /* GCC is a whiney bastard -- see the XXX below. */\r\r   if (!(header.flags1 & FLAGS_MASK_QR))\r          return std::make_pair((unsigned char*)NULL,"Not a query result");\r\r     if (header.flags1 & FLAGS_MASK_OPCODE)\r         return std::make_pair((unsigned char*)NULL,"Unexpected value in DNS reply packet");\r\r   if (header.flags2 & FLAGS_MASK_RCODE)\r          return std::make_pair((unsigned char*)NULL,"Domain name not found");\r\r  if (header.ancount < 1)\r                return std::make_pair((unsigned char*)NULL,"No resource records returned");\r\r   /* Subtract the length of the header from the length of the packet */\r  length -= 12;\r\r while ((unsigned int)q < header.qdcount && i < length)\r {\r              if (header.payload[i] > 63)\r            {\r                      i += 6;\r                        q++;\r           }\r              else\r           {\r                      if (header.payload[i] == 0)\r                    {\r                              q++;\r                           i += 5;\r                        }\r                      else i += header.payload[i] + 1;\r               }\r      }\r      curanswer = 0;\r while ((unsigned)curanswer < header.ancount)\r   {\r              q = 0;\r         while (q == 0 && i < length)\r           {\r                      if (header.payload[i] > 63)\r                    {\r                              i += 2;\r                                q = 1;\r                 }\r                      else\r                   {\r                              if (header.payload[i] == 0)\r                            {\r                                      i++;\r                                   q = 1;\r                         }\r                              else i += header.payload[i] + 1; /* skip length and label */\r                   }\r              }\r              if (length - i < 10)\r                   return std::make_pair((unsigned char*)NULL,"Incorrectly sized DNS reply");\r\r            /* XXX: We actually initialise 'rr' here including its ttl field */\r            DNS::FillResourceRecord(&rr,&header.payload[i]);\r               i += 10;\r               if (rr.type != this->type)\r             {\r                      curanswer++;\r                   i += rr.rdlength;\r                      continue;\r              }\r              if (rr.rr_class != this->rr_class)\r             {\r                      curanswer++;\r                   i += rr.rdlength;\r                      continue;\r              }\r              break;\r }\r      if ((unsigned int)curanswer == header.ancount)\r         return std::make_pair((unsigned char*)NULL,"No valid answers");\r\r       if (i + rr.rdlength > (unsigned int)length)\r            return std::make_pair((unsigned char*)NULL,"Resource record larger than stated");\r\r     if (rr.rdlength > 1023)\r                return std::make_pair((unsigned char*)NULL,"Resource record too large");\r\r      this->ttl = rr.ttl;\r\r   switch (rr.type)\r       {\r              case DNS_QUERY_CNAME:\r                  /* CNAME and PTR have the same processing code */\r              case DNS_QUERY_PTR:\r                    o = 0;\r                 q = 0;\r                 while (q == 0 && i < length && o + 256 < 1023)\r                 {\r                              if (header.payload[i] > 63)\r                            {\r                                      memcpy(&ptr,&header.payload[i],2);\r                                     i = ntohs(ptr) - 0xC000 - 12;\r                          }\r                              else\r                           {\r                                      if (header.payload[i] == 0)\r                                    {\r                                              q = 1;\r                                 }\r                                      else\r                                   {\r                                              res[o] = 0;\r                                            if (o != 0)\r                                                    res[o++] = '.';\r                                                memcpy(&res[o],&header.payload[i + 1],header.payload[i]);\r                                              o += header.payload[i];\r                                                i += header.payload[i] + 1;\r                                    }\r                              }\r                      }\r                      res[o] = 0;\r            break;\r         case DNS_QUERY_AAAA:\r                   memcpy(res,&header.payload[i],rr.rdlength);\r                    res[rr.rdlength] = 0;\r          break;\r         case DNS_QUERY_A:\r                      memcpy(res,&header.payload[i],rr.rdlength);\r                    res[rr.rdlength] = 0;\r          break;\r         default:\r                       memcpy(res,&header.payload[i],rr.rdlength);\r                    res[rr.rdlength] = 0;\r          break;\r }\r      return std::make_pair(res,"No error");;\r}\r\r/** Close the master socket */\rDNS::~DNS()\r{\r        shutdown(this->GetFd(), 2);\r    close(this->GetFd());\r  ServerInstance->Timers->DelTimer(this->PruneTimer);\r    delete this->PruneTimer;\r}\r\rCachedQuery* DNS::GetCache(const std::string &source)\r{\r    dnscache::iterator x = cache->find(source.c_str());\r    if (x != cache->end())\r         return &(x->second);\r   else\r           return NULL;\r}\r         \rvoid DNS::DelCache(const std::string &source)\r{\r       cache->erase(source.c_str());\r}\r\rvoid Resolver::TriggerCachedResult()\r{\r        if (CQ)\r                OnLookupComplete(CQ->data, time_left, true);\r}\r\r/** High level abstraction of dns used by application at large */\rResolver::Resolver(InspIRCd* Instance, const std::string &source, QueryType qt, bool &cached, Module* creator) : ServerInstance(Instance), Creator(creator), input(source), querytype(qt)\r{\r  cached = false;\r\r       CQ = ServerInstance->Res->GetCache(source);\r    if (CQ)\r        {\r              time_left = CQ->CalcTTLRemaining();\r            if (!time_left)\r                {\r                      ServerInstance->Res->DelCache(source);\r         }\r              else\r           {\r                      cached = true;\r                 return;\r                }\r      }\r\r     insp_inaddr binip;\r\r    switch (querytype)\r     {\r              case DNS_QUERY_A:\r                      this->myid = ServerInstance->Res->GetIP(source.c_str());\r               break;\r\r                case DNS_QUERY_PTR:\r                    if (insp_aton(source.c_str(), &binip) > 0)\r                     {\r                              /* Valid ip address */\r                         this->myid = ServerInstance->Res->GetName(&binip);\r                     }\r                      else\r                   {\r                              this->OnError(RESOLVER_BADIP, "Bad IP address for reverse lookup");\r                            throw ModuleException("Resolver: Bad IP address");\r                             return;\r                        }\r              break;\r\r                case DNS_QUERY_PTR4:\r                   querytype = DNS_QUERY_PTR;\r                     this->myid = ServerInstance->Res->GetNameForce(source.c_str(), PROTOCOL_IPV4);\r         break;\r\r                case DNS_QUERY_PTR6:\r                   querytype = DNS_QUERY_PTR;\r                     this->myid = ServerInstance->Res->GetNameForce(source.c_str(), PROTOCOL_IPV6);\r         break;\r\r                case DNS_QUERY_AAAA:\r                   this->myid = ServerInstance->Res->GetIP6(source.c_str());\r              break;\r\r                case DNS_QUERY_CNAME:\r                  this->myid = ServerInstance->Res->GetCName(source.c_str());\r            break;\r\r                default:\r                       this->myid = -1;\r               break;\r }\r      if (this->myid == -1)\r  {\r              this->OnError(RESOLVER_NSDOWN, "Nameserver is down");\r          throw ModuleException("Resolver: Couldnt get an id to make a request");\r                /* We shouldnt get here really */\r              return;\r        }\r}\r\r/** Called when an error occurs */\rvoid Resolver::OnError(ResolverError e, const std::string &errormessage)\r{\r     /* Nothing in here */\r}\r\r/** Destroy a resolver */\rResolver::~Resolver()\r{\r     /* Nothing here (yet) either */\r}\r\r/** Get the request id associated with this class */\rint Resolver::GetId()\r{\r        return this->myid;\r}\r\rModule* Resolver::GetCreator()\r{\r return this->Creator;\r}\r\r/** Process a socket read event */\rvoid DNS::HandleEvent(EventType et, int errornum)\r{\r        /* Fetch the id and result of the next available packet */\r     DNSResult res = this->GetResult();\r     /* Is there a usable request id? */\r    if (res.id != -1)\r      {\r              /* Its an error reply */\r               if (res.id & ERROR_MASK)\r               {\r                      /* Mask off the error bit */\r                   res.id -= ERROR_MASK;\r                  /* Marshall the error to the correct class */\r                  if (Classes[res.id])\r                   {\r                              if (ServerInstance && ServerInstance->stats)\r                                   ServerInstance->stats->statsDnsBad++;\r                          Classes[res.id]->OnError(RESOLVER_NXDOMAIN, res.result);\r                               delete Classes[res.id];\r                                Classes[res.id] = NULL;\r                        }\r              }\r              else\r           {\r                      /* It is a non-error result, marshall the result to the correct class */\r                       if (Classes[res.id])\r                   {\r                              if (ServerInstance && ServerInstance->stats)\r                                   ServerInstance->stats->statsDnsGood++;\r\r                                if (!this->GetCache(res.original.c_str()))\r                                     this->cache->insert(std::make_pair(res.original.c_str(), CachedQuery(res.result, res.ttl)));\r\r                          Classes[res.id]->OnLookupComplete(res.result, res.ttl, false);\r                         delete Classes[res.id];\r                                Classes[res.id] = NULL;\r                        }\r              }\r\r             if (ServerInstance && ServerInstance->stats)\r                   ServerInstance->stats->statsDns++;\r     }\r}\r\r/** Add a derived Resolver to the working set */\rbool DNS::AddResolverClass(Resolver* r)\r{\r        /* Check the pointers validity and the id's validity */\r        if ((r) && (r->GetId() > -1))\r  {\r              /* Check the slot isnt already occupied -\r               * This should NEVER happen unless we have\r              * a severely broken DNS server somewhere\r               */\r            if (!Classes[r->GetId()])\r              {\r                      /* Set up the pointer to the class */\r                  Classes[r->GetId()] = r;\r                       return true;\r           }\r              else\r                   /* Duplicate id */\r                     return false;\r  }\r      else\r   {\r              /* Pointer or id not valid.\r             * Free the item and return\r             */\r            if (r)\r                 delete r;\r\r             return false;\r  }\r}\r\rvoid DNS::CleanResolvers(Module* module)\r{\r        for (int i = 0; i < MAX_REQUEST_ID; i++)\r       {\r              if (Classes[i])\r                {\r                      if (Classes[i]->GetCreator() == module)\r                        {\r                              Classes[i]->OnError(RESLOVER_FORCEUNLOAD, "Parent module is unloading");\r                               delete Classes[i];\r                             Classes[i] = NULL;\r                     }\r              }\r      }\r}\r\r/** Generate pseudo-random number */\runsigned long DNS::PRNG()\r{\r#ifndef WIN32\r    unsigned long val = 0;\r timeval n;\r     serverstats* s = ServerInstance->stats;\r        gettimeofday(&n,NULL);\r val = (n.tv_usec ^ getpid() ^ geteuid() ^ (this->currid++)) ^ s->statsAccept + n.tv_sec;\r       val = val + s->statsCollisions ^ s->statsDnsGood - s->statsDnsBad;\r     val += (s->statsConnects ^ (unsigned long)s->statsSent ^ (unsigned long)s->statsRecv) - ServerInstance->Config->ports.size();\r  return val;\r#else\r      unsigned long val = 0;\r serverstats* s = ServerInstance->stats;\r        val = (time(NULL) ^ GetCurrentProcessId() ^ GetCurrentThreadId() ^ (this->currid++)) ^ s->statsAccept + time(NULL);\r    val = val + s->statsCollisions ^ s->statsDnsGood - s->statsDnsBad;\r     val += (s->statsConnects ^ (unsigned long)s->statsSent ^ (unsigned long)s->statsRecv);\r return val;\r#endif\r}\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+/*
+dns.cpp - Nonblocking DNS functions.
+Very very loosely based on the firedns library,
+Copyright (C) 2002 Ian Gulliver. This file is no
+longer anything like firedns, there are many major
+differences between this code and the original.
+Please do not assume that firedns works like this,
+looks like this, walks like this or tastes like this.
+*/
+
+#ifndef WIN32
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <errno.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#else
+#include "inspircd_win32wrapper.h"
+#include "inspircd_se_config.h"
+#endif
+
+#include "dns.h"
+#include "inspircd.h"
+#include "socketengine.h"
+#include "configreader.h"
+#include "socket.h"
+
+using irc::sockets::insp_inaddr;
+using irc::sockets::insp_ntoa;
+using irc::sockets::insp_aton;
+using irc::sockets::OpenTCPSocket;
+
+/** Masks to mask off the responses we get from the DNSRequest methods
+ */
+enum QueryInfo
+{
+       ERROR_MASK      = 0x10000       /* Result is an error */
+};
+
+/** Flags which can be ORed into a request or reply for different meanings
+ */
+enum QueryFlags
+{
+       FLAGS_MASK_RD           = 0x01, /* Recursive */
+       FLAGS_MASK_TC           = 0x02,
+       FLAGS_MASK_AA           = 0x04, /* Authoritative */
+       FLAGS_MASK_OPCODE       = 0x78,
+       FLAGS_MASK_QR           = 0x80,
+       FLAGS_MASK_RCODE        = 0x0F, /* Request */
+       FLAGS_MASK_Z            = 0x70,
+       FLAGS_MASK_RA           = 0x80
+};
+
+
+/** Represents a dns resource record (rr)
+ */
+struct ResourceRecord
+{
+       QueryType       type;           /* Record type */
+       unsigned int    rr_class;       /* Record class */
+       unsigned long   ttl;            /* Time to live */
+       unsigned int    rdlength;       /* Record length */
+};
+
+/** Represents a dns request/reply header, and its payload as opaque data.
+ */
+class DNSHeader
+{
+ public:
+       unsigned char   id[2];          /* Request id */
+       unsigned int    flags1;         /* Flags */
+       unsigned int    flags2;         /* Flags */
+       unsigned int    qdcount;
+       unsigned int    ancount;        /* Answer count */
+       unsigned int    nscount;        /* Nameserver count */
+       unsigned int    arcount;
+       unsigned char   payload[512];   /* Packet payload */
+};
+
+class DNSRequest
+{
+ public:
+       unsigned char   id[2];          /* Request id */
+       unsigned char*  res;            /* Result processing buffer */
+       unsigned int    rr_class;       /* Request class */
+       QueryType       type;           /* Request type */
+       DNS*            dnsobj;         /* DNS caller (where we get our FD from) */
+       unsigned long   ttl;            /* Time to live */
+       std::string     orig;           /* Original requested name/ip */
+
+       DNSRequest(InspIRCd* Instance, DNS* dns, int id, const std::string &original);
+       ~DNSRequest();
+       DNSInfo ResultIsReady(DNSHeader &h, int length);
+       int SendRequests(const DNSHeader *header, const int length, QueryType qt);
+};
+
+class CacheTimer : public InspTimer
+{
+ private:
+       InspIRCd* ServerInstance;
+       DNS* dns;
+ public:
+       CacheTimer(InspIRCd* Instance, DNS* thisdns)
+               : InspTimer(3600, Instance->Time(), true), ServerInstance(Instance), dns(thisdns) { }
+
+       virtual void Tick(time_t TIME)
+       {
+               dns->PruneCache();
+       }
+};
+
+class RequestTimeout : public InspTimer
+{
+       InspIRCd* ServerInstance;
+       DNSRequest* watch;
+       int watchid;
+ public:
+       RequestTimeout(unsigned long n, InspIRCd* SI, DNSRequest* watching, int id) : InspTimer(n, time(NULL)), ServerInstance(SI), watch(watching), watchid(id)
+       {
+       }
+
+       void Tick(time_t TIME)
+       {
+               if (ServerInstance->Res->requests[watchid] == watch)
+               {
+                       /* Still exists, whack it */
+                       if (ServerInstance->Res->Classes[watchid])
+                       {
+                               ServerInstance->Res->Classes[watchid]->OnError(RESOLVER_TIMEOUT, "Request timed out");
+                               delete ServerInstance->Res->Classes[watchid];
+                               ServerInstance->Res->Classes[watchid] = NULL;
+                       }
+                       ServerInstance->Res->requests[watchid] = NULL;
+                       DELETE(watch);
+                       return;
+               }
+       }
+};
+
+/* Allocate the processing buffer */
+DNSRequest::DNSRequest(InspIRCd* Instance, DNS* dns, int id, const std::string &original) : dnsobj(dns)
+{
+       res = new unsigned char[512];
+       *res = 0;
+       orig = original;
+       RequestTimeout* RT = new RequestTimeout(Instance->Config->dns_timeout ? Instance->Config->dns_timeout : 5, Instance, this, id);
+       Instance->Timers->AddTimer(RT); /* The timer manager frees this */
+}
+
+/* Deallocate the processing buffer */
+DNSRequest::~DNSRequest()
+{
+       delete[] res;
+}
+
+/** Fill a ResourceRecord class based on raw data input */
+inline void DNS::FillResourceRecord(ResourceRecord* rr, const unsigned char *input)
+{
+       rr->type = (QueryType)((input[0] << 8) + input[1]);
+       rr->rr_class = (input[2] << 8) + input[3];
+       rr->ttl = (input[4] << 24) + (input[5] << 16) + (input[6] << 8) + input[7];
+       rr->rdlength = (input[8] << 8) + input[9];
+}
+
+/** Fill a DNSHeader class based on raw data input of a given length */
+inline void DNS::FillHeader(DNSHeader *header, const unsigned char *input, const int length)
+{
+       header->id[0] = input[0];
+       header->id[1] = input[1];
+       header->flags1 = input[2];
+       header->flags2 = input[3];
+       header->qdcount = (input[4] << 8) + input[5];
+       header->ancount = (input[6] << 8) + input[7];
+       header->nscount = (input[8] << 8) + input[9];
+       header->arcount = (input[10] << 8) + input[11];
+       memcpy(header->payload,&input[12],length);
+}
+
+/** Empty a DNSHeader class out into raw data, ready for transmission */
+inline void DNS::EmptyHeader(unsigned char *output, const DNSHeader *header, const int length)
+{
+       output[0] = header->id[0];
+       output[1] = header->id[1];
+       output[2] = header->flags1;
+       output[3] = header->flags2;
+       output[4] = header->qdcount >> 8;
+       output[5] = header->qdcount & 0xFF;
+       output[6] = header->ancount >> 8;
+       output[7] = header->ancount & 0xFF;
+       output[8] = header->nscount >> 8;
+       output[9] = header->nscount & 0xFF;
+       output[10] = header->arcount >> 8;
+       output[11] = header->arcount & 0xFF;
+       memcpy(&output[12],header->payload,length);
+}
+
+/** Send requests we have previously built down the UDP socket */
+int DNSRequest::SendRequests(const DNSHeader *header, const int length, QueryType qt)
+{
+       unsigned char payload[sizeof(DNSHeader)];
+
+       this->rr_class = 1;
+       this->type = qt;
+               
+       DNS::EmptyHeader(payload,header,length);
+
+#ifdef IPV6
+       if (this->dnsobj->socketfamily == AF_INET6)
+       {
+               sockaddr_in6 addr;
+               memset(&addr,0,sizeof(addr));
+               memcpy(&addr.sin6_addr,&dnsobj->myserver6,sizeof(addr.sin6_addr));
+               addr.sin6_family = AF_INET6;
+               addr.sin6_port = htons(DNS::QUERY_PORT);
+               if (sendto(dnsobj->GetFd(), payload, length + 12, 0, (sockaddr *) &addr, sizeof(addr)) != length+12)
+                       return -1;
+       }
+       else
+       {
+               sockaddr_in addr;
+               memset(&addr,0,sizeof(addr));
+               memcpy(&addr.sin_addr.s_addr,&dnsobj->myserver4,sizeof(addr.sin_addr));
+               addr.sin_family = AF_INET;
+               addr.sin_port = htons(DNS::QUERY_PORT);
+               if (sendto(dnsobj->GetFd(), payload, length + 12, 0, (sockaddr *) &addr, sizeof(addr)) != length+12)
+                       return -1;
+       }
+#else
+       sockaddr_in addr;
+       memset(&addr,0,sizeof(addr));
+       memcpy(&addr.sin_addr.s_addr, &dnsobj->myserver4, sizeof(addr.sin_addr));
+       addr.sin_family = AF_INET;
+       addr.sin_port = htons(DNS::QUERY_PORT);
+       if (sendto(dnsobj->GetFd(), (const char*)payload, length + 12, 0, (sockaddr *) &addr, sizeof(addr)) != length+12)
+               return -1;
+#endif
+
+       return 0;
+}
+
+/** Add a query with a predefined header, and allocate an ID for it. */
+DNSRequest* DNS::AddQuery(DNSHeader *header, int &id, const char* original)
+{
+       /* Is the DNS connection down? */
+       if (this->GetFd() == -1)
+               return NULL;
+       
+       /* Create an id */
+       id = this->PRNG() & DNS::MAX_REQUEST_ID;
+
+       /* If this id is already 'in flight', pick another. */
+       while (requests[id])
+               id = this->PRNG() & DNS::MAX_REQUEST_ID;
+
+       DNSRequest* req = new DNSRequest(ServerInstance, this, id, original);
+
+       header->id[0] = req->id[0] = id >> 8;
+       header->id[1] = req->id[1] = id & 0xFF;
+       header->flags1 = FLAGS_MASK_RD;
+       header->flags2 = 0;
+       header->qdcount = 1;
+       header->ancount = 0;
+       header->nscount = 0;
+       header->arcount = 0;
+
+       /* At this point we already know the id doesnt exist,
+        * so there needs to be no second check for the ::end()
+        */
+       requests[id] = req;
+
+       /* According to the C++ spec, new never returns NULL. */
+       return req;
+}
+
+int DNS::ClearCache()
+{
+       /* This ensures the buckets are reset to sane levels */
+       int rv = this->cache->size();
+       delete this->cache;
+       this->cache = new dnscache();
+       return rv;
+}
+
+int DNS::PruneCache()
+{
+       int n = 0;
+       dnscache* newcache = new dnscache();
+       for (dnscache::iterator i = this->cache->begin(); i != this->cache->end(); i++)
+               /* Dont include expired items (theres no point) */
+               if (i->second.CalcTTLRemaining())
+                       newcache->insert(*i);
+               else
+                       n++;
+
+       delete this->cache;
+       this->cache = newcache;
+       return n;
+}
+
+void DNS::Rehash()
+{
+       ip6munge = false;
+       int portpass = 0;
+
+       if (this->GetFd() > -1)
+       {
+               if (ServerInstance && ServerInstance->SE)
+                       ServerInstance->SE->DelFd(this);
+               shutdown(this->GetFd(), 2);
+               close(this->GetFd());
+               this->SetFd(-1);
+
+               /* Rehash the cache */
+               this->PruneCache();
+       }
+       else
+       {
+               /* Create initial dns cache */
+               this->cache = new dnscache();
+       }
+
+       if ((strstr(ServerInstance->Config->DNSServer,"::ffff:") == (char*)&ServerInstance->Config->DNSServer) ||  (strstr(ServerInstance->Config->DNSServer,"::FFFF:") == (char*)&ServerInstance->Config->DNSServer))
+       {
+               ServerInstance->Log(DEFAULT,"WARNING: Using IPv4 addresses over IPv6 forces some DNS checks to be disabled.");
+               ServerInstance->Log(DEFAULT,"         This should not cause a problem, however it is recommended you migrate");
+               ServerInstance->Log(DEFAULT,"         to a true IPv6 environment.");
+               this->ip6munge = true;
+       }
+
+       this->socketfamily = AF_INET;
+#ifdef IPV6
+       if (strchr(ServerInstance->Config->DNSServer,':'))
+       {
+               this->socketfamily = AF_INET6;
+               inet_pton(AF_INET6, ServerInstance->Config->DNSServer, &this->myserver6);
+       }
+       else
+       {
+               inet_aton(ServerInstance->Config->DNSServer, &this->myserver4);
+               portpass = -1;
+       }
+#else
+       inet_aton(ServerInstance->Config->DNSServer, &this->myserver4);
+#endif
+
+       /* Initialize mastersocket */
+       int s = OpenTCPSocket(ServerInstance->Config->DNSServer, SOCK_DGRAM);
+       this->SetFd(s);
+
+       /* Have we got a socket and is it nonblocking? */
+       if (this->GetFd() != -1)
+       {
+               /* Bind the port - port 0 INADDR_ANY */
+               if (!ServerInstance->BindSocket(this->GetFd(), portpass, "", false))
+               {
+                       /* Failed to bind */
+                       shutdown(this->GetFd(),2);
+                       close(this->GetFd());
+                       this->SetFd(-1);
+               }
+
+               if (this->GetFd() >= 0)
+               {
+                       /* Hook the descriptor into the socket engine */
+                       if (ServerInstance && ServerInstance->SE)
+                       {
+                               if (!ServerInstance->SE->AddFd(this))
+                               {
+                                       ServerInstance->Log(DEFAULT,"Internal error starting DNS - hostnames will NOT resolve.");
+                                       shutdown(this->GetFd(),2);
+                                       close(this->GetFd());
+                                       this->SetFd(-1);
+                               }
+                       }
+               }
+       }
+}
+
+/** Initialise the DNS UDP socket so that we can send requests */
+DNS::DNS(InspIRCd* Instance) : ServerInstance(Instance)
+{
+       /* Clear the Resolver class table */
+       memset(Classes,0,sizeof(Classes));
+
+       /* Clear the requests class table */
+       memset(requests,0,sizeof(requests));
+
+       /* Set the id of the next request to 0
+        */
+       currid = 0;
+
+       /* DNS::Rehash() sets this to a valid ptr
+        */
+       this->cache = NULL;
+       
+       /* Again, DNS::Rehash() sets this to a
+        * valid value
+        */
+       this->SetFd(-1);
+
+       /* Actually read the settings
+        */
+       this->Rehash();
+
+       this->PruneTimer = new CacheTimer(ServerInstance, this);
+
+       ServerInstance->Timers->AddTimer(this->PruneTimer);
+}
+
+/** Build a payload to be placed after the header, based upon input data, a resource type, a class and a pointer to a buffer */
+int DNS::MakePayload(const char * const name, const QueryType rr, const unsigned short rr_class, unsigned char * const payload)
+{
+       short payloadpos = 0;
+       const char* tempchr, *tempchr2 = name;
+       unsigned short length;
+
+       /* split name up into labels, create query */
+       while ((tempchr = strchr(tempchr2,'.')) != NULL)
+       {
+               length = tempchr - tempchr2;
+               if (payloadpos + length + 1 > 507)
+                       return -1;
+               payload[payloadpos++] = length;
+               memcpy(&payload[payloadpos],tempchr2,length);
+               payloadpos += length;
+               tempchr2 = &tempchr[1];
+       }
+       length = strlen(tempchr2);
+       if (length)
+       {
+               if (payloadpos + length + 2 > 507)
+                       return -1;
+               payload[payloadpos++] = length;
+               memcpy(&payload[payloadpos],tempchr2,length);
+               payloadpos += length;
+               payload[payloadpos++] = 0;
+       }
+       if (payloadpos > 508)
+               return -1;
+       length = htons(rr);
+       memcpy(&payload[payloadpos],&length,2);
+       length = htons(rr_class);
+       memcpy(&payload[payloadpos + 2],&length,2);
+       return payloadpos + 4;
+}
+
+/** Start lookup of an hostname to an IP address */
+int DNS::GetIP(const char *name)
+{
+       DNSHeader h;
+       int id;
+       int length;
+       
+       if ((length = this->MakePayload(name, DNS_QUERY_A, 1, (unsigned char*)&h.payload)) == -1)
+               return -1;
+
+       DNSRequest* req = this->AddQuery(&h, id, name);
+
+       if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_A) == -1))
+               return -1;
+
+       return id;
+}
+
+/** Start lookup of an hostname to an IPv6 address */
+int DNS::GetIP6(const char *name)
+{
+       DNSHeader h;
+       int id;
+       int length;
+
+       if ((length = this->MakePayload(name, DNS_QUERY_AAAA, 1, (unsigned char*)&h.payload)) == -1)
+               return -1;
+
+       DNSRequest* req = this->AddQuery(&h, id, name);
+
+       if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_AAAA) == -1))
+               return -1;
+
+       return id;
+}
+
+/** Start lookup of a cname to another name */
+int DNS::GetCName(const char *alias)
+{
+       DNSHeader h;
+       int id;
+       int length;
+
+       if ((length = this->MakePayload(alias, DNS_QUERY_CNAME, 1, (unsigned char*)&h.payload)) == -1)
+               return -1;
+
+       DNSRequest* req = this->AddQuery(&h, id, alias);
+
+       if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_CNAME) == -1))
+               return -1;
+
+       return id;
+}
+
+/** Start lookup of an IP address to a hostname */
+int DNS::GetName(const insp_inaddr *ip)
+{
+       char query[128];
+       DNSHeader h;
+       int id;
+       int length;
+
+#ifdef IPV6
+       unsigned char* c = (unsigned char*)&ip->s6_addr;
+       if (c[0] == 0 && c[1] == 0 && c[2] == 0 && c[3] == 0 &&
+           c[4] == 0 && c[5] == 0 && c[6] == 0 && c[7] == 0 &&
+           c[8] == 0 && c[9] == 0 && c[10] == 0xFF && c[11] == 0xFF)
+               sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[15],c[14],c[13],c[12]);
+       else
+               DNS::MakeIP6Int(query, (in6_addr*)ip);
+#else
+       unsigned char* c = (unsigned char*)&ip->s_addr;
+       sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[3],c[2],c[1],c[0]);
+#endif
+
+       if ((length = this->MakePayload(query, DNS_QUERY_PTR, 1, (unsigned char*)&h.payload)) == -1)
+               return -1;
+
+       DNSRequest* req = this->AddQuery(&h, id, insp_ntoa(*ip));
+
+       if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_PTR) == -1))
+               return -1;
+
+       return id;
+}
+
+/** Start lookup of an IP address to a hostname */
+int DNS::GetNameForce(const char *ip, ForceProtocol fp)
+{
+       char query[128];
+       DNSHeader h;
+       int id;
+       int length;
+#ifdef SUPPORT_IP6LINKS
+       if (fp == PROTOCOL_IPV6)
+       {
+               in6_addr i;
+               if (inet_pton(AF_INET6, ip, &i) > 0)
+               {
+                       DNS::MakeIP6Int(query, &i);
+               }
+               else
+                       /* Invalid IP address */
+                       return -1;
+       }
+       else
+#endif
+       {
+               in_addr i;
+               if (inet_aton(ip, &i))
+               {
+                       unsigned char* c = (unsigned char*)&i.s_addr;
+                       sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[3],c[2],c[1],c[0]);
+               }
+               else
+                       /* Invalid IP address */
+                       return -1;
+       }
+
+       if ((length = this->MakePayload(query, DNS_QUERY_PTR, 1, (unsigned char*)&h.payload)) == -1)
+               return -1;
+
+       DNSRequest* req = this->AddQuery(&h, id, ip);
+
+       if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_PTR) == -1))
+               return -1;
+
+       return id;
+}
+
+/** Build an ipv6 reverse domain from an in6_addr
+ */
+void DNS::MakeIP6Int(char* query, const in6_addr *ip)
+{
+#ifdef SUPPORT_IP6LINKS
+       const char* hex = "0123456789abcdef";
+       for (int index = 31; index >= 0; index--) /* for() loop steps twice per byte */
+       {
+               if (index % 2)
+                       /* low nibble */
+                       *query++ = hex[ip->s6_addr[index / 2] & 0x0F];
+               else
+                       /* high nibble */
+                       *query++ = hex[(ip->s6_addr[index / 2] & 0xF0) >> 4];
+               *query++ = '.'; /* Seperator */
+       }
+       strcpy(query,"ip6.arpa"); /* Suffix the string */
+#else
+       *query = 0;
+#endif
+}
+
+/** Return the next id which is ready, and the result attached to it */
+DNSResult DNS::GetResult()
+{
+       /* Fetch dns query response and decide where it belongs */
+       DNSHeader header;
+       DNSRequest *req;
+       unsigned char buffer[sizeof(DNSHeader)];
+       sockaddr* from = new sockaddr[2];
+#ifdef IPV6
+       socklen_t x = this->socketfamily == AF_INET ? sizeof(sockaddr_in) : sizeof(sockaddr_in6);
+#else
+       socklen_t x = sizeof(sockaddr_in);
+#endif
+       const char* ipaddr_from;
+       unsigned short int port_from = 0;
+       int length = _recvfrom(this->GetFd(),(char*)buffer,sizeof(DNSHeader),0,from,&x);
+
+       /* Did we get the whole header? */
+       if (length < 12)
+       {
+               /* Nope - something screwed up. */
+               delete[] from;
+               return DNSResult(-1,"",0,"");
+       }
+
+       /* Check wether the reply came from a different DNS
+        * server to the one we sent it to, or the source-port
+        * is not 53.
+        * A user could in theory still spoof dns packets anyway
+        * but this is less trivial than just sending garbage
+        * to the client, which is possible without this check.
+        *
+        * -- Thanks jilles for pointing this one out.
+        */
+#ifdef IPV6
+       char nbuf[MAXBUF];
+       if (this->socketfamily == AF_INET6)
+       {
+               ipaddr_from = inet_ntop(AF_INET6, &((sockaddr_in6*)from)->sin6_addr, nbuf, sizeof(nbuf));
+               port_from = ntohs(((sockaddr_in6*)from)->sin6_port);
+       }
+       else
+#endif
+       {
+               ipaddr_from = inet_ntoa(((sockaddr_in*)from)->sin_addr);
+               port_from = ntohs(((sockaddr_in*)from)->sin_port);
+       }
+
+       delete[] from;
+
+       /* We cant perform this security check if you're using 4in6.
+        * Tough luck to you, choose one or't other!
+        */
+       if (!ip6munge)
+       {
+               if ((port_from != DNS::QUERY_PORT) || (strcasecmp(ipaddr_from, ServerInstance->Config->DNSServer)))
+               {
+                       return DNSResult(-1,"",0,"");
+               }
+       }
+
+       /* Put the read header info into a header class */
+       DNS::FillHeader(&header,buffer,length - 12);
+
+       /* Get the id of this request.
+        * Its a 16 bit value stored in two char's,
+        * so we use logic shifts to create the value.
+        */
+       unsigned long this_id = header.id[1] + (header.id[0] << 8);
+
+       /* Do we have a pending request matching this id? */
+       if (!requests[this_id])
+       {
+               /* Somehow we got a DNS response for a request we never made... */
+               return DNSResult(-1,"",0,"");
+       }
+       else
+       {
+               /* Remove the query from the list of pending queries */
+               req = requests[this_id];
+               requests[this_id] = NULL;
+       }
+
+       /* Inform the DNSRequest class that it has a result to be read.
+        * When its finished it will return a DNSInfo which is a pair of
+        * unsigned char* resource record data, and an error message.
+        */
+       DNSInfo data = req->ResultIsReady(header, length);
+       std::string resultstr;
+
+       /* Check if we got a result, if we didnt, its an error */
+       if (data.first == NULL)
+       {
+               /* An error.
+                * Mask the ID with the value of ERROR_MASK, so that
+                * the dns_deal_with_classes() function knows that its
+                * an error response and needs to be treated uniquely.
+                * Put the error message in the second field.
+                */
+               std::string ro = req->orig;
+               delete req;
+               return DNSResult(this_id | ERROR_MASK, data.second, 0, ro);
+       }
+       else
+       {
+               unsigned long ttl = req->ttl;
+               char formatted[128];
+
+               /* Forward lookups come back as binary data. We must format them into ascii */
+               switch (req->type)
+               {
+                       case DNS_QUERY_A:
+                               snprintf(formatted,16,"%u.%u.%u.%u",data.first[0],data.first[1],data.first[2],data.first[3]);
+                               resultstr = formatted;
+                       break;
+
+                       case DNS_QUERY_AAAA:
+                       {
+                               snprintf(formatted,40,"%x:%x:%x:%x:%x:%x:%x:%x",
+                                               (ntohs(data.first[0]) + ntohs(data.first[1] << 8)),
+                                               (ntohs(data.first[2]) + ntohs(data.first[3] << 8)),
+                                               (ntohs(data.first[4]) + ntohs(data.first[5] << 8)),
+                                               (ntohs(data.first[6]) + ntohs(data.first[7] << 8)),
+                                               (ntohs(data.first[8]) + ntohs(data.first[9] << 8)),
+                                               (ntohs(data.first[10]) + ntohs(data.first[11] << 8)),
+                                               (ntohs(data.first[12]) + ntohs(data.first[13] << 8)),
+                                               (ntohs(data.first[14]) + ntohs(data.first[15] << 8)));
+                               char* c = strstr(formatted,":0:");
+                               if (c != NULL)
+                               {
+                                       memmove(c+1,c+2,strlen(c+2) + 1);
+                                       c += 2;
+                                       while (memcmp(c,"0:",2) == 0)
+                                               memmove(c,c+2,strlen(c+2) + 1);
+                                       if (memcmp(c,"0",2) == 0)
+                                               *c = 0;
+                                       if (memcmp(formatted,"0::",3) == 0)
+                                               memmove(formatted,formatted + 1, strlen(formatted + 1) + 1);
+                               }
+                               resultstr = formatted;
+
+                               /* Special case. Sending ::1 around between servers
+                                * and to clients is dangerous, because the : on the
+                                * start makes the client or server interpret the IP
+                                * as the last parameter on the line with a value ":1".
+                                */
+                               if (*formatted == ':')
+                                       resultstr.insert(0, "0");
+                       }
+                       break;
+
+                       case DNS_QUERY_CNAME:
+                               /* Identical handling to PTR */
+
+                       case DNS_QUERY_PTR:
+                               /* Reverse lookups just come back as char* */
+                               resultstr = std::string((const char*)data.first);
+                       break;
+
+                       default:
+                       break;
+                       
+               }
+
+               /* Build the reply with the id and hostname/ip in it */
+               std::string ro = req->orig;
+               delete req;
+               return DNSResult(this_id,resultstr,ttl,ro);
+       }
+}
+
+/** A result is ready, process it */
+DNSInfo DNSRequest::ResultIsReady(DNSHeader &header, int length)
+{
+       int i = 0;
+       int q = 0;
+       int curanswer, o;
+       ResourceRecord rr;
+       unsigned short ptr;
+
+       /* This is just to keep _FORTIFY_SOURCE happy */
+       rr.type = DNS_QUERY_NONE;
+       rr.rdlength = 0;
+       rr.ttl = 1;     /* GCC is a whiney bastard -- see the XXX below. */
+
+       if (!(header.flags1 & FLAGS_MASK_QR))
+               return std::make_pair((unsigned char*)NULL,"Not a query result");
+
+       if (header.flags1 & FLAGS_MASK_OPCODE)
+               return std::make_pair((unsigned char*)NULL,"Unexpected value in DNS reply packet");
+
+       if (header.flags2 & FLAGS_MASK_RCODE)
+               return std::make_pair((unsigned char*)NULL,"Domain name not found");
+
+       if (header.ancount < 1)
+               return std::make_pair((unsigned char*)NULL,"No resource records returned");
+
+       /* Subtract the length of the header from the length of the packet */
+       length -= 12;
+
+       while ((unsigned int)q < header.qdcount && i < length)
+       {
+               if (header.payload[i] > 63)
+               {
+                       i += 6;
+                       q++;
+               }
+               else
+               {
+                       if (header.payload[i] == 0)
+                       {
+                               q++;
+                               i += 5;
+                       }
+                       else i += header.payload[i] + 1;
+               }
+       }
+       curanswer = 0;
+       while ((unsigned)curanswer < header.ancount)
+       {
+               q = 0;
+               while (q == 0 && i < length)
+               {
+                       if (header.payload[i] > 63)
+                       {
+                               i += 2;
+                               q = 1;
+                       }
+                       else
+                       {
+                               if (header.payload[i] == 0)
+                               {
+                                       i++;
+                                       q = 1;
+                               }
+                               else i += header.payload[i] + 1; /* skip length and label */
+                       }
+               }
+               if (length - i < 10)
+                       return std::make_pair((unsigned char*)NULL,"Incorrectly sized DNS reply");
+
+               /* XXX: We actually initialise 'rr' here including its ttl field */
+               DNS::FillResourceRecord(&rr,&header.payload[i]);
+               i += 10;
+               if (rr.type != this->type)
+               {
+                       curanswer++;
+                       i += rr.rdlength;
+                       continue;
+               }
+               if (rr.rr_class != this->rr_class)
+               {
+                       curanswer++;
+                       i += rr.rdlength;
+                       continue;
+               }
+               break;
+       }
+       if ((unsigned int)curanswer == header.ancount)
+               return std::make_pair((unsigned char*)NULL,"No valid answers");
+
+       if (i + rr.rdlength > (unsigned int)length)
+               return std::make_pair((unsigned char*)NULL,"Resource record larger than stated");
+
+       if (rr.rdlength > 1023)
+               return std::make_pair((unsigned char*)NULL,"Resource record too large");
+
+       this->ttl = rr.ttl;
+
+       switch (rr.type)
+       {
+               case DNS_QUERY_CNAME:
+                       /* CNAME and PTR have the same processing code */
+               case DNS_QUERY_PTR:
+                       o = 0;
+                       q = 0;
+                       while (q == 0 && i < length && o + 256 < 1023)
+                       {
+                               if (header.payload[i] > 63)
+                               {
+                                       memcpy(&ptr,&header.payload[i],2);
+                                       i = ntohs(ptr) - 0xC000 - 12;
+                               }
+                               else
+                               {
+                                       if (header.payload[i] == 0)
+                                       {
+                                               q = 1;
+                                       }
+                                       else
+                                       {
+                                               res[o] = 0;
+                                               if (o != 0)
+                                                       res[o++] = '.';
+                                               memcpy(&res[o],&header.payload[i + 1],header.payload[i]);
+                                               o += header.payload[i];
+                                               i += header.payload[i] + 1;
+                                       }
+                               }
+                       }
+                       res[o] = 0;
+               break;
+               case DNS_QUERY_AAAA:
+                       memcpy(res,&header.payload[i],rr.rdlength);
+                       res[rr.rdlength] = 0;
+               break;
+               case DNS_QUERY_A:
+                       memcpy(res,&header.payload[i],rr.rdlength);
+                       res[rr.rdlength] = 0;
+               break;
+               default:
+                       memcpy(res,&header.payload[i],rr.rdlength);
+                       res[rr.rdlength] = 0;
+               break;
+       }
+       return std::make_pair(res,"No error");;
+}
+
+/** Close the master socket */
+DNS::~DNS()
+{
+       shutdown(this->GetFd(), 2);
+       close(this->GetFd());
+       ServerInstance->Timers->DelTimer(this->PruneTimer);
+       delete this->PruneTimer;
+}
+
+CachedQuery* DNS::GetCache(const std::string &source)
+{
+       dnscache::iterator x = cache->find(source.c_str());
+       if (x != cache->end())
+               return &(x->second);
+       else
+               return NULL;
+}
+               
+void DNS::DelCache(const std::string &source)
+{
+       cache->erase(source.c_str());
+}
+
+void Resolver::TriggerCachedResult()
+{
+       if (CQ)
+               OnLookupComplete(CQ->data, time_left, true);
+}
+
+/** High level abstraction of dns used by application at large */
+Resolver::Resolver(InspIRCd* Instance, const std::string &source, QueryType qt, bool &cached, Module* creator) : ServerInstance(Instance), Creator(creator), input(source), querytype(qt)
+{
+       cached = false;
+
+       CQ = ServerInstance->Res->GetCache(source);
+       if (CQ)
+       {
+               time_left = CQ->CalcTTLRemaining();
+               if (!time_left)
+               {
+                       ServerInstance->Res->DelCache(source);
+               }
+               else
+               {
+                       cached = true;
+                       return;
+               }
+       }
+
+       insp_inaddr binip;
+
+       switch (querytype)
+       {
+               case DNS_QUERY_A:
+                       this->myid = ServerInstance->Res->GetIP(source.c_str());
+               break;
+
+               case DNS_QUERY_PTR:
+                       if (insp_aton(source.c_str(), &binip) > 0)
+                       {
+                               /* Valid ip address */
+                               this->myid = ServerInstance->Res->GetName(&binip);
+                       }
+                       else
+                       {
+                               this->OnError(RESOLVER_BADIP, "Bad IP address for reverse lookup");
+                               throw ModuleException("Resolver: Bad IP address");
+                               return;
+                       }
+               break;
+
+               case DNS_QUERY_PTR4:
+                       querytype = DNS_QUERY_PTR;
+                       this->myid = ServerInstance->Res->GetNameForce(source.c_str(), PROTOCOL_IPV4);
+               break;
+
+               case DNS_QUERY_PTR6:
+                       querytype = DNS_QUERY_PTR;
+                       this->myid = ServerInstance->Res->GetNameForce(source.c_str(), PROTOCOL_IPV6);
+               break;
+
+               case DNS_QUERY_AAAA:
+                       this->myid = ServerInstance->Res->GetIP6(source.c_str());
+               break;
+
+               case DNS_QUERY_CNAME:
+                       this->myid = ServerInstance->Res->GetCName(source.c_str());
+               break;
+
+               default:
+                       this->myid = -1;
+               break;
+       }
+       if (this->myid == -1)
+       {
+               this->OnError(RESOLVER_NSDOWN, "Nameserver is down");
+               throw ModuleException("Resolver: Couldnt get an id to make a request");
+               /* We shouldnt get here really */
+               return;
+       }
+}
+
+/** Called when an error occurs */
+void Resolver::OnError(ResolverError e, const std::string &errormessage)
+{
+       /* Nothing in here */
+}
+
+/** Destroy a resolver */
+Resolver::~Resolver()
+{
+       /* Nothing here (yet) either */
+}
+
+/** Get the request id associated with this class */
+int Resolver::GetId()
+{
+       return this->myid;
+}
+
+Module* Resolver::GetCreator()
+{
+       return this->Creator;
+}
+
+/** Process a socket read event */
+void DNS::HandleEvent(EventType et, int errornum)
+{
+       /* Fetch the id and result of the next available packet */
+       DNSResult res = this->GetResult();
+       /* Is there a usable request id? */
+       if (res.id != -1)
+       {
+               /* Its an error reply */
+               if (res.id & ERROR_MASK)
+               {
+                       /* Mask off the error bit */
+                       res.id -= ERROR_MASK;
+                       /* Marshall the error to the correct class */
+                       if (Classes[res.id])
+                       {
+                               if (ServerInstance && ServerInstance->stats)
+                                       ServerInstance->stats->statsDnsBad++;
+                               Classes[res.id]->OnError(RESOLVER_NXDOMAIN, res.result);
+                               delete Classes[res.id];
+                               Classes[res.id] = NULL;
+                       }
+               }
+               else
+               {
+                       /* It is a non-error result, marshall the result to the correct class */
+                       if (Classes[res.id])
+                       {
+                               if (ServerInstance && ServerInstance->stats)
+                                       ServerInstance->stats->statsDnsGood++;
+
+                               if (!this->GetCache(res.original.c_str()))
+                                       this->cache->insert(std::make_pair(res.original.c_str(), CachedQuery(res.result, res.ttl)));
+
+                               Classes[res.id]->OnLookupComplete(res.result, res.ttl, false);
+                               delete Classes[res.id];
+                               Classes[res.id] = NULL;
+                       }
+               }
+
+               if (ServerInstance && ServerInstance->stats)
+                       ServerInstance->stats->statsDns++;
+       }
+}
+
+/** Add a derived Resolver to the working set */
+bool DNS::AddResolverClass(Resolver* r)
+{
+       /* Check the pointers validity and the id's validity */
+       if ((r) && (r->GetId() > -1))
+       {
+               /* Check the slot isnt already occupied -
+                * This should NEVER happen unless we have
+                * a severely broken DNS server somewhere
+                */
+               if (!Classes[r->GetId()])
+               {
+                       /* Set up the pointer to the class */
+                       Classes[r->GetId()] = r;
+                       return true;
+               }
+               else
+                       /* Duplicate id */
+                       return false;
+       }
+       else
+       {
+               /* Pointer or id not valid.
+                * Free the item and return
+                */
+               if (r)
+                       delete r;
+
+               return false;
+       }
+}
+
+void DNS::CleanResolvers(Module* module)
+{
+       for (int i = 0; i < MAX_REQUEST_ID; i++)
+       {
+               if (Classes[i])
+               {
+                       if (Classes[i]->GetCreator() == module)
+                       {
+                               Classes[i]->OnError(RESLOVER_FORCEUNLOAD, "Parent module is unloading");
+                               delete Classes[i];
+                               Classes[i] = NULL;
+                       }
+               }
+       }
+}
+
+/** Generate pseudo-random number */
+unsigned long DNS::PRNG()
+{
+#ifndef WIN32
+       unsigned long val = 0;
+       timeval n;
+       serverstats* s = ServerInstance->stats;
+       gettimeofday(&n,NULL);
+       val = (n.tv_usec ^ getpid() ^ geteuid() ^ (this->currid++)) ^ s->statsAccept + n.tv_sec;
+       val = val + s->statsCollisions ^ s->statsDnsGood - s->statsDnsBad;
+       val += (s->statsConnects ^ (unsigned long)s->statsSent ^ (unsigned long)s->statsRecv) - ServerInstance->Config->ports.size();
+       return val;
+#else
+       unsigned long val = 0;
+       serverstats* s = ServerInstance->stats;
+       val = (time(NULL) ^ GetCurrentProcessId() ^ GetCurrentThreadId() ^ (this->currid++)) ^ s->statsAccept + time(NULL);
+       val = val + s->statsCollisions ^ s->statsDnsGood - s->statsDnsBad;
+       val += (s->statsConnects ^ (unsigned long)s->statsSent ^ (unsigned long)s->statsRecv);
+       return val;
+#endif
+}
+
index 5d7759b4751761daefcff49ad083143db720867f..179113cae94dda3701f26f69822cf6b67ac035ac 100644 (file)
@@ -1 +1,89 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "configreader.h"\r#include "dynamic.h"\r#ifndef WIN32\r#include <dlfcn.h>\r#endif\r\rDLLManager::DLLManager(InspIRCd* ServerInstance, const char *fname)\r{\r       err = NULL;\r\r   if (!strstr(fname,".so"))\r      {\r              err = "This doesn't look like a module file to me...";\r         return;\r        }\r\r     h = dlopen(fname, RTLD_NOW|RTLD_LOCAL);\r        if (!h)\r        {\r              err = (char*)dlerror();\r                return;\r        }\r}\r\rDLLManager::~DLLManager()\r{\r       // close the library if it isn't null\r  if (h)\r         dlclose(h);\r}\r\r\r\rbool DLLManager::GetSymbol(void** v, const char* sym_name)\r{\r  // try extract a symbol from the library\r       // get any error message is there is any\r       \r       if (h)\r {\r              dlerror(); // clear value\r              *v = dlsym(h, sym_name);\r               err = (char*)dlerror();\r                if (!*v || err)\r                        return false;\r  }\r      \r       if (err)\r       {\r              return false;\r  }\r      else\r   {       \r               return true;\r   }\r}\r\rDLLFactoryBase::DLLFactoryBase(InspIRCd* Instance, const char* fname, const char* symbol) : DLLManager(Instance, fname)\r{\r // try get the factory function if there is no error yet\r       factory_func = 0;\r      \r       if (!LastError())\r      {\r              if (!GetSymbol( (void **)&factory_func, symbol ? symbol : "init_module"))\r              {\r                      throw ModuleException("Missing init_module() entrypoint!");\r            }\r      }\r}\r\rDLLFactoryBase::~DLLFactoryBase()\r{\r}\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "configreader.h"
+#include "dynamic.h"
+#ifndef WIN32
+#include <dlfcn.h>
+#endif
+
+DLLManager::DLLManager(InspIRCd* ServerInstance, const char *fname)
+{
+       err = NULL;
+
+       if (!strstr(fname,".so"))
+       {
+               err = "This doesn't look like a module file to me...";
+               return;
+       }
+
+       h = dlopen(fname, RTLD_NOW|RTLD_LOCAL);
+       if (!h)
+       {
+               err = (char*)dlerror();
+               return;
+       }
+}
+
+DLLManager::~DLLManager()
+{
+       // close the library if it isn't null
+       if (h)
+               dlclose(h);
+}
+
+
+
+bool DLLManager::GetSymbol(void** v, const char* sym_name)
+{
+       // try extract a symbol from the library
+       // get any error message is there is any
+       
+       if (h)
+       {
+               dlerror(); // clear value
+               *v = dlsym(h, sym_name);
+               err = (char*)dlerror();
+               if (!*v || err)
+                       return false;
+       }
+       
+       if (err)
+       {
+               return false;
+       }
+       else
+       {       
+               return true;
+       }
+}
+
+DLLFactoryBase::DLLFactoryBase(InspIRCd* Instance, const char* fname, const char* symbol) : DLLManager(Instance, fname)
+{
+       // try get the factory function if there is no error yet
+       factory_func = 0;
+       
+       if (!LastError())
+       {
+               if (!GetSymbol( (void **)&factory_func, symbol ? symbol : "init_module"))
+               {
+                       throw ModuleException("Missing init_module() entrypoint!");
+               }
+       }
+}
+
+DLLFactoryBase::~DLLFactoryBase()
+{
+}
+
index e5a6acffee12f9a9c01a88bec8c79be65619b084..caf93ec1be9ebec29ca450d6476aeaeef93842da 100644 (file)
@@ -1 +1,619 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "hashcomp.h"\r#ifndef WIN32\r#include <ext/hash_map>\r#define nspace __gnu_cxx\r#else\r#include <hash_map>\r#define nspace stdext\rusing stdext::hash_map;\r#endif\r\r/******************************************************\r *\r * The hash functions of InspIRCd are the centrepoint\r * of the entire system. If these functions are\r * inefficient or wasteful, the whole program suffers\r * as a result. A lot of C programmers in the ircd\r * scene spend a lot of time debating (arguing) about\r * the best way to write hash functions to hash irc\r * nicknames, channels etc.\r * We are lucky as C++ developers as hash_map does\r * a lot of this for us. It does intellegent memory\r * requests, bucketing, search functions, insertion\r * and deletion etc. All we have to do is write some\r * overloaded comparison and hash value operators which\r * cause it to act in an irc-like way. The features we\r * add to the standard hash_map are:\r *\r * Case insensitivity: The hash_map will be case\r * insensitive.\r *\r * Scandanavian Comparisons: The characters [, ], \ will\r * be considered the lowercase of {, } and |.\r *\r ******************************************************/\r\rusing namespace irc::sockets;\r\r/* convert a string to lowercase. Note following special circumstances\r * taken from RFC 1459. Many "official" server branches still hold to this\r * rule so i will too;\r *\r *  Because of IRC's scandanavian origin, the characters {}| are\r *  considered to be the lower case equivalents of the characters []\,\r *  respectively. This is a critical issue when determining the\r *  equivalence of two nicknames.\r */\rvoid nspace::strlower(char *n)\r{\r       if (n)\r {\r              for (char* t = n; *t; t++)\r                     *t = lowermap[(unsigned char)*t];\r      }\r}\r\r#ifndef WIN32\rsize_t nspace::hash<string>::operator()(const string &s) const\r#else\rsize_t nspace::hash_compare<string, std::less<string> >::operator()(const string &s) const\r#endif\r{\r    /* XXX: NO DATA COPIES! :)\r      * The hash function here is practically\r        * a copy of the one in STL's hash_fun.h,\r       * only with *x replaced with lowermap[*x].\r     * This avoids a copy to use hash<const char*>\r  */\r    register size_t t = 0;\r for (std::string::const_iterator x = s.begin(); x != s.end(); ++x) /* ++x not x++, as its faster */\r            t = 5 * t + lowermap[(unsigned char)*x];\r       return t;\r}\r\r#ifndef WIN32\rsize_t nspace::hash<irc::string>::operator()(const irc::string &s) const\r#else\rsize_t nspace::hash_compare<irc::string, std::less<irc::string> >::operator()(const irc::string &s) const\r#endif\r{\r   register size_t t = 0;\r for (irc::string::const_iterator x = s.begin(); x != s.end(); ++x) /* ++x not x++, as its faster */\r            t = 5 * t + lowermap[(unsigned char)*x];\r       return t;\r}\r\rbool irc::StrHashComp::operator()(const std::string& s1, const std::string& s2) const\r{\r   unsigned char* n1 = (unsigned char*)s1.c_str();\r        unsigned char* n2 = (unsigned char*)s2.c_str();\r        for (; *n1 && *n2; n1++, n2++)\r         if (lowermap[*n1] != lowermap[*n2])\r                    return false;\r  return (lowermap[*n1] == lowermap[*n2]);\r}\r\r/******************************************************\r *\r * This is the implementation of our special irc::string\r * class which is a case-insensitive equivalent to\r * std::string which is not only case-insensitive but\r * can also do scandanavian comparisons, e.g. { = [, etc.\r *\r * This class depends on the const array 'lowermap'.\r *\r ******************************************************/\r\rbool irc::irc_char_traits::eq(char c1st, char c2nd)\r{\r  return lowermap[(unsigned char)c1st] == lowermap[(unsigned char)c2nd];\r}\r\rbool irc::irc_char_traits::ne(char c1st, char c2nd)\r{\r        return lowermap[(unsigned char)c1st] != lowermap[(unsigned char)c2nd];\r}\r\rbool irc::irc_char_traits::lt(char c1st, char c2nd)\r{\r        return lowermap[(unsigned char)c1st] < lowermap[(unsigned char)c2nd];\r}\r\rint irc::irc_char_traits::compare(const char* str1, const char* str2, size_t n)\r{\r     for(unsigned int i = 0; i < n; i++)\r    {\r              if(lowermap[(unsigned char)*str1] > lowermap[(unsigned char)*str2])\r                    return 1;\r\r             if(lowermap[(unsigned char)*str1] < lowermap[(unsigned char)*str2])\r                    return -1;\r\r            if(*str1 == 0 || *str2 == 0)\r                   return 0;\r\r             str1++;\r                str2++;\r        }\r      return 0;\r}\r\rconst char* irc::irc_char_traits::find(const char* s1, int  n, char c)\r{\r  while(n-- > 0 && lowermap[(unsigned char)*s1] != lowermap[(unsigned char)c])\r           s1++;\r  return s1;\r}\r\rirc::tokenstream::tokenstream(const std::string &source) : tokens(source), last_pushed(false)\r{\r  /* Record starting position and current position */\r    last_starting_position = tokens.begin();\r       n = tokens.begin();\r}\r\rirc::tokenstream::~tokenstream()\r{\r}\r\rbool irc::tokenstream::GetToken(std::string &token)\r{\r     std::string::iterator lsp = last_starting_position;\r\r   while (n != tokens.end())\r      {\r              /** Skip multi space, converting "  " into " "\r          */\r            while ((n+1 != tokens.end()) && (*n == ' ') && (*(n+1) == ' '))\r                        n++;\r\r          if ((last_pushed) && (*n == ':'))\r              {\r                      /* If we find a token thats not the first and starts with :,\r                    * this is the last token on the line\r                   */\r                    std::string::iterator curr = ++n;\r                      n = tokens.end();\r                      token = std::string(curr, tokens.end());\r                       return true;\r           }\r\r             last_pushed = false;\r\r          if ((*n == ' ') || (n+1 == tokens.end()))\r              {\r                      /* If we find a space, or end of string, this is the end of a token.\r                    */\r                    last_starting_position = n+1;\r                  last_pushed = true;\r\r                   std::string strip(lsp, n+1 == tokens.end() ? n+1  : n++);\r                      while ((strip.length()) && (strip.find_last_of(' ') == strip.length() - 1))\r                            strip.erase(strip.end() - 1);\r\r                 token = strip;\r                 return !token.empty();\r         }\r\r             n++;\r   }\r      token.clear();\r return false;\r}\r\rbool irc::tokenstream::GetToken(irc::string &token)\r{\r std::string stdstring;\r bool returnval = GetToken(stdstring);\r  token = assign(stdstring);\r     return returnval;\r}\r\rbool irc::tokenstream::GetToken(int &token)\r{\r     std::string tok;\r       bool returnval = GetToken(tok);\r        token = ConvToInt(tok);\r        return returnval;\r}\r\rbool irc::tokenstream::GetToken(long &token)\r{\r    std::string tok;\r       bool returnval = GetToken(tok);\r        token = ConvToInt(tok);\r        return returnval;\r}\r\rirc::sepstream::sepstream(const std::string &source, char seperator) : tokens(source), sep(seperator)\r{\r   last_starting_position = tokens.begin();\r       n = tokens.begin();\r}\r\rconst std::string irc::sepstream::GetToken()\r{\r  std::string::iterator lsp = last_starting_position;\r\r   while (n != tokens.end())\r      {\r              if ((*n == sep) || (n+1 == tokens.end()))\r              {\r                      last_starting_position = n+1;\r                  std::string strip = std::string(lsp, n+1 == tokens.end() ? n+1  : n++);\r\r                       while ((strip.length()) && (strip.find_last_of(sep) == strip.length() - 1))\r                            strip.erase(strip.end() - 1);\r\r                 return strip;\r          }\r\r             n++;\r   }\r\r     return "";\r}\r\rconst std::string irc::sepstream::GetRemaining()\r{\r       return std::string(n, tokens.end());\r}\r\rbool irc::sepstream::StreamEnd()\r{\r     return ((n + 1) == tokens.end());\r}\r\rirc::sepstream::~sepstream()\r{\r}\r\rstd::string irc::hex(const unsigned char *raw, size_t rawsz)\r{\r  if (!rawsz)\r            return "";\r\r    /* EWW! This used to be using sprintf, which is WAY inefficient. -Special */\r   \r       const char *hex = "0123456789abcdef";\r  static char hexbuf[MAXBUF];\r\r   size_t i, j;\r   for (i = 0, j = 0; j < rawsz; ++j)\r     {\r              hexbuf[i++] = hex[raw[j] / 16];\r                hexbuf[i++] = hex[raw[j] % 16];\r        }\r      hexbuf[i] = 0;\r\r        return hexbuf;\r}\r\rCoreExport const char* irc::Spacify(const char* n)\r{\r static char x[MAXBUF];\r strlcpy(x,n,MAXBUF);\r   for (char* y = x; *y; y++)\r             if (*y == '_')\r                 *y = ' ';\r      return x;\r}\r\r\rirc::modestacker::modestacker(bool add) : adding(add)\r{\r  sequence.clear();\r      sequence.push_back("");\r}\r\rvoid irc::modestacker::Push(char modeletter, const std::string &parameter)\r{\r        *(sequence.begin()) += modeletter;\r     sequence.push_back(parameter);\r}\r\rvoid irc::modestacker::Push(char modeletter)\r{\r       this->Push(modeletter,"");\r}\r\rvoid irc::modestacker::PushPlus()\r{\r      this->Push('+',"");\r}\r\rvoid irc::modestacker::PushMinus()\r{\r    this->Push('-',"");\r}\r\rint irc::modestacker::GetStackedLine(std::deque<std::string> &result, int max_line_size)\r{\r      if (sequence.empty())\r  {\r              result.clear();\r                return 0;\r      }\r\r     int n = 0;\r     int size = 1; /* Account for initial +/- char */\r       int nextsize = 0;\r      result.clear();\r        result.push_back(adding ? "+" : "-");\r\r if (sequence.size() > 1)\r               nextsize = sequence[1].length() + 2;\r\r  while (!sequence[0].empty() && (sequence.size() > 1) && (result.size() < MAXMODES) && ((size + nextsize) < max_line_size))\r     {\r              result[0] += *(sequence[0].begin());\r           if (!sequence[1].empty())\r              {\r                      result.push_back(sequence[1]);\r                 size += nextsize; /* Account for mode character and whitespace */\r              }\r              sequence[0].erase(sequence[0].begin());\r                sequence.erase(sequence.begin() + 1);\r\r         if (sequence.size() > 1)\r                       nextsize = sequence[1].length() + 2;\r\r          n++;\r   }\r\r     return n;\r}\r\rirc::stringjoiner::stringjoiner(const std::string &seperator, const std::vector<std::string> &sequence, int begin, int end)\r{\r     for (int v = begin; v < end; v++)\r              joined.append(sequence[v]).append(seperator);\r  joined.append(sequence[end]);\r}\r\rirc::stringjoiner::stringjoiner(const std::string &seperator, const std::deque<std::string> &sequence, int begin, int end)\r{\r  for (int v = begin; v < end; v++)\r              joined.append(sequence[v]).append(seperator);\r  joined.append(sequence[end]);\r}\r\rirc::stringjoiner::stringjoiner(const std::string &seperator, const char** sequence, int begin, int end)\r{\r    for (int v = begin; v < end; v++)\r              joined.append(sequence[v]).append(seperator);\r  joined.append(sequence[end]);\r}\r\rstd::string& irc::stringjoiner::GetJoined()\r{\r return joined;\r}\r\rirc::portparser::portparser(const std::string &source, bool allow_overlapped) : in_range(0), range_begin(0), range_end(0), overlapped(allow_overlapped)\r{\r    sep = new irc::commasepstream(source);\r overlap_set.clear();\r}\r\rirc::portparser::~portparser()\r{\r       delete sep;\r}\r\rbool irc::portparser::Overlaps(long val)\r{\r      if (!overlapped)\r               return false;\r\r if (overlap_set.find(val) == overlap_set.end())\r        {\r              overlap_set[val] = true;\r               return false;\r  }\r      else\r           return true;\r}\r\rlong irc::portparser::GetToken()\r{\r     if (in_range > 0)\r      {\r              in_range++;\r            if (in_range <= range_end)\r             {\r                      if (!Overlaps(in_range))\r                       {\r                              return in_range;\r                       }\r                      else\r                   {\r                              while (((Overlaps(in_range)) && (in_range <= range_end)))\r                                      in_range++;\r                            \r                               if (in_range <= range_end)\r                                     return in_range;\r                       }\r              }\r              else\r                   in_range = 0;\r  }\r\r     std::string x = sep->GetToken();\r\r      if (x.empty())\r         return 0;\r\r     while (Overlaps(atoi(x.c_str())))\r      {\r              x = sep->GetToken();\r\r          if (x.empty())\r                 return 0;\r      }\r\r     std::string::size_type dash = x.rfind('-');\r    if (dash != std::string::npos)\r {\r              std::string sbegin = x.substr(0, dash);\r                std::string send = x.substr(dash+1, x.length());\r               range_begin = atoi(sbegin.c_str());\r            range_end = atoi(send.c_str());\r\r               if ((range_begin > 0) && (range_end > 0) && (range_begin < 65536) && (range_end < 65536) && (range_begin < range_end))\r         {\r                      in_range = range_begin;\r                        return in_range;\r               }\r              else\r           {\r                      /* Assume its just the one port */\r                     return atoi(sbegin.c_str());\r           }\r      }\r      else\r   {\r              return atoi(x.c_str());\r        }\r}\r\rirc::dynamicbitmask::dynamicbitmask() : bits_size(4)\r{\r    /* We start with 4 bytes allocated which is room\r        * for 4 items. Something makes me doubt its worth\r      * allocating less than 4 bytes.\r        */\r    bits = new unsigned char[bits_size];\r   memset(bits, 0, bits_size);\r}\r\rirc::dynamicbitmask::~dynamicbitmask()\r{\r        /* Tidy up the entire used memory on delete */\r delete[] bits;\r}\r\rirc::bitfield irc::dynamicbitmask::Allocate()\r{\r      /* Yeah, this isnt too efficient, however a module or the core\r  * should only be allocating bitfields on load, the Toggle and\r  * Get methods are O(1) as these are called much more often.\r    */\r    unsigned char* freebits = this->GetFreeBits();\r for (unsigned char i = 0; i < bits_size; i++)\r  {\r              /* Yes, this is right. You'll notice we terminate the  loop when !current_pos,\r          * this is because we logic shift our bit off the end of unsigned char, and its\r                 * lost, making the loop counter 0 when we're done.\r             */\r            for (unsigned char current_pos = 1; current_pos; current_pos = current_pos << 1)\r               {\r                      if (!(freebits[i] & current_pos))\r                      {\r                              freebits[i] |= current_pos;\r                            return std::make_pair(i, current_pos);\r                 }\r              }\r      }\r      /* We dont have any free space left, increase by one */\r\r       if (bits_size == 255)\r          /* Oh dear, cant grow it any further */\r                throw std::bad_alloc();\r\r       unsigned char old_bits_size = bits_size;\r       bits_size++;\r   /* Allocate new bitfield space */\r      unsigned char* temp_bits = new unsigned char[bits_size];\r       unsigned char* temp_freebits = new unsigned char[bits_size];\r   /* Copy the old data in */\r     memcpy(temp_bits, bits, old_bits_size);\r        memcpy(temp_freebits, freebits, old_bits_size);\r        /* Delete the old data pointers */\r     delete[] bits;\r delete[] freebits;\r     /* Swap the pointers over so now the new \r       * pointers point to our member values\r  */\r    bits = temp_bits;\r      freebits = temp_freebits;\r      this->SetFreeBits(freebits);\r   /* Initialize the new byte on the end of\r        * the bitfields, pre-allocate the one bit\r      * for this allocation\r  */\r    bits[old_bits_size] = 0;\r       freebits[old_bits_size] = 1;\r   /* We already know where we just allocated\r      * the bitfield, so no loop needed\r      */\r    return std::make_pair(old_bits_size, 1);\r}\r\rbool irc::dynamicbitmask::Deallocate(irc::bitfield &pos)\r{\r /* We dont bother to shrink the bitfield\r        * on deallocation, the most we could do\r        * is save one byte (!) and this would cost\r     * us a loop (ugly O(n) stuff) so we just\r       * clear the bit and leave the memory\r   * claimed -- nobody will care about one\r        * byte.\r        */\r    if (pos.first < bits_size)\r     {\r              this->GetFreeBits()[pos.first] &= ~pos.second;\r         return true;\r   }\r      /* They gave a bitfield outside of the\r  * length of our array. BAD programmer.\r         */\r    return false;\r}\r\rvoid irc::dynamicbitmask::Toggle(irc::bitfield &pos, bool state)\r{\r    /* Range check the value */\r    if (pos.first < bits_size)\r     {\r              if (state)\r                     /* Set state, OR the state in */\r                       bits[pos.first] |= pos.second;\r         else\r                   /* Clear state, AND the !state out */\r                  bits[pos.first] &= ~pos.second;\r        }\r}\r\rbool irc::dynamicbitmask::Get(irc::bitfield &pos)\r{\r       /* Range check the value */\r    if (pos.first < bits_size)\r             return (bits[pos.first] & pos.second);\r else\r           /* We can't return false, otherwise we can't\r            * distinguish between failure and a cleared bit!\r               * Our only sensible choice is to throw (ew).\r           */\r            throw ModuleException("irc::dynamicbitmask::Get(): Invalid bitfield, out of range");\r}\r\runsigned char irc::dynamicbitmask::GetSize()\r{\r return bits_size;\r}\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "hashcomp.h"
+#ifndef WIN32
+#include <ext/hash_map>
+#define nspace __gnu_cxx
+#else
+#include <hash_map>
+#define nspace stdext
+using stdext::hash_map;
+#endif
+
+/******************************************************
+ *
+ * The hash functions of InspIRCd are the centrepoint
+ * of the entire system. If these functions are
+ * inefficient or wasteful, the whole program suffers
+ * as a result. A lot of C programmers in the ircd
+ * scene spend a lot of time debating (arguing) about
+ * the best way to write hash functions to hash irc
+ * nicknames, channels etc.
+ * We are lucky as C++ developers as hash_map does
+ * a lot of this for us. It does intellegent memory
+ * requests, bucketing, search functions, insertion
+ * and deletion etc. All we have to do is write some
+ * overloaded comparison and hash value operators which
+ * cause it to act in an irc-like way. The features we
+ * add to the standard hash_map are:
+ *
+ * Case insensitivity: The hash_map will be case
+ * insensitive.
+ *
+ * Scandanavian Comparisons: The characters [, ], \ will
+ * be considered the lowercase of {, } and |.
+ *
+ ******************************************************/
+
+using namespace irc::sockets;
+
+/* convert a string to lowercase. Note following special circumstances
+ * taken from RFC 1459. Many "official" server branches still hold to this
+ * rule so i will too;
+ *
+ *  Because of IRC's scandanavian origin, the characters {}| are
+ *  considered to be the lower case equivalents of the characters []\,
+ *  respectively. This is a critical issue when determining the
+ *  equivalence of two nicknames.
+ */
+void nspace::strlower(char *n)
+{
+       if (n)
+       {
+               for (char* t = n; *t; t++)
+                       *t = lowermap[(unsigned char)*t];
+       }
+}
+
+#ifndef WIN32
+size_t nspace::hash<string>::operator()(const string &s) const
+#else
+size_t nspace::hash_compare<string, std::less<string> >::operator()(const string &s) const
+#endif
+{
+       /* XXX: NO DATA COPIES! :)
+        * The hash function here is practically
+        * a copy of the one in STL's hash_fun.h,
+        * only with *x replaced with lowermap[*x].
+        * This avoids a copy to use hash<const char*>
+        */
+       register size_t t = 0;
+       for (std::string::const_iterator x = s.begin(); x != s.end(); ++x) /* ++x not x++, as its faster */
+               t = 5 * t + lowermap[(unsigned char)*x];
+       return t;
+}
+
+#ifndef WIN32
+size_t nspace::hash<irc::string>::operator()(const irc::string &s) const
+#else
+size_t nspace::hash_compare<irc::string, std::less<irc::string> >::operator()(const irc::string &s) const
+#endif
+{
+       register size_t t = 0;
+       for (irc::string::const_iterator x = s.begin(); x != s.end(); ++x) /* ++x not x++, as its faster */
+               t = 5 * t + lowermap[(unsigned char)*x];
+       return t;
+}
+
+bool irc::StrHashComp::operator()(const std::string& s1, const std::string& s2) const
+{
+       unsigned char* n1 = (unsigned char*)s1.c_str();
+       unsigned char* n2 = (unsigned char*)s2.c_str();
+       for (; *n1 && *n2; n1++, n2++)
+               if (lowermap[*n1] != lowermap[*n2])
+                       return false;
+       return (lowermap[*n1] == lowermap[*n2]);
+}
+
+/******************************************************
+ *
+ * This is the implementation of our special irc::string
+ * class which is a case-insensitive equivalent to
+ * std::string which is not only case-insensitive but
+ * can also do scandanavian comparisons, e.g. { = [, etc.
+ *
+ * This class depends on the const array 'lowermap'.
+ *
+ ******************************************************/
+
+bool irc::irc_char_traits::eq(char c1st, char c2nd)
+{
+       return lowermap[(unsigned char)c1st] == lowermap[(unsigned char)c2nd];
+}
+
+bool irc::irc_char_traits::ne(char c1st, char c2nd)
+{
+       return lowermap[(unsigned char)c1st] != lowermap[(unsigned char)c2nd];
+}
+
+bool irc::irc_char_traits::lt(char c1st, char c2nd)
+{
+       return lowermap[(unsigned char)c1st] < lowermap[(unsigned char)c2nd];
+}
+
+int irc::irc_char_traits::compare(const char* str1, const char* str2, size_t n)
+{
+       for(unsigned int i = 0; i < n; i++)
+       {
+               if(lowermap[(unsigned char)*str1] > lowermap[(unsigned char)*str2])
+                       return 1;
+
+               if(lowermap[(unsigned char)*str1] < lowermap[(unsigned char)*str2])
+                       return -1;
+
+               if(*str1 == 0 || *str2 == 0)
+                       return 0;
+
+               str1++;
+               str2++;
+       }
+       return 0;
+}
+
+const char* irc::irc_char_traits::find(const char* s1, int  n, char c)
+{
+       while(n-- > 0 && lowermap[(unsigned char)*s1] != lowermap[(unsigned char)c])
+               s1++;
+       return s1;
+}
+
+irc::tokenstream::tokenstream(const std::string &source) : tokens(source), last_pushed(false)
+{
+       /* Record starting position and current position */
+       last_starting_position = tokens.begin();
+       n = tokens.begin();
+}
+
+irc::tokenstream::~tokenstream()
+{
+}
+
+bool irc::tokenstream::GetToken(std::string &token)
+{
+       std::string::iterator lsp = last_starting_position;
+
+       while (n != tokens.end())
+       {
+               /** Skip multi space, converting "  " into " "
+                */
+               while ((n+1 != tokens.end()) && (*n == ' ') && (*(n+1) == ' '))
+                       n++;
+
+               if ((last_pushed) && (*n == ':'))
+               {
+                       /* If we find a token thats not the first and starts with :,
+                        * this is the last token on the line
+                        */
+                       std::string::iterator curr = ++n;
+                       n = tokens.end();
+                       token = std::string(curr, tokens.end());
+                       return true;
+               }
+
+               last_pushed = false;
+
+               if ((*n == ' ') || (n+1 == tokens.end()))
+               {
+                       /* If we find a space, or end of string, this is the end of a token.
+                        */
+                       last_starting_position = n+1;
+                       last_pushed = true;
+
+                       std::string strip(lsp, n+1 == tokens.end() ? n+1  : n++);
+                       while ((strip.length()) && (strip.find_last_of(' ') == strip.length() - 1))
+                               strip.erase(strip.end() - 1);
+
+                       token = strip;
+                       return !token.empty();
+               }
+
+               n++;
+       }
+       token.clear();
+       return false;
+}
+
+bool irc::tokenstream::GetToken(irc::string &token)
+{
+       std::string stdstring;
+       bool returnval = GetToken(stdstring);
+       token = assign(stdstring);
+       return returnval;
+}
+
+bool irc::tokenstream::GetToken(int &token)
+{
+       std::string tok;
+       bool returnval = GetToken(tok);
+       token = ConvToInt(tok);
+       return returnval;
+}
+
+bool irc::tokenstream::GetToken(long &token)
+{
+       std::string tok;
+       bool returnval = GetToken(tok);
+       token = ConvToInt(tok);
+       return returnval;
+}
+
+irc::sepstream::sepstream(const std::string &source, char seperator) : tokens(source), sep(seperator)
+{
+       last_starting_position = tokens.begin();
+       n = tokens.begin();
+}
+
+const std::string irc::sepstream::GetToken()
+{
+       std::string::iterator lsp = last_starting_position;
+
+       while (n != tokens.end())
+       {
+               if ((*n == sep) || (n+1 == tokens.end()))
+               {
+                       last_starting_position = n+1;
+                       std::string strip = std::string(lsp, n+1 == tokens.end() ? n+1  : n++);
+
+                       while ((strip.length()) && (strip.find_last_of(sep) == strip.length() - 1))
+                               strip.erase(strip.end() - 1);
+
+                       return strip;
+               }
+
+               n++;
+       }
+
+       return "";
+}
+
+const std::string irc::sepstream::GetRemaining()
+{
+       return std::string(n, tokens.end());
+}
+
+bool irc::sepstream::StreamEnd()
+{
+       return ((n + 1) == tokens.end());
+}
+
+irc::sepstream::~sepstream()
+{
+}
+
+std::string irc::hex(const unsigned char *raw, size_t rawsz)
+{
+       if (!rawsz)
+               return "";
+
+       /* EWW! This used to be using sprintf, which is WAY inefficient. -Special */
+       
+       const char *hex = "0123456789abcdef";
+       static char hexbuf[MAXBUF];
+
+       size_t i, j;
+       for (i = 0, j = 0; j < rawsz; ++j)
+       {
+               hexbuf[i++] = hex[raw[j] / 16];
+               hexbuf[i++] = hex[raw[j] % 16];
+       }
+       hexbuf[i] = 0;
+
+       return hexbuf;
+}
+
+CoreExport const char* irc::Spacify(const char* n)
+{
+       static char x[MAXBUF];
+       strlcpy(x,n,MAXBUF);
+       for (char* y = x; *y; y++)
+               if (*y == '_')
+                       *y = ' ';
+       return x;
+}
+
+
+irc::modestacker::modestacker(bool add) : adding(add)
+{
+       sequence.clear();
+       sequence.push_back("");
+}
+
+void irc::modestacker::Push(char modeletter, const std::string &parameter)
+{
+       *(sequence.begin()) += modeletter;
+       sequence.push_back(parameter);
+}
+
+void irc::modestacker::Push(char modeletter)
+{
+       this->Push(modeletter,"");
+}
+
+void irc::modestacker::PushPlus()
+{
+       this->Push('+',"");
+}
+
+void irc::modestacker::PushMinus()
+{
+       this->Push('-',"");
+}
+
+int irc::modestacker::GetStackedLine(std::deque<std::string> &result, int max_line_size)
+{
+       if (sequence.empty())
+       {
+               result.clear();
+               return 0;
+       }
+
+       int n = 0;
+       int size = 1; /* Account for initial +/- char */
+       int nextsize = 0;
+       result.clear();
+       result.push_back(adding ? "+" : "-");
+
+       if (sequence.size() > 1)
+               nextsize = sequence[1].length() + 2;
+
+       while (!sequence[0].empty() && (sequence.size() > 1) && (result.size() < MAXMODES) && ((size + nextsize) < max_line_size))
+       {
+               result[0] += *(sequence[0].begin());
+               if (!sequence[1].empty())
+               {
+                       result.push_back(sequence[1]);
+                       size += nextsize; /* Account for mode character and whitespace */
+               }
+               sequence[0].erase(sequence[0].begin());
+               sequence.erase(sequence.begin() + 1);
+
+               if (sequence.size() > 1)
+                       nextsize = sequence[1].length() + 2;
+
+               n++;
+       }
+
+       return n;
+}
+
+irc::stringjoiner::stringjoiner(const std::string &seperator, const std::vector<std::string> &sequence, int begin, int end)
+{
+       for (int v = begin; v < end; v++)
+               joined.append(sequence[v]).append(seperator);
+       joined.append(sequence[end]);
+}
+
+irc::stringjoiner::stringjoiner(const std::string &seperator, const std::deque<std::string> &sequence, int begin, int end)
+{
+       for (int v = begin; v < end; v++)
+               joined.append(sequence[v]).append(seperator);
+       joined.append(sequence[end]);
+}
+
+irc::stringjoiner::stringjoiner(const std::string &seperator, const char** sequence, int begin, int end)
+{
+       for (int v = begin; v < end; v++)
+               joined.append(sequence[v]).append(seperator);
+       joined.append(sequence[end]);
+}
+
+std::string& irc::stringjoiner::GetJoined()
+{
+       return joined;
+}
+
+irc::portparser::portparser(const std::string &source, bool allow_overlapped) : in_range(0), range_begin(0), range_end(0), overlapped(allow_overlapped)
+{
+       sep = new irc::commasepstream(source);
+       overlap_set.clear();
+}
+
+irc::portparser::~portparser()
+{
+       delete sep;
+}
+
+bool irc::portparser::Overlaps(long val)
+{
+       if (!overlapped)
+               return false;
+
+       if (overlap_set.find(val) == overlap_set.end())
+       {
+               overlap_set[val] = true;
+               return false;
+       }
+       else
+               return true;
+}
+
+long irc::portparser::GetToken()
+{
+       if (in_range > 0)
+       {
+               in_range++;
+               if (in_range <= range_end)
+               {
+                       if (!Overlaps(in_range))
+                       {
+                               return in_range;
+                       }
+                       else
+                       {
+                               while (((Overlaps(in_range)) && (in_range <= range_end)))
+                                       in_range++;
+                               
+                               if (in_range <= range_end)
+                                       return in_range;
+                       }
+               }
+               else
+                       in_range = 0;
+       }
+
+       std::string x = sep->GetToken();
+
+       if (x.empty())
+               return 0;
+
+       while (Overlaps(atoi(x.c_str())))
+       {
+               x = sep->GetToken();
+
+               if (x.empty())
+                       return 0;
+       }
+
+       std::string::size_type dash = x.rfind('-');
+       if (dash != std::string::npos)
+       {
+               std::string sbegin = x.substr(0, dash);
+               std::string send = x.substr(dash+1, x.length());
+               range_begin = atoi(sbegin.c_str());
+               range_end = atoi(send.c_str());
+
+               if ((range_begin > 0) && (range_end > 0) && (range_begin < 65536) && (range_end < 65536) && (range_begin < range_end))
+               {
+                       in_range = range_begin;
+                       return in_range;
+               }
+               else
+               {
+                       /* Assume its just the one port */
+                       return atoi(sbegin.c_str());
+               }
+       }
+       else
+       {
+               return atoi(x.c_str());
+       }
+}
+
+irc::dynamicbitmask::dynamicbitmask() : bits_size(4)
+{
+       /* We start with 4 bytes allocated which is room
+        * for 4 items. Something makes me doubt its worth
+        * allocating less than 4 bytes.
+        */
+       bits = new unsigned char[bits_size];
+       memset(bits, 0, bits_size);
+}
+
+irc::dynamicbitmask::~dynamicbitmask()
+{
+       /* Tidy up the entire used memory on delete */
+       delete[] bits;
+}
+
+irc::bitfield irc::dynamicbitmask::Allocate()
+{
+       /* Yeah, this isnt too efficient, however a module or the core
+        * should only be allocating bitfields on load, the Toggle and
+        * Get methods are O(1) as these are called much more often.
+        */
+       unsigned char* freebits = this->GetFreeBits();
+       for (unsigned char i = 0; i < bits_size; i++)
+       {
+               /* Yes, this is right. You'll notice we terminate the  loop when !current_pos,
+                * this is because we logic shift our bit off the end of unsigned char, and its
+                * lost, making the loop counter 0 when we're done.
+                */
+               for (unsigned char current_pos = 1; current_pos; current_pos = current_pos << 1)
+               {
+                       if (!(freebits[i] & current_pos))
+                       {
+                               freebits[i] |= current_pos;
+                               return std::make_pair(i, current_pos);
+                       }
+               }
+       }
+       /* We dont have any free space left, increase by one */
+
+       if (bits_size == 255)
+               /* Oh dear, cant grow it any further */
+               throw std::bad_alloc();
+
+       unsigned char old_bits_size = bits_size;
+       bits_size++;
+       /* Allocate new bitfield space */
+       unsigned char* temp_bits = new unsigned char[bits_size];
+       unsigned char* temp_freebits = new unsigned char[bits_size];
+       /* Copy the old data in */
+       memcpy(temp_bits, bits, old_bits_size);
+       memcpy(temp_freebits, freebits, old_bits_size);
+       /* Delete the old data pointers */
+       delete[] bits;
+       delete[] freebits;
+       /* Swap the pointers over so now the new 
+        * pointers point to our member values
+        */
+       bits = temp_bits;
+       freebits = temp_freebits;
+       this->SetFreeBits(freebits);
+       /* Initialize the new byte on the end of
+        * the bitfields, pre-allocate the one bit
+        * for this allocation
+        */
+       bits[old_bits_size] = 0;
+       freebits[old_bits_size] = 1;
+       /* We already know where we just allocated
+        * the bitfield, so no loop needed
+        */
+       return std::make_pair(old_bits_size, 1);
+}
+
+bool irc::dynamicbitmask::Deallocate(irc::bitfield &pos)
+{
+       /* We dont bother to shrink the bitfield
+        * on deallocation, the most we could do
+        * is save one byte (!) and this would cost
+        * us a loop (ugly O(n) stuff) so we just
+        * clear the bit and leave the memory
+        * claimed -- nobody will care about one
+        * byte.
+        */
+       if (pos.first < bits_size)
+       {
+               this->GetFreeBits()[pos.first] &= ~pos.second;
+               return true;
+       }
+       /* They gave a bitfield outside of the
+        * length of our array. BAD programmer.
+        */
+       return false;
+}
+
+void irc::dynamicbitmask::Toggle(irc::bitfield &pos, bool state)
+{
+       /* Range check the value */
+       if (pos.first < bits_size)
+       {
+               if (state)
+                       /* Set state, OR the state in */
+                       bits[pos.first] |= pos.second;
+               else
+                       /* Clear state, AND the !state out */
+                       bits[pos.first] &= ~pos.second;
+       }
+}
+
+bool irc::dynamicbitmask::Get(irc::bitfield &pos)
+{
+       /* Range check the value */
+       if (pos.first < bits_size)
+               return (bits[pos.first] & pos.second);
+       else
+               /* We can't return false, otherwise we can't
+                * distinguish between failure and a cleared bit!
+                * Our only sensible choice is to throw (ew).
+                */
+               throw ModuleException("irc::dynamicbitmask::Get(): Invalid bitfield, out of range");
+}
+
+unsigned char irc::dynamicbitmask::GetSize()
+{
+       return bits_size;
+}
+
index b5d8f5630260200df40ab5695de3c6a7f010471a..da3fa5e1bc38f184e465e80cc893b907fa73000b 100644 (file)
@@ -1 +1,534 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include <stdarg.h>\r#include "configreader.h"\r#include "users.h"\r#include "modules.h"\r#include "wildcard.h"\r#include "mode.h"\r#include "xline.h"\r#include "exitcodes.h"\r\rstatic char TIMESTR[26];\rstatic time_t LAST = 0;\r\r/** Log()\r *  Write a line of text `text' to the logfile (and stdout, if in nofork) if the level `level'\r *  is greater than the configured loglevel.\r */\rvoid InspIRCd::Log(int level, const char* text, ...)\r{\r /* Do this check again here so that we save pointless vsnprintf calls */\r       if ((level < Config->LogLevel) && !Config->forcedebug)\r         return;\r\r       va_list argsPtr;\r       char textbuffer[65536];\r\r       va_start(argsPtr, text);\r       vsnprintf(textbuffer, 65536, text, argsPtr);\r   va_end(argsPtr);\r\r      this->Log(level, std::string(textbuffer));\r}\r\rvoid InspIRCd::Log(int level, const std::string &text)\r{\r if (!this->Config)\r             return;\r\r       /* If we were given -debug we output all messages, regardless of configured loglevel */\r        if ((level < Config->LogLevel) && !Config->forcedebug)\r         return;\r\r       if (Time() != LAST)\r    {\r              time_t local = Time();\r         struct tm *timeinfo = localtime(&local);\r\r              strlcpy(TIMESTR,asctime(timeinfo),26);\r         TIMESTR[24] = ':';\r             LAST = Time();\r }\r\r     if (Config->log_file && Config->writelog)\r      {\r              std::string out = std::string(TIMESTR) + " " + text.c_str() + "\n";\r            this->Logger->WriteLogLine(out);\r       }\r\r     if (Config->nofork)\r    {\r              printf("%s %s\n", TIMESTR, text.c_str());\r      }\r}\r\rstd::string InspIRCd::GetServerDescription(const char* servername)\r{\r      std::string description;\r\r      FOREACH_MOD_I(this,I_OnGetServerDescription,OnGetServerDescription(servername,description));\r\r  if (!description.empty())\r      {\r              return description;\r    }\r      else\r   {\r              // not a remote server that can be found, it must be me.\r               return Config->ServerDesc;\r     }\r}\r\r/* XXX - We don't use WriteMode for this because WriteMode is very slow and\r * this isnt. Basically WriteMode has to iterate ALL the users 'n' times for\r * the number of modes provided, e.g. if you send WriteMode 'og' to write to\r * opers with globops, and you have 2000 users, thats 4000 iterations. WriteOpers\r * uses the oper list, which means if you have 2000 users but only 5 opers,\r * it iterates 5 times.\r */\rvoid InspIRCd::WriteOpers(const char* text, ...)\r{\r        char textbuffer[MAXBUF];\r       va_list argsPtr;\r\r      va_start(argsPtr, text);\r       vsnprintf(textbuffer, MAXBUF, text, argsPtr);\r  va_end(argsPtr);\r\r      this->WriteOpers(std::string(textbuffer));\r}\r\rvoid InspIRCd::WriteOpers(const std::string &text)\r{\r     for (std::vector<userrec*>::iterator i = this->all_opers.begin(); i != this->all_opers.end(); i++)\r     {\r              userrec* a = *i;\r               if (IS_LOCAL(a) && a->modes[UM_SERVERNOTICE])\r          {\r                      // send server notices to all with +s\r                  a->WriteServ("NOTICE %s :%s",a->nick,text.c_str());\r            }\r      }\r}\r\rvoid InspIRCd::ServerNoticeAll(char* text, ...)\r{\r if (!text)\r             return;\r\r       char textbuffer[MAXBUF];\r       char formatbuffer[MAXBUF];\r     va_list argsPtr;\r       va_start (argsPtr, text);\r      vsnprintf(textbuffer, MAXBUF, text, argsPtr);\r  va_end(argsPtr);\r\r      snprintf(formatbuffer,MAXBUF,"NOTICE $%s :%s",Config->ServerName,textbuffer);\r\r for (std::vector<userrec*>::const_iterator i = local_users.begin(); i != local_users.end(); i++)\r       {\r              userrec* t = *i;\r               t->WriteServ(std::string(formatbuffer));\r       }\r}\r\rvoid InspIRCd::ServerPrivmsgAll(char* text, ...)\r{\r        if (!text)\r             return;\r\r       char textbuffer[MAXBUF];\r       char formatbuffer[MAXBUF];\r     va_list argsPtr;\r       va_start (argsPtr, text);\r      vsnprintf(textbuffer, MAXBUF, text, argsPtr);\r  va_end(argsPtr);\r\r      snprintf(formatbuffer,MAXBUF,"PRIVMSG $%s :%s",Config->ServerName,textbuffer);\r\r        for (std::vector<userrec*>::const_iterator i = local_users.begin(); i != local_users.end(); i++)\r       {\r              userrec* t = *i;\r               t->WriteServ(std::string(formatbuffer));\r       }\r}\r\rvoid InspIRCd::WriteMode(const char* modes, int flags, const char* text, ...)\r{\r   char textbuffer[MAXBUF];\r       int modelen;\r   va_list argsPtr;\r\r      if (!text || !modes || !flags)\r {\r              this->Log(DEFAULT,"*** BUG *** WriteMode was given an invalid parameter");\r             return;\r        }\r\r     va_start(argsPtr, text);\r       vsnprintf(textbuffer, MAXBUF, text, argsPtr);\r  va_end(argsPtr);\r       modelen = strlen(modes);\r\r      if (flags == WM_AND)\r   {\r              for (std::vector<userrec*>::const_iterator i = local_users.begin(); i != local_users.end(); i++)\r               {\r                      userrec* t = *i;\r                       bool send_to_user = true;\r\r                     for (int n = 0; n < modelen; n++)\r                      {\r                              if (!t->modes[modes[n]-65])\r                            {\r                                      send_to_user = false;\r                                  break;\r                         }\r                      }\r                      if (send_to_user)\r                              t->WriteServ("NOTICE %s :%s",t->nick,textbuffer);\r              }\r      }\r      else\r   if (flags == WM_OR)\r    {\r              for (std::vector<userrec*>::const_iterator i = local_users.begin(); i != local_users.end(); i++)\r               {\r                      userrec* t = *i;\r                       bool send_to_user = false;\r\r                    for (int n = 0; n < modelen; n++)\r                      {\r                              if (t->modes[modes[n]-65])\r                             {\r                                      send_to_user = true;\r                                   break;\r                         }\r                      }\r                      if (send_to_user)\r                              t->WriteServ("NOTICE %s :%s",t->nick,textbuffer);\r              }\r      }\r}\r\r/* Find a user record by nickname and return a pointer to it */\r\ruserrec* InspIRCd::FindNick(const std::string &nick)\r{\r   user_hash::iterator iter = clientlist->find(nick);\r\r    if (iter == clientlist->end())\r         /* Couldn't find it */\r         return NULL;\r\r  return iter->second;\r}\r\ruserrec* InspIRCd::FindNick(const char* nick)\r{\r        user_hash::iterator iter = clientlist->find(nick);\r     \r       if (iter == clientlist->end())\r         return NULL;\r\r  return iter->second;\r}\r\r/* find a channel record by channel name and return a pointer to it */\r\rchanrec* InspIRCd::FindChan(const char* chan)\r{\r        chan_hash::iterator iter = chanlist->find(chan);\r\r      if (iter == chanlist->end())\r           /* Couldn't find it */\r         return NULL;\r\r  return iter->second;\r}\r\rchanrec* InspIRCd::FindChan(const std::string &chan)\r{\r chan_hash::iterator iter = chanlist->find(chan);\r\r      if (iter == chanlist->end())\r           /* Couldn't find it */\r         return NULL;\r\r  return iter->second;\r}\r\r/*\r * sends out an error notice to all connected clients (not to be used\r * lightly!)\r */\rvoid InspIRCd::SendError(const std::string &s)\r{\r     for (std::vector<userrec*>::const_iterator i = this->local_users.begin(); i != this->local_users.end(); i++)\r   {\r              if ((*i)->registered == REG_ALL)\r               {\r                      (*i)->WriteServ("NOTICE %s :%s",(*i)->nick,s.c_str());\r         }\r              else\r           {\r                      /* Unregistered connections receive ERROR, not a NOTICE */\r                     (*i)->Write("ERROR :" + s);\r            }\r              /* This might generate a whole load of EAGAIN, but we dont really\r               * care about this, as if we call SendError something catastrophic\r              * has occured anyway, and we wont receive the events for these.\r                */\r            (*i)->FlushWriteBuf();\r }\r}\r\r// this function counts all users connected, wether they are registered or NOT.\rint InspIRCd::UserCount()\r{\r       return clientlist->size();\r}\r\r// this counts only registered users, so that the percentages in /MAP don't mess up when users are sitting in an unregistered state\rint InspIRCd::RegisteredUserCount()\r{\r        return clientlist->size() - this->UnregisteredUserCount();\r}\r\rint InspIRCd::ModeCount(const char mode)\r{\r       ModeHandler* mh = this->Modes->FindMode(mode, MODETYPE_USER);\r\r if (mh)\r                return mh->GetCount();\r else\r           return 0;\r}\r\rint InspIRCd::InvisibleUserCount()\r{\r      return ModeCount('i');\r}\r\rint InspIRCd::OperCount()\r{\r  return this->all_opers.size();\r}\r\rint InspIRCd::UnregisteredUserCount()\r{\r      return this->unregistered_count;\r}\r\rlong InspIRCd::ChannelCount()\r{\r    return chanlist->size();\r}\r\rlong InspIRCd::LocalUserCount()\r{\r  /* Doesnt count unregistered clients */\r        return (local_users.size() - this->UnregisteredUserCount());\r}\r \rbool InspIRCd::IsChannel(const char *chname)\r{\r        char *c;\r\r      /* check for no name - don't check for !*chname, as if it is empty, it won't be '#'! */\r        if (!chname || *chname != '#')\r {\r              return false;\r  }\r\r     c = (char *)chname + 1;\r        while (*c)\r     {\r              switch (*c)\r            {\r                      case ' ':\r                      case ',':\r                      case 7:\r                                return false;\r          }\r\r             c++;\r   }\r              \r       /* too long a name - note funky pointer arithmetic here. */\r    if ((c - chname) > CHANMAX)\r    {\r                      return false;\r  }\r\r     return true;\r}\r\rbool InspIRCd::IsNick(const char* n)\r{\r if (!n || !*n)\r         return false;\r \r        int p = 0;\r     for (char* i = (char*)n; *i; i++, p++)\r {\r              if ((*i >= 'A') && (*i <= '}'))\r                {\r                      /* "A"-"}" can occur anywhere in a nickname */\r                 continue;\r              }\r\r             if ((((*i >= '0') && (*i <= '9')) || (*i == '-')) && (i > n))\r          {\r                      /* "0"-"9", "-" can occur anywhere BUT the first char of a nickname */\r                 continue;\r              }\r\r             /* invalid character! abort */\r         return false;\r  }\r\r     /* too long? or not -- pointer arithmetic rocks */\r     return (p < NICKMAX - 1);\r}\r\r\rbool InspIRCd::IsIdent(const char* n)\r{\r  if (!n || !*n)\r         return false;\r\r for (char* i = (char*)n; *i; i++)\r      {\r              if ((*i >= 'A') && (*i <= '}'))\r                {\r                      continue;\r              }\r\r             if (((*i >= '0') && (*i <= '9')) || (*i == '-') || (*i == '.'))\r                {\r                      continue;\r              }\r\r             return false;\r  }\r\r     return true;\r}\r\rvoid InspIRCd::OpenLog(char** argv, int argc)\r{\r        Config->MyDir = Config->GetFullProgDir();\r\r     if (!*this->LogFileName)\r       {\r              if (Config->logpath.empty())\r           {\r#ifndef DARWIN\r                       Config->logpath = Config->MyDir + "/ircd.log";\r#else\r                   Config->logpath = "/var/log/ircd.log";\r#endif\r          }\r\r             Config->log_file = fopen(Config->logpath.c_str(),"a+");\r        }\r      else\r   {\r              Config->log_file = fopen(this->LogFileName,"a+");\r      }\r\r     if (!Config->log_file)\r {\r              printf("ERROR: Could not write to logfile %s: %s\n\n", Config->logpath.c_str(), strerror(errno));\r              Exit(EXIT_STATUS_LOG);\r }\r\r     this->Logger = new FileLogger(this, Config->log_file);\r}\r\rvoid InspIRCd::CheckRoot()\r{\r#ifndef DARWIN\r  if (geteuid() == 0)\r    {\r              printf("WARNING!!! You are running an irc server as ROOT!!! DO NOT DO THIS!!!\n\n");\r           this->Log(DEFAULT,"Cant start as root");\r#else\r if (geteuid() != 16)\r   {\r              printf("WARNING!!! You are not running inspircd as the ircdaemon user!!! YOU CAN NOT DO THIS!!!\n\n");\r         this->Log(DEFAULT,"Must start as user ircdaemon");\r#endif\r              Exit(EXIT_STATUS_ROOT);\r        }\r}\r\rvoid InspIRCd::CheckDie()\r{\r       if (*Config->DieValue)\r {\r              printf("WARNING: %s\n\n",Config->DieValue);\r            this->Log(DEFAULT,"Died because of <die> tag: %s",Config->DieValue);\r           Exit(EXIT_STATUS_DIETAG);\r      }\r}\r\r/* We must load the modules AFTER initializing the socket engine, now */\rvoid InspIRCd::LoadAllModules()\r{\r        char configToken[MAXBUF];\r      Config->module_names.clear();\r  this->ModCount = -1;\r\r  for (int count = 0; count < Config->ConfValueEnum(Config->config_data, "module"); count++)\r     {\r              Config->ConfValue(Config->config_data, "module", "name", count, configToken, MAXBUF);\r          printf_c("[\033[1;32m*\033[0m] Loading module:\t\033[1;32m%s\033[0m\n",configToken);\r           \r               if (!this->LoadModule(configToken))             \r               {\r                      this->Log(DEFAULT,"There was an error loading the module '%s': %s", configToken, this->ModuleError());\r                 printf_c("\n[\033[1;31m*\033[0m] There was an error loading the module '%s': %s\n\n", configToken, this->ModuleError());\r                       Exit(EXIT_STATUS_MODULE);\r              }\r      }\r      printf_c("\nA total of \033[1;32m%d\033[0m module%s been loaded.\n", this->ModCount+1, this->ModCount+1 == 1 ? " has" : "s have");\r     this->Log(DEFAULT,"Total loaded modules: %d", this->ModCount+1);\r}\r\rvoid InspIRCd::SendWhoisLine(userrec* user, userrec* dest, int numeric, const std::string &text)\r{\r std::string copy_text = text;\r\r int MOD_RESULT = 0;\r    FOREACH_RESULT_I(this, I_OnWhoisLine, OnWhoisLine(user, dest, numeric, copy_text));\r\r   if (!MOD_RESULT)\r               user->WriteServ("%d %s", numeric, copy_text.c_str());\r}\r\rvoid InspIRCd::SendWhoisLine(userrec* user, userrec* dest, int numeric, const char* format, ...)\r{\r    char textbuffer[MAXBUF];\r       va_list argsPtr;\r       va_start (argsPtr, format);\r    vsnprintf(textbuffer, MAXBUF, format, argsPtr);\r        va_end(argsPtr);\r\r      this->SendWhoisLine(user, dest, numeric, std::string(textbuffer));\r}\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include <stdarg.h>
+#include "configreader.h"
+#include "users.h"
+#include "modules.h"
+#include "wildcard.h"
+#include "mode.h"
+#include "xline.h"
+#include "exitcodes.h"
+
+static char TIMESTR[26];
+static time_t LAST = 0;
+
+/** Log()
+ *  Write a line of text `text' to the logfile (and stdout, if in nofork) if the level `level'
+ *  is greater than the configured loglevel.
+ */
+void InspIRCd::Log(int level, const char* text, ...)
+{
+       /* Do this check again here so that we save pointless vsnprintf calls */
+       if ((level < Config->LogLevel) && !Config->forcedebug)
+               return;
+
+       va_list argsPtr;
+       char textbuffer[65536];
+
+       va_start(argsPtr, text);
+       vsnprintf(textbuffer, 65536, text, argsPtr);
+       va_end(argsPtr);
+
+       this->Log(level, std::string(textbuffer));
+}
+
+void InspIRCd::Log(int level, const std::string &text)
+{
+       if (!this->Config)
+               return;
+
+       /* If we were given -debug we output all messages, regardless of configured loglevel */
+       if ((level < Config->LogLevel) && !Config->forcedebug)
+               return;
+
+       if (Time() != LAST)
+       {
+               time_t local = Time();
+               struct tm *timeinfo = localtime(&local);
+
+               strlcpy(TIMESTR,asctime(timeinfo),26);
+               TIMESTR[24] = ':';
+               LAST = Time();
+       }
+
+       if (Config->log_file && Config->writelog)
+       {
+               std::string out = std::string(TIMESTR) + " " + text.c_str() + "\n";
+               this->Logger->WriteLogLine(out);
+       }
+
+       if (Config->nofork)
+       {
+               printf("%s %s\n", TIMESTR, text.c_str());
+       }
+}
+
+std::string InspIRCd::GetServerDescription(const char* servername)
+{
+       std::string description;
+
+       FOREACH_MOD_I(this,I_OnGetServerDescription,OnGetServerDescription(servername,description));
+
+       if (!description.empty())
+       {
+               return description;
+       }
+       else
+       {
+               // not a remote server that can be found, it must be me.
+               return Config->ServerDesc;
+       }
+}
+
+/* XXX - We don't use WriteMode for this because WriteMode is very slow and
+ * this isnt. Basically WriteMode has to iterate ALL the users 'n' times for
+ * the number of modes provided, e.g. if you send WriteMode 'og' to write to
+ * opers with globops, and you have 2000 users, thats 4000 iterations. WriteOpers
+ * uses the oper list, which means if you have 2000 users but only 5 opers,
+ * it iterates 5 times.
+ */
+void InspIRCd::WriteOpers(const char* text, ...)
+{
+       char textbuffer[MAXBUF];
+       va_list argsPtr;
+
+       va_start(argsPtr, text);
+       vsnprintf(textbuffer, MAXBUF, text, argsPtr);
+       va_end(argsPtr);
+
+       this->WriteOpers(std::string(textbuffer));
+}
+
+void InspIRCd::WriteOpers(const std::string &text)
+{
+       for (std::vector<userrec*>::iterator i = this->all_opers.begin(); i != this->all_opers.end(); i++)
+       {
+               userrec* a = *i;
+               if (IS_LOCAL(a) && a->modes[UM_SERVERNOTICE])
+               {
+                       // send server notices to all with +s
+                       a->WriteServ("NOTICE %s :%s",a->nick,text.c_str());
+               }
+       }
+}
+
+void InspIRCd::ServerNoticeAll(char* text, ...)
+{
+       if (!text)
+               return;
+
+       char textbuffer[MAXBUF];
+       char formatbuffer[MAXBUF];
+       va_list argsPtr;
+       va_start (argsPtr, text);
+       vsnprintf(textbuffer, MAXBUF, text, argsPtr);
+       va_end(argsPtr);
+
+       snprintf(formatbuffer,MAXBUF,"NOTICE $%s :%s",Config->ServerName,textbuffer);
+
+       for (std::vector<userrec*>::const_iterator i = local_users.begin(); i != local_users.end(); i++)
+       {
+               userrec* t = *i;
+               t->WriteServ(std::string(formatbuffer));
+       }
+}
+
+void InspIRCd::ServerPrivmsgAll(char* text, ...)
+{
+       if (!text)
+               return;
+
+       char textbuffer[MAXBUF];
+       char formatbuffer[MAXBUF];
+       va_list argsPtr;
+       va_start (argsPtr, text);
+       vsnprintf(textbuffer, MAXBUF, text, argsPtr);
+       va_end(argsPtr);
+
+       snprintf(formatbuffer,MAXBUF,"PRIVMSG $%s :%s",Config->ServerName,textbuffer);
+
+       for (std::vector<userrec*>::const_iterator i = local_users.begin(); i != local_users.end(); i++)
+       {
+               userrec* t = *i;
+               t->WriteServ(std::string(formatbuffer));
+       }
+}
+
+void InspIRCd::WriteMode(const char* modes, int flags, const char* text, ...)
+{
+       char textbuffer[MAXBUF];
+       int modelen;
+       va_list argsPtr;
+
+       if (!text || !modes || !flags)
+       {
+               this->Log(DEFAULT,"*** BUG *** WriteMode was given an invalid parameter");
+               return;
+       }
+
+       va_start(argsPtr, text);
+       vsnprintf(textbuffer, MAXBUF, text, argsPtr);
+       va_end(argsPtr);
+       modelen = strlen(modes);
+
+       if (flags == WM_AND)
+       {
+               for (std::vector<userrec*>::const_iterator i = local_users.begin(); i != local_users.end(); i++)
+               {
+                       userrec* t = *i;
+                       bool send_to_user = true;
+
+                       for (int n = 0; n < modelen; n++)
+                       {
+                               if (!t->modes[modes[n]-65])
+                               {
+                                       send_to_user = false;
+                                       break;
+                               }
+                       }
+                       if (send_to_user)
+                               t->WriteServ("NOTICE %s :%s",t->nick,textbuffer);
+               }
+       }
+       else
+       if (flags == WM_OR)
+       {
+               for (std::vector<userrec*>::const_iterator i = local_users.begin(); i != local_users.end(); i++)
+               {
+                       userrec* t = *i;
+                       bool send_to_user = false;
+
+                       for (int n = 0; n < modelen; n++)
+                       {
+                               if (t->modes[modes[n]-65])
+                               {
+                                       send_to_user = true;
+                                       break;
+                               }
+                       }
+                       if (send_to_user)
+                               t->WriteServ("NOTICE %s :%s",t->nick,textbuffer);
+               }
+       }
+}
+
+/* Find a user record by nickname and return a pointer to it */
+
+userrec* InspIRCd::FindNick(const std::string &nick)
+{
+       user_hash::iterator iter = clientlist->find(nick);
+
+       if (iter == clientlist->end())
+               /* Couldn't find it */
+               return NULL;
+
+       return iter->second;
+}
+
+userrec* InspIRCd::FindNick(const char* nick)
+{
+       user_hash::iterator iter = clientlist->find(nick);
+       
+       if (iter == clientlist->end())
+               return NULL;
+
+       return iter->second;
+}
+
+/* find a channel record by channel name and return a pointer to it */
+
+chanrec* InspIRCd::FindChan(const char* chan)
+{
+       chan_hash::iterator iter = chanlist->find(chan);
+
+       if (iter == chanlist->end())
+               /* Couldn't find it */
+               return NULL;
+
+       return iter->second;
+}
+
+chanrec* InspIRCd::FindChan(const std::string &chan)
+{
+       chan_hash::iterator iter = chanlist->find(chan);
+
+       if (iter == chanlist->end())
+               /* Couldn't find it */
+               return NULL;
+
+       return iter->second;
+}
+
+/*
+ * sends out an error notice to all connected clients (not to be used
+ * lightly!)
+ */
+void InspIRCd::SendError(const std::string &s)
+{
+       for (std::vector<userrec*>::const_iterator i = this->local_users.begin(); i != this->local_users.end(); i++)
+       {
+               if ((*i)->registered == REG_ALL)
+               {
+                       (*i)->WriteServ("NOTICE %s :%s",(*i)->nick,s.c_str());
+               }
+               else
+               {
+                       /* Unregistered connections receive ERROR, not a NOTICE */
+                       (*i)->Write("ERROR :" + s);
+               }
+               /* This might generate a whole load of EAGAIN, but we dont really
+                * care about this, as if we call SendError something catastrophic
+                * has occured anyway, and we wont receive the events for these.
+                */
+               (*i)->FlushWriteBuf();
+       }
+}
+
+// this function counts all users connected, wether they are registered or NOT.
+int InspIRCd::UserCount()
+{
+       return clientlist->size();
+}
+
+// this counts only registered users, so that the percentages in /MAP don't mess up when users are sitting in an unregistered state
+int InspIRCd::RegisteredUserCount()
+{
+       return clientlist->size() - this->UnregisteredUserCount();
+}
+
+int InspIRCd::ModeCount(const char mode)
+{
+       ModeHandler* mh = this->Modes->FindMode(mode, MODETYPE_USER);
+
+       if (mh)
+               return mh->GetCount();
+       else
+               return 0;
+}
+
+int InspIRCd::InvisibleUserCount()
+{
+       return ModeCount('i');
+}
+
+int InspIRCd::OperCount()
+{
+       return this->all_opers.size();
+}
+
+int InspIRCd::UnregisteredUserCount()
+{
+       return this->unregistered_count;
+}
+
+long InspIRCd::ChannelCount()
+{
+       return chanlist->size();
+}
+
+long InspIRCd::LocalUserCount()
+{
+       /* Doesnt count unregistered clients */
+       return (local_users.size() - this->UnregisteredUserCount());
+}
+       
+bool InspIRCd::IsChannel(const char *chname)
+{
+       char *c;
+
+       /* check for no name - don't check for !*chname, as if it is empty, it won't be '#'! */
+       if (!chname || *chname != '#')
+       {
+               return false;
+       }
+
+       c = (char *)chname + 1;
+       while (*c)
+       {
+               switch (*c)
+               {
+                       case ' ':
+                       case ',':
+                       case 7:
+                               return false;
+               }
+
+               c++;
+       }
+               
+       /* too long a name - note funky pointer arithmetic here. */
+       if ((c - chname) > CHANMAX)
+       {
+                       return false;
+       }
+
+       return true;
+}
+
+bool InspIRCd::IsNick(const char* n)
+{
+       if (!n || !*n)
+               return false;
+       int p = 0;
+       for (char* i = (char*)n; *i; i++, p++)
+       {
+               if ((*i >= 'A') && (*i <= '}'))
+               {
+                       /* "A"-"}" can occur anywhere in a nickname */
+                       continue;
+               }
+
+               if ((((*i >= '0') && (*i <= '9')) || (*i == '-')) && (i > n))
+               {
+                       /* "0"-"9", "-" can occur anywhere BUT the first char of a nickname */
+                       continue;
+               }
+
+               /* invalid character! abort */
+               return false;
+       }
+
+       /* too long? or not -- pointer arithmetic rocks */
+       return (p < NICKMAX - 1);
+}
+
+
+bool InspIRCd::IsIdent(const char* n)
+{
+       if (!n || !*n)
+               return false;
+
+       for (char* i = (char*)n; *i; i++)
+       {
+               if ((*i >= 'A') && (*i <= '}'))
+               {
+                       continue;
+               }
+
+               if (((*i >= '0') && (*i <= '9')) || (*i == '-') || (*i == '.'))
+               {
+                       continue;
+               }
+
+               return false;
+       }
+
+       return true;
+}
+
+void InspIRCd::OpenLog(char** argv, int argc)
+{
+       Config->MyDir = Config->GetFullProgDir();
+
+       if (!*this->LogFileName)
+       {
+               if (Config->logpath.empty())
+               {
+#ifndef DARWIN
+                       Config->logpath = Config->MyDir + "/ircd.log";
+#else
+                       Config->logpath = "/var/log/ircd.log";
+#endif
+               }
+
+               Config->log_file = fopen(Config->logpath.c_str(),"a+");
+       }
+       else
+       {
+               Config->log_file = fopen(this->LogFileName,"a+");
+       }
+
+       if (!Config->log_file)
+       {
+               printf("ERROR: Could not write to logfile %s: %s\n\n", Config->logpath.c_str(), strerror(errno));
+               Exit(EXIT_STATUS_LOG);
+       }
+
+       this->Logger = new FileLogger(this, Config->log_file);
+}
+
+void InspIRCd::CheckRoot()
+{
+#ifndef DARWIN
+       if (geteuid() == 0)
+       {
+               printf("WARNING!!! You are running an irc server as ROOT!!! DO NOT DO THIS!!!\n\n");
+               this->Log(DEFAULT,"Cant start as root");
+#else
+       if (geteuid() != 16)
+       {
+               printf("WARNING!!! You are not running inspircd as the ircdaemon user!!! YOU CAN NOT DO THIS!!!\n\n");
+               this->Log(DEFAULT,"Must start as user ircdaemon");
+#endif
+               Exit(EXIT_STATUS_ROOT);
+       }
+}
+
+void InspIRCd::CheckDie()
+{
+       if (*Config->DieValue)
+       {
+               printf("WARNING: %s\n\n",Config->DieValue);
+               this->Log(DEFAULT,"Died because of <die> tag: %s",Config->DieValue);
+               Exit(EXIT_STATUS_DIETAG);
+       }
+}
+
+/* We must load the modules AFTER initializing the socket engine, now */
+void InspIRCd::LoadAllModules()
+{
+       char configToken[MAXBUF];
+       Config->module_names.clear();
+       this->ModCount = -1;
+
+       for (int count = 0; count < Config->ConfValueEnum(Config->config_data, "module"); count++)
+       {
+               Config->ConfValue(Config->config_data, "module", "name", count, configToken, MAXBUF);
+               printf_c("[\033[1;32m*\033[0m] Loading module:\t\033[1;32m%s\033[0m\n",configToken);
+               
+               if (!this->LoadModule(configToken))             
+               {
+                       this->Log(DEFAULT,"There was an error loading the module '%s': %s", configToken, this->ModuleError());
+                       printf_c("\n[\033[1;31m*\033[0m] There was an error loading the module '%s': %s\n\n", configToken, this->ModuleError());
+                       Exit(EXIT_STATUS_MODULE);
+               }
+       }
+       printf_c("\nA total of \033[1;32m%d\033[0m module%s been loaded.\n", this->ModCount+1, this->ModCount+1 == 1 ? " has" : "s have");
+       this->Log(DEFAULT,"Total loaded modules: %d", this->ModCount+1);
+}
+
+void InspIRCd::SendWhoisLine(userrec* user, userrec* dest, int numeric, const std::string &text)
+{
+       std::string copy_text = text;
+
+       int MOD_RESULT = 0;
+       FOREACH_RESULT_I(this, I_OnWhoisLine, OnWhoisLine(user, dest, numeric, copy_text));
+
+       if (!MOD_RESULT)
+               user->WriteServ("%d %s", numeric, copy_text.c_str());
+}
+
+void InspIRCd::SendWhoisLine(userrec* user, userrec* dest, int numeric, const char* format, ...)
+{
+       char textbuffer[MAXBUF];
+       va_list argsPtr;
+       va_start (argsPtr, format);
+       vsnprintf(textbuffer, MAXBUF, format, argsPtr);
+       va_end(argsPtr);
+
+       this->SendWhoisLine(user, dest, numeric, std::string(textbuffer));
+}
+
index 7f93427063287014d3e24e236956c686b31e6de5..858862e9dfa79c0ce06d05fbe9d3ddf1096fef84 100644 (file)
@@ -1 +1,1307 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "configreader.h"\r#include <signal.h>\r\r#ifndef WIN32\r#include <dirent.h>\r#include <unistd.h>\r#include <sys/resource.h>\r#include <dlfcn.h>\r#include <getopt.h>\r\r/* Some systems don't define RUSAGE_SELF. This should fix them. */\r#ifndef RUSAGE_SELF\r       #define RUSAGE_SELF 0\r#endif\r\r#endif\r\r#include <exception>\r#include <fstream>\r#include "modules.h"\r#include "mode.h"\r#include "xline.h"\r#include "socketengine.h"\r#include "inspircd_se_config.h"\r#include "socket.h"\r#include "typedefs.h"\r#include "command_parse.h"\r#include "exitcodes.h"\r\r#ifdef WIN32\r\r/* This MUST remain static and delcared outside the class, so that WriteProcessMemory can reference it properly */\rstatic DWORD owner_processid = 0;\r\rDWORD WindowsForkStart(InspIRCd * Instance)\r{\r       /* Windows implementation of fork() :P */\r\r     char module[MAX_PATH];\r if(!GetModuleFileName(NULL, module, MAX_PATH))\r {\r              printf("GetModuleFileName() failed.\n");\r               return false;\r  }\r\r     STARTUPINFO startupinfo;\r       PROCESS_INFORMATION procinfo;\r  ZeroMemory(&startupinfo, sizeof(STARTUPINFO));\r ZeroMemory(&procinfo, sizeof(PROCESS_INFORMATION));\r\r   // Fill in the startup info struct\r     GetStartupInfo(&startupinfo);\r\r /* Default creation flags create the processes suspended */\r    DWORD startupflags = CREATE_SUSPENDED;\r\r        /* On windows 2003/XP and above, we can use the value\r   * CREATE_PRESERVE_CODE_AUTHZ_LEVEL which gives more access\r     * to the process which we may require on these operating systems.\r      */\r    OSVERSIONINFO vi;\r      vi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);\r        GetVersionEx(&vi);\r     if ((vi.dwMajorVersion >= 5) && (vi.dwMinorVersion > 0))\r               startupflags |= CREATE_PRESERVE_CODE_AUTHZ_LEVEL;\r\r     // Launch our "forked" process.\r        BOOL bSuccess = CreateProcess ( module, // Module (exe) filename\r               strdup(GetCommandLine()),       // Command line (exe plus parameters from the OS)\r                                              // NOTE: We cannot return the direct value of the\r                                              // GetCommandLine function here, as the pointer is\r                                             // passed straight to the child process, and will be\r                                           // invalid once we exit as it goes out of context.\r                                             // strdup() seems ok, though.\r          0,                              // PROCESS_SECURITY_ATTRIBUTES\r         0,                              // THREAD_SECURITY_ATTRIBUTES\r          TRUE,                           // We went to inherit handles.\r         startupflags,                   // Allow us full access to the process and suspend it.\r         0,                              // ENVIRONMENT\r         0,                              // CURRENT_DIRECTORY\r           &startupinfo,                   // startup info\r                &procinfo);                     // process info\r\r       if(!bSuccess)\r  {\r              printf("CreateProcess() error: %s\n", dlerror());\r              return false;\r  }\r\r     // Set the owner process id in the target process.\r     SIZE_T written = 0;\r    DWORD pid = GetCurrentProcessId();\r     if(!WriteProcessMemory(procinfo.hProcess, &owner_processid, &pid, sizeof(DWORD), &written) || written != sizeof(DWORD))\r        {\r              printf("WriteProcessMemory() failed: %s\n", dlerror());\r                return false;\r  }\r\r     // Resume the other thread (let it start)\r      ResumeThread(procinfo.hThread);\r\r       // Wait for the new process to kill us. If there is some error, the new process will end and we will end up at the next line.\r  WaitForSingleObject(procinfo.hProcess, INFINITE);\r\r     // If we hit this it means startup failed, default to 14 if this fails.\r        DWORD ExitCode = 14;\r   GetExitCodeProcess(procinfo.hProcess, &ExitCode);\r      CloseHandle(procinfo.hThread);\r CloseHandle(procinfo.hProcess);\r        return ExitCode;\r}\r\rvoid WindowsForkKillOwner(InspIRCd * Instance)\r{\r   HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, owner_processid);\r      if(!hProcess || !owner_processid)\r      {\r              printf("Could not open process id %u: %s.\n", owner_processid, dlerror());\r             Instance->Exit(14);\r    }\r\r     // die die die\r if(!TerminateProcess(hProcess, 0))\r     {\r              printf("Could not TerminateProcess(): %s\n", dlerror());\r               Instance->Exit(14);\r    }\r\r     CloseHandle(hProcess);\r}\r\r#endif\r\rusing irc::sockets::NonBlocking;\rusing irc::sockets::Blocking;\rusing irc::sockets::insp_ntoa;\rusing irc::sockets::insp_inaddr;\rusing irc::sockets::insp_sockaddr;\r\rInspIRCd* SI = NULL;\r\r/* Burlex: Moved from exitcodes.h -- due to duplicate symbols */\rconst char* ExitCodes[] =\r{\r                "No error", /* 0 */\r            "DIE command", /* 1 */\r         "execv() failed", /* 2 */\r              "Internal error", /* 3 */\r              "Config file error", /* 4 */\r           "Logfile error", /* 5 */\r               "POSIX fork failed", /* 6 */\r           "Bad commandline parameters", /* 7 */\r          "No ports could be bound", /* 8 */\r             "Can't write PID file", /* 9 */\r                "SocketEngine could not initialize", /* 10 */\r          "Refusing to start up as root", /* 11 */\r               "Found a <die> tag!", /* 12 */\r         "Couldn't load module on startup", /* 13 */\r            "Could not create windows forked process", /* 14 */\r            "Received SIGTERM", /* 15 */\r};\r\rvoid InspIRCd::AddServerName(const std::string &servername)\r{\r servernamelist::iterator itr = servernames.begin();\r    for(; itr != servernames.end(); ++itr)\r         if(**itr == servername)\r                        return;\r\r       string * ns = new string(servername);\r  servernames.push_back(ns);\r}\r\rconst char* InspIRCd::FindServerNamePtr(const std::string &servername)\r{\r servernamelist::iterator itr = servernames.begin();\r    for(; itr != servernames.end(); ++itr)\r         if(**itr == servername)\r                        return (*itr)->c_str();\r\r       servernames.push_back(new string(servername));\r itr = --servernames.end();\r     return (*itr)->c_str();\r}\r\rbool InspIRCd::FindServerName(const std::string &servername)\r{\r      servernamelist::iterator itr = servernames.begin();\r    for(; itr != servernames.end(); ++itr)\r         if(**itr == servername)\r                        return true;\r   return false;\r}\r\rvoid InspIRCd::Exit(int status)\r{\r#ifdef WINDOWS\r      CloseIPC();\r#endif\r     if (SI)\r        {\r              SI->SendError("Exiting with status " + ConvToStr(status) + " (" + std::string(ExitCodes[status]) + ")");\r               SI->Cleanup();\r }\r      exit (status);\r}\r\rvoid InspIRCd::Cleanup()\r{\r   std::vector<std::string> mymodnames;\r   int MyModCount = this->GetModuleCount();\r\r      for (unsigned int i = 0; i < Config->ports.size(); i++)\r        {\r              /* This calls the constructor and closes the listening socket */\r               delete Config->ports[i];\r       }\r\r     Config->ports.clear();\r\r        /* Close all client sockets, or the new process inherits them */\r       for (std::vector<userrec*>::const_iterator i = this->local_users.begin(); i != this->local_users.end(); i++)\r   {\r              (*i)->SetWriteError("Server shutdown");\r                (*i)->CloseSocket();\r   }\r\r     /* We do this more than once, so that any service providers get a\r       * chance to be unhooked by the modules using them, but then get\r        * a chance to be removed themsleves.\r   */\r    for (int tries = 0; tries < 3; tries++)\r        {\r              MyModCount = this->GetModuleCount();\r           mymodnames.clear();\r\r           /* Unload all modules, so they get a chance to clean up their listeners */\r             for (int j = 0; j <= MyModCount; j++)\r                  mymodnames.push_back(Config->module_names[j]);\r\r                for (int k = 0; k <= MyModCount; k++)\r                  this->UnloadModule(mymodnames[k].c_str());\r     }\r\r     /* Close logging */\r    this->Logger->Close();\r\r        /* Cleanup Server Names */\r     for(servernamelist::iterator itr = servernames.begin(); itr != servernames.end(); ++itr)\r               delete (*itr);\r\r#ifdef WINDOWS\r /* WSACleanup */\r       WSACleanup();\r#endif\r}\r\rvoid InspIRCd::Restart(const std::string &reason)\r{\r    /* SendError flushes each client's queue,\r       * regardless of writeability state\r     */\r    this->SendError(reason);\r\r      this->Cleanup();\r\r      /* Figure out our filename (if theyve renamed it, we're boned) */\r      std::string me;\r\r#ifdef WINDOWS\r        char module[MAX_PATH];\r if (GetModuleFileName(NULL, module, MAX_PATH))\r         me = module;\r#else\r     me = Config->MyDir + "/inspircd";\r#endif\r\r      if (execv(me.c_str(), Config->argv) == -1)\r     {\r              /* Will raise a SIGABRT if not trapped */\r              throw CoreException(std::string("Failed to execv()! error: ") + strerror(errno));\r      }\r}\r\rvoid InspIRCd::Start()\r{\r  printf_c("\033[1;32mInspire Internet Relay Chat Server, compiled %s at %s\n",__DATE__,__TIME__);\r       printf_c("(C) InspIRCd Development Team.\033[0m\n\n");\r printf_c("Developers:\t\t\033[1;32mBrain, FrostyCoolSlug, w00t, Om, Special, pippijn, peavey, Burlex\033[0m\n");\r       printf_c("Others:\t\t\t\033[1;32mSee /INFO Output\033[0m\n");\r}\r\rvoid InspIRCd::Rehash(int status)\r{\r   SI->WriteOpers("*** Rehashing config file %s due to SIGHUP",ServerConfig::CleanFilename(SI->ConfigFileName));\r  SI->CloseLog();\r        SI->OpenLog(SI->Config->argv, SI->Config->argc);\r       SI->RehashUsersAndChans();\r     FOREACH_MOD_I(SI, I_OnGarbageCollect, OnGarbageCollect());\r     SI->Config->Read(false,NULL);\r  SI->ResetMaxBans();\r    SI->Res->Rehash();\r     FOREACH_MOD_I(SI,I_OnRehash,OnRehash(NULL,""));\r        SI->BuildISupport();\r}\r\rvoid InspIRCd::ResetMaxBans()\r{\r        for (chan_hash::const_iterator i = chanlist->begin(); i != chanlist->end(); i++)\r               i->second->ResetMaxBans();\r}\r\r\r/** Because hash_map doesnt free its buckets when we delete items (this is a 'feature')\r * we must occasionally rehash the hash (yes really).\r * We do this by copying the entries from the old hash to a new hash, causing all\r * empty buckets to be weeded out of the hash. We dont do this on a timer, as its\r * very expensive, so instead we do it when the user types /REHASH and expects a\r * short delay anyway.\r */\rvoid InspIRCd::RehashUsersAndChans()\r{\r    user_hash* old_users = this->clientlist;\r       chan_hash* old_chans = this->chanlist;\r\r        this->clientlist = new user_hash();\r    this->chanlist = new chan_hash();\r\r     for (user_hash::const_iterator n = old_users->begin(); n != old_users->end(); n++)\r             this->clientlist->insert(*n);\r\r delete old_users;\r\r     for (chan_hash::const_iterator n = old_chans->begin(); n != old_chans->end(); n++)\r             this->chanlist->insert(*n);\r\r   delete old_chans;\r}\r\rvoid InspIRCd::CloseLog()\r{\r       this->Logger->Close();\r}\r\rvoid InspIRCd::SetSignals()\r{\r#ifndef WIN32\r  signal(SIGALRM, SIG_IGN);\r      signal(SIGHUP, InspIRCd::Rehash);\r      signal(SIGPIPE, SIG_IGN);\r      signal(SIGCHLD, SIG_IGN);\r#endif\r       signal(SIGTERM, InspIRCd::Exit);\r}\r\rvoid InspIRCd::QuickExit(int status)\r{\r     exit(0);\r}\r\rbool InspIRCd::DaemonSeed()\r{\r#ifdef WINDOWS\r       printf_c("InspIRCd Process ID: \033[1;32m%lu\033[0m\n", GetCurrentProcessId());\r        return true;\r#else\r     signal(SIGTERM, InspIRCd::QuickExit);\r\r int childpid;\r  if ((childpid = fork ()) < 0)\r          return false;\r  else if (childpid > 0)\r {\r              /* We wait here for the child process to kill us,\r               * so that the shell prompt doesnt come back over\r               * the output.\r          * Sending a kill with a signal of 0 just checks\r                * if the child pid is still around. If theyre not,\r             * they threw an error and we should give up.\r           */\r            while (kill(childpid, 0) != -1)\r                        sleep(1);\r              exit(0);\r       }\r      setsid ();\r     umask (007);\r   printf("InspIRCd Process ID: \033[1;32m%lu\033[0m\n",(unsigned long)getpid());\r\r        signal(SIGTERM, InspIRCd::Exit);\r\r      rlimit rl;\r     if (getrlimit(RLIMIT_CORE, &rl) == -1)\r {\r              this->Log(DEFAULT,"Failed to getrlimit()!");\r           return false;\r  }\r      else\r   {\r              rl.rlim_cur = rl.rlim_max;\r             if (setrlimit(RLIMIT_CORE, &rl) == -1)\r                 this->Log(DEFAULT,"setrlimit() failed, cannot increase coredump size.");\r       }\r\r     return true;\r#endif\r}\r\rvoid InspIRCd::WritePID(const std::string &filename)\r{\r  std::string fname = (filename.empty() ? "inspircd.pid" : filename);\r    if (*(fname.begin()) != '/')\r   {\r              std::string::size_type pos;\r            std::string confpath = this->ConfigFileName;\r           if ((pos = confpath.rfind("/")) != std::string::npos)\r          {\r                      /* Leaves us with just the path */\r                     fname = confpath.substr(0, pos) + std::string("/") + fname;\r            }\r      }\r      std::ofstream outfile(fname.c_str());\r  if (outfile.is_open())\r {\r              outfile << getpid();\r           outfile.close();\r       }\r      else\r   {\r              printf("Failed to write PID-file '%s', exiting.\n",fname.c_str());\r             this->Log(DEFAULT,"Failed to write PID-file '%s', exiting.",fname.c_str());\r            Exit(EXIT_STATUS_PID);\r }\r}\r\rstd::string InspIRCd::GetRevision()\r{\r     return REVISION;\r}\r\rInspIRCd::InspIRCd(int argc, char** argv)\r  : ModCount(-1), GlobalCulls(this)\r{\r    int found_ports = 0;\r   FailedPortList pl;\r     int do_version = 0, do_nofork = 0, do_debug = 0, do_nolog = 0, do_root = 0;    /* flag variables */\r    char c = 0;\r\r   modules.resize(255);\r   factory.resize(255);\r   memset(&server, 0, sizeof(server));\r    memset(&client, 0, sizeof(client));\r\r   this->unregistered_count = 0;\r\r this->clientlist = new user_hash();\r    this->chanlist = new chan_hash();\r\r     this->Config = new ServerConfig(this);\r\r        this->Config->argv = argv;\r     this->Config->argc = argc;\r\r    chdir(Config->GetFullProgDir().c_str());\r\r      this->Config->opertypes.clear();\r       this->Config->operclass.clear();\r       this->SNO = new SnomaskManager(this);\r  this->TIME = this->OLDTIME = this->startup_time = time(NULL);\r  this->time_delta = 0;\r  this->next_call = this->TIME + 3;\r      srand(this->TIME);\r\r    *this->LogFileName = 0;\r        strlcpy(this->ConfigFileName, CONFIG_FILE, MAXBUF);\r\r   struct option longopts[] =\r     {\r              { "nofork",     no_argument,            &do_nofork,     1       },\r             { "logfile",    required_argument,      NULL,           'f'     },\r             { "config",     required_argument,      NULL,           'c'     },\r             { "debug",      no_argument,            &do_debug,      1       },\r             { "nolog",      no_argument,            &do_nolog,      1       },\r             { "runasroot",  no_argument,            &do_root,       1       },\r             { "version",    no_argument,            &do_version,    1       },\r             { 0, 0, 0, 0 }\r };\r\r    while ((c = getopt_long_only(argc, argv, ":f:", longopts, NULL)) != -1)\r        {\r              switch (c)\r             {\r                      case 'f':\r                              /* Log filename was set */\r                             strlcpy(LogFileName, optarg, MAXBUF);\r                  break;\r                 case 'c':\r                              /* Config filename was set */\r                          strlcpy(ConfigFileName, optarg, MAXBUF);\r                       break;\r                 case 0:\r                                /* getopt_long_only() set an int variable, just keep going */\r                  break;\r                 default:\r                               /* Unknown parameter! DANGER, INTRUDER.... err.... yeah. */\r                            printf("Usage: %s [--nofork] [--nolog] [--debug] [--logfile <filename>] [--runasroot] [--version] [--config <config>]\n", argv[0]);\r                            Exit(EXIT_STATUS_ARGV);\r                        break;\r         }\r      }\r\r     if (do_version)\r        {\r              printf("\n%s r%s\n", VERSION, REVISION);\r               Exit(EXIT_STATUS_NOERROR);\r     }\r\r#ifdef WIN32\r\r       // Handle forking\r      if(!do_nofork && !owner_processid)\r     {\r              DWORD ExitCode = WindowsForkStart(this);\r               if(ExitCode)\r                   Exit(ExitCode);\r        }\r\r     // Set up winsock\r      WSADATA wsadata;\r       WSAStartup(MAKEWORD(2,0), &wsadata);\r\r#endif\r   if (!ServerConfig::FileExists(this->ConfigFileName))\r   {\r              printf("ERROR: Cannot open config file: %s\nExiting...\n", this->ConfigFileName);\r              this->Log(DEFAULT,"Unable to open config file %s", this->ConfigFileName);\r              Exit(EXIT_STATUS_CONFIG);\r      }\r\r     this->Start();\r\r        /* Set the finished argument values */\r Config->nofork = do_nofork;\r    Config->forcedebug = do_debug;\r Config->writelog = !do_nolog;\r\r strlcpy(Config->MyExecutable,argv[0],MAXBUF);\r\r this->OpenLog(argv, argc);\r\r    this->stats = new serverstats();\r       this->Timers = new TimerManager(this);\r this->Parser = new CommandParser(this);\r        this->XLines = new XLineManager(this);\r Config->ClearStack();\r  Config->Read(true, NULL);\r\r     if (!do_root)\r          this->CheckRoot();\r     else\r   {\r              printf("* WARNING * WARNING * WARNING * WARNING * WARNING * \n\n");\r            printf("YOU ARE RUNNING INSPIRCD AS ROOT. THIS IS UNSUPPORTED\n");\r             printf("AND IF YOU ARE HACKED, CRACKED, SPINDLED OR MUTILATED\n");\r             printf("OR ANYTHING ELSE UNEXPECTED HAPPENS TO YOU OR YOUR\n");\r                printf("SERVER, THEN IT IS YOUR OWN FAULT. IF YOU DID NOT MEAN\n");\r            printf("TO START INSPIRCD AS ROOT, HIT CTRL+C NOW AND RESTART\n");\r             printf("THE PROGRAM AS A NORMAL USER. YOU HAVE BEEN WARNED!\n");\r               printf("\nInspIRCd starting in 20 seconds, ctrl+c to abort...\n");\r             sleep(20);\r     }\r\r     this->SetSignals();\r\r   if (!Config->nofork)\r   {\r              if (!this->DaemonSeed())\r               {\r                      printf("ERROR: could not go into daemon mode. Shutting down.\n");\r                      Log(DEFAULT,"ERROR: could not go into daemon mode. Shutting down.");\r                   Exit(EXIT_STATUS_FORK);\r                }\r      }\r\r\r    /* Because of limitations in kqueue on freebsd, we must fork BEFORE we\r  * initialize the socket engine.\r        */\r    SocketEngineFactory* SEF = new SocketEngineFactory();\r  SE = SEF->Create(this);\r        delete SEF;\r\r   this->Modes = new ModeParser(this);\r    this->AddServerName(Config->ServerName);\r       CheckDie();\r    int bounditems = BindPorts(true, found_ports, pl);\r\r    for(int t = 0; t < 255; t++)\r           Config->global_implementation[t] = 0;\r\r memset(&Config->implement_lists,0,sizeof(Config->implement_lists));\r\r   printf("\n");\r\r this->Res = new DNS(this);\r\r    this->LoadAllModules();\r        /* Just in case no modules were loaded - fix for bug #101 */\r   this->BuildISupport();\r InitializeDisabledCommands(Config->DisabledCommands, this);\r\r   if ((Config->ports.size() == 0) && (found_ports > 0))\r  {\r              printf("\nERROR: I couldn't bind any ports! Are you sure you didn't start InspIRCd twice?\n");\r         Log(DEFAULT,"ERROR: I couldn't bind any ports! Are you sure you didn't start InspIRCd twice?");\r                Exit(EXIT_STATUS_BIND);\r        }\r\r     if (Config->ports.size() != (unsigned int)found_ports)\r {\r              printf("\nWARNING: Not all your client ports could be bound --\nstarting anyway with %d of %d client ports bound.\n\n", bounditems, found_ports);\r              printf("The following port(s) failed to bind:\n");\r             int j = 1;\r             for (FailedPortList::iterator i = pl.begin(); i != pl.end(); i++, j++)\r         {\r                      printf("%d.\tIP: %s\tPort: %lu\n", j, i->first.empty() ? "<all>" : i->first.c_str(), (unsigned long)i->second);\r                }\r      }\r#ifndef WINDOWS\r      if (!Config->nofork)\r   {\r              if (kill(getppid(), SIGTERM) == -1)\r            {\r                      printf("Error killing parent process: %s\n",strerror(errno));\r                  Log(DEFAULT,"Error killing parent process: %s",strerror(errno));\r               }\r      }\r\r     if (isatty(0) && isatty(1) && isatty(2))\r       {\r              /* We didn't start from a TTY, we must have started from a background process -\r                 * e.g. we are restarting, or being launched by cron. Dont kill parent, and dont\r                * close stdin/stdout\r           */\r            if (!do_nofork)\r                {\r                      fclose(stdin);\r                 fclose(stderr);\r                        fclose(stdout);\r                }\r              else\r           {\r                      Log(DEFAULT,"Keeping pseudo-tty open as we are running in the foreground.");\r           }\r      }\r#else\r        InitIPC();\r     if(!Config->nofork)\r    {\r              WindowsForkKillOwner(this);\r            FreeConsole();\r }\r#endif\r       printf("\nInspIRCd is now running!\n");\r        Log(DEFAULT,"Startup complete.");\r\r     this->WritePID(Config->PID);\r}\r\rstd::string InspIRCd::GetVersionString()\r{\r     char versiondata[MAXBUF];\r      char dnsengine[] = "singlethread-object";\r\r     if (*Config->CustomVersion)\r    {\r              snprintf(versiondata,MAXBUF,"%s %s :%s",VERSION,Config->ServerName,Config->CustomVersion);\r     }\r      else\r   {\r              snprintf(versiondata,MAXBUF,"%s %s :%s [FLAGS=%s,%s,%s]",VERSION,Config->ServerName,SYSTEM,REVISION,SE->GetName().c_str(),dnsengine);\r  }\r      return versiondata;\r}\r\rchar* InspIRCd::ModuleError()\r{\r return MODERR;\r}\r\rvoid InspIRCd::EraseFactory(int j)\r{\r int v = 0;\r     for (std::vector<ircd_module*>::iterator t = factory.begin(); t != factory.end(); t++)\r {\r              if (v == j)\r            {\r                      delete *t;\r                     factory.erase(t);\r                      factory.push_back(NULL);\r                       return;\r                }\r              v++;\r   }\r}\r\rvoid InspIRCd::EraseModule(int j)\r{\r       int v1 = 0;\r    for (ModuleList::iterator m = modules.begin(); m!= modules.end(); m++)\r {\r              if (v1 == j)\r           {\r                      DELETE(*m);\r                    modules.erase(m);\r                      modules.push_back(NULL);\r                       break;\r         }\r              v1++;\r  }\r      int v2 = 0;\r    for (std::vector<std::string>::iterator v = Config->module_names.begin(); v != Config->module_names.end(); v++)\r        {\r              if (v2 == j)\r           {\r                      Config->module_names.erase(v);\r                 break;\r         }\r              v2++;\r  }\r\r}\r\rvoid InspIRCd::MoveTo(std::string modulename,int slot)\r{\r unsigned int v2 = 256;\r for (unsigned int v = 0; v < Config->module_names.size(); v++)\r {\r              if (Config->module_names[v] == modulename)\r             {\r                      // found an instance, swap it with the item at the end\r                 v2 = v;\r                        break;\r         }\r      }\r      if ((v2 != (unsigned int)slot) && (v2 < 256))\r  {\r              // Swap the module names over\r          Config->module_names[v2] = Config->module_names[slot];\r         Config->module_names[slot] = modulename;\r               // now swap the module factories\r               ircd_module* temp = factory[v2];\r               factory[v2] = factory[slot];\r           factory[slot] = temp;\r          // now swap the module objects\r         Module* temp_module = modules[v2];\r             modules[v2] = modules[slot];\r           modules[slot] = temp_module;\r           // now swap the implement lists (we dont\r               // need to swap the global or recount it)\r              for (int n = 0; n < 255; n++)\r          {\r                      char x = Config->implement_lists[v2][n];\r                       Config->implement_lists[v2][n] = Config->implement_lists[slot][n];\r                     Config->implement_lists[slot][n] = x;\r          }\r      }\r}\r\rvoid InspIRCd::MoveAfter(std::string modulename, std::string after)\r{\r     for (unsigned int v = 0; v < Config->module_names.size(); v++)\r {\r              if (Config->module_names[v] == after)\r          {\r                      MoveTo(modulename, v);\r                 return;\r                }\r      }\r}\r\rvoid InspIRCd::MoveBefore(std::string modulename, std::string before)\r{\r   for (unsigned int v = 0; v < Config->module_names.size(); v++)\r {\r              if (Config->module_names[v] == before)\r         {\r                      if (v > 0)\r                     {\r                              MoveTo(modulename, v-1);\r                       }\r                      else\r                   {\r                              MoveTo(modulename, v);\r                 }\r                      return;\r                }\r      }\r}\r\rvoid InspIRCd::MoveToFirst(std::string modulename)\r{\r      MoveTo(modulename,0);\r}\r\rvoid InspIRCd::MoveToLast(std::string modulename)\r{\r   MoveTo(modulename,this->GetModuleCount());\r}\r\rvoid InspIRCd::BuildISupport()\r{\r // the neatest way to construct the initial 005 numeric, considering the number of configure constants to go in it...\r  std::stringstream v;\r   v << "WALLCHOPS WALLVOICES MODES=" << MAXMODES-1 << " CHANTYPES=# PREFIX=" << this->Modes->BuildPrefixes() << " MAP MAXCHANNELS=" << Config->MaxChans << " MAXBANS=60 VBANLIST NICKLEN=" << NICKMAX-1;\r v << " CASEMAPPING=rfc1459 STATUSMSG=@%+ CHARSET=ascii TOPICLEN=" << MAXTOPIC << " KICKLEN=" << MAXKICK << " MAXTARGETS=" << Config->MaxTargets << " AWAYLEN=";\r        v << MAXAWAY << " CHANMODES=" << this->Modes->ChanModes() << " FNC NETWORK=" << Config->Network << " MAXPARA=32 ELIST=MU";\r     Config->data005 = v.str();\r     FOREACH_MOD_I(this,I_On005Numeric,On005Numeric(Config->data005));\r      Config->Update005();\r}\r\rbool InspIRCd::UnloadModule(const char* filename)\r{\r    std::string filename_str = filename;\r   for (unsigned int j = 0; j != Config->module_names.size(); j++)\r        {\r              if (Config->module_names[j] == filename_str)\r           {\r                      if (modules[j]->GetVersion().Flags & VF_STATIC)\r                        {\r                              this->Log(DEFAULT,"Failed to unload STATIC module %s",filename);\r                               snprintf(MODERR,MAXBUF,"Module not unloadable (marked static)");\r                               return false;\r                  }\r                      std::pair<int,std::string> intercount = GetInterfaceInstanceCount(modules[j]);\r                 if (intercount.first > 0)\r                      {\r                              this->Log(DEFAULT,"Failed to unload module %s, being used by %d other(s) via interface '%s'",filename, intercount.first, intercount.second.c_str());\r                           snprintf(MODERR,MAXBUF,"Module not unloadable (Still in use by %d other module%s which %s using its interface '%s') -- unload dependent modules first!",\r                                               intercount.first,\r                                              intercount.first > 1 ? "s" : "",\r                                               intercount.first > 1 ? "are" : "is",\r                                           intercount.second.c_str());\r                            return false;\r                  }\r                      /* Give the module a chance to tidy out all its metadata */\r                    for (chan_hash::iterator c = this->chanlist->begin(); c != this->chanlist->end(); c++)\r                 {\r                              modules[j]->OnCleanup(TYPE_CHANNEL,c->second);\r                 }\r                      for (user_hash::iterator u = this->clientlist->begin(); u != this->clientlist->end(); u++)\r                     {\r                              modules[j]->OnCleanup(TYPE_USER,u->second);\r                    }\r\r                     /* Tidy up any dangling resolvers */\r                   this->Res->CleanResolvers(modules[j]);\r\r                        FOREACH_MOD_I(this,I_OnUnloadModule,OnUnloadModule(modules[j],Config->module_names[j]));\r\r                      for(int t = 0; t < 255; t++)\r                   {\r                              Config->global_implementation[t] -= Config->implement_lists[j][t];\r                     }\r\r                     /* We have to renumber implement_lists after unload because the module numbers change!\r                  */\r                    for(int j2 = j; j2 < 254; j2++)\r                        {\r                              for(int t = 0; t < 255; t++)\r                           {\r                                      Config->implement_lists[j2][t] = Config->implement_lists[j2+1][t];\r                             }\r                      }\r\r                     // found the module\r                    Parser->RemoveCommands(filename);\r                      this->EraseModule(j);\r                  this->EraseFactory(j);\r                 this->Log(DEFAULT,"Module %s unloaded",filename);\r                      this->ModCount--;\r                      BuildISupport();\r                       return true;\r           }\r      }\r      this->Log(DEFAULT,"Module %s is not loaded, cannot unload it!",filename);\r      snprintf(MODERR,MAXBUF,"Module not loaded");\r   return false;\r}\r\rbool InspIRCd::LoadModule(const char* filename)\r{\r     /* Do we have a glob pattern in the filename?\r   * The user wants to load multiple modules which\r        * match the pattern.\r   */\r    if (strchr(filename,'*') || (strchr(filename,'?')))\r    {\r              int n_match = 0;\r               DIR* library = opendir(Config->ModPath);\r               if (library)\r           {\r                      /* Try and locate and load all modules matching the pattern */\r                 dirent* entry = NULL;\r                  while ((entry = readdir(library)))\r                     {\r                              if (this->MatchText(entry->d_name, filename))\r                          {\r                                      if (!this->LoadModule(entry->d_name))\r                                          n_match++;\r                             }\r                      }\r                      closedir(library);\r             }\r              /* Loadmodule will now return false if any one of the modules failed\r            * to load (but wont abort when it encounters a bad one) and when 1 or\r          * more modules were actually loaded.\r           */\r            return (n_match > 0);\r  }\r\r     char modfile[MAXBUF];\r  snprintf(modfile,MAXBUF,"%s/%s",Config->ModPath,filename);\r     std::string filename_str = filename;\r\r  if (!ServerConfig::DirValid(modfile))\r  {\r              this->Log(DEFAULT,"Module %s is not within the modules directory.",modfile);\r           snprintf(MODERR,MAXBUF,"Module %s is not within the modules directory.",modfile);\r              return false;\r  }\r      if (ServerConfig::FileExists(modfile))\r {\r\r             for (unsigned int j = 0; j < Config->module_names.size(); j++)\r         {\r                      if (Config->module_names[j] == filename_str)\r                   {\r                              this->Log(DEFAULT,"Module %s is already loaded, cannot load a module twice!",modfile);\r                         snprintf(MODERR,MAXBUF,"Module already loaded");\r                               return false;\r                  }\r              }\r              Module* m = NULL;\r              ircd_module* a = NULL;\r         try\r            {\r                      a = new ircd_module(this, modfile);\r                    factory[this->ModCount+1] = a;\r                 if (factory[this->ModCount+1]->LastError())\r                    {\r                              this->Log(DEFAULT,"Unable to load %s: %s",modfile,factory[this->ModCount+1]->LastError());\r                             snprintf(MODERR,MAXBUF,"Loader/Linker error: %s",factory[this->ModCount+1]->LastError());\r                              return false;\r                  }\r                      if ((long)factory[this->ModCount+1]->factory != -1)\r                    {\r                              m = factory[this->ModCount+1]->factory->CreateModule(this);\r\r                           Version v = m->GetVersion();\r\r                          if (v.API != API_VERSION)\r                              {\r                                      delete m;\r                                      this->Log(DEFAULT,"Unable to load %s: Incorrect module API version: %d (our version: %d)",modfile,v.API,API_VERSION);\r                                  snprintf(MODERR,MAXBUF,"Loader/Linker error: Incorrect module API version: %d (our version: %d)",v.API,API_VERSION);\r                                   return false;\r                          }\r                              else\r                           {\r                                      this->Log(DEFAULT,"New module introduced: %s (API version %d, Module version %d.%d.%d.%d)%s", filename, v.API, v.Major, v.Minor, v.Revision, v.Build, (!(v.Flags & VF_VENDOR) ? " [3rd Party]" : " [Vendor]"));\r                                }\r\r                             modules[this->ModCount+1] = m;\r                         /* save the module and the module's classfactory, if\r                            * this isnt done, random crashes can occur :/ */\r                              Config->module_names.push_back(filename);\r\r                             char* x = &Config->implement_lists[this->ModCount+1][0];\r                               for(int t = 0; t < 255; t++)\r                                   x[t] = 0;\r\r                             modules[this->ModCount+1]->Implements(x);\r\r                             for(int t = 0; t < 255; t++)\r                                   Config->global_implementation[t] += Config->implement_lists[this->ModCount+1][t];\r                      }\r                      else\r                   {\r                              this->Log(DEFAULT,"Unable to load %s",modfile);\r                                snprintf(MODERR,MAXBUF,"Factory function failed: Probably missing init_module() entrypoint.");\r                         return false;\r                  }\r              }\r              catch (CoreException& modexcept)\r               {\r                      this->Log(DEFAULT,"Unable to load %s: %s",modfile,modexcept.GetReason());\r                      snprintf(MODERR,MAXBUF,"Factory function of %s threw an exception: %s", modexcept.GetSource(), modexcept.GetReason());\r                 return false;\r          }\r      }\r      else\r   {\r              this->Log(DEFAULT,"InspIRCd: startup: Module Not Found %s",modfile);\r           snprintf(MODERR,MAXBUF,"Module file could not be found");\r              return false;\r  }\r      this->ModCount++;\r      FOREACH_MOD_I(this,I_OnLoadModule,OnLoadModule(modules[this->ModCount],filename_str));\r // now work out which modules, if any, want to move to the back of the queue,\r  // and if they do, move them there.\r    std::vector<std::string> put_to_back;\r  std::vector<std::string> put_to_front;\r std::map<std::string,std::string> put_before;\r  std::map<std::string,std::string> put_after;\r   for (unsigned int j = 0; j < Config->module_names.size(); j++)\r {\r              if (modules[j]->Prioritize() == PRIORITY_LAST)\r                 put_to_back.push_back(Config->module_names[j]);\r                else if (modules[j]->Prioritize() == PRIORITY_FIRST)\r                   put_to_front.push_back(Config->module_names[j]);\r               else if ((modules[j]->Prioritize() & 0xFF) == PRIORITY_BEFORE)\r                 put_before[Config->module_names[j]] = Config->module_names[modules[j]->Prioritize() >> 8];\r             else if ((modules[j]->Prioritize() & 0xFF) == PRIORITY_AFTER)\r                  put_after[Config->module_names[j]] = Config->module_names[modules[j]->Prioritize() >> 8];\r      }\r      for (unsigned int j = 0; j < put_to_back.size(); j++)\r          MoveToLast(put_to_back[j]);\r    for (unsigned int j = 0; j < put_to_front.size(); j++)\r         MoveToFirst(put_to_front[j]);\r  for (std::map<std::string,std::string>::iterator j = put_before.begin(); j != put_before.end(); j++)\r           MoveBefore(j->first,j->second);\r        for (std::map<std::string,std::string>::iterator j = put_after.begin(); j != put_after.end(); j++)\r             MoveAfter(j->first,j->second);\r BuildISupport();\r       return true;\r}\r\rvoid InspIRCd::DoOneIteration(bool process_module_sockets)\r{\r#ifndef WIN32\r     static rusage ru;\r#else\r        static time_t uptime;\r  static struct tm * stime;\r      static char window_title[100];\r#endif\r\r /* time() seems to be a pretty expensive syscall, so avoid calling it too much.\r         * Once per loop iteration is pleanty.\r  */\r    OLDTIME = TIME;\r        TIME = time(NULL);\r\r    /* Run background module timers every few seconds\r       * (the docs say modules shouldnt rely on accurate\r      * timing using this event, so we dont have to\r  * time this exactly).\r  */\r    if (TIME != OLDTIME)\r   {\r              if (TIME < OLDTIME)\r                    WriteOpers("*** \002EH?!\002 -- Time is flowing BACKWARDS in this dimension! Clock drifted backwards %d secs.",abs(OLDTIME-TIME));\r             if ((TIME % 3600) == 0)\r                {\r                      this->RehashUsersAndChans();\r                   FOREACH_MOD_I(this, I_OnGarbageCollect, OnGarbageCollect());\r           }\r              Timers->TickTimers(TIME);\r              this->DoBackgroundUserStuff(TIME);\r\r            if ((TIME % 5) == 0)\r           {\r                      XLines->expire_lines();\r                        FOREACH_MOD_I(this,I_OnBackgroundTimer,OnBackgroundTimer(TIME));\r                       Timers->TickMissedTimers(TIME);\r                }\r#ifndef WIN32\r                /* Same change as in cmd_stats.cpp, use RUSAGE_SELF rather than '0' -- Om */\r           if (!getrusage(RUSAGE_SELF, &ru))\r              {\r                      gettimeofday(&this->stats->LastSampled, NULL);\r                 this->stats->LastCPU = ru.ru_utime;\r            }\r#else\r                CheckIPC(this);\r\r               if(Config->nofork)\r             {\r                      uptime = Time() - startup_time;\r                        stime = gmtime(&uptime);\r                       snprintf(window_title, 100, "InspIRCd - %u clients, %u accepted connections - Up %u days, %.2u:%.2u:%.2u",\r                             LocalUserCount(), stats->statsAccept, stime->tm_yday, stime->tm_hour, stime->tm_min, stime->tm_sec);\r                   SetConsoleTitle(window_title);\r         }\r#endif\r       }\r\r     /* Call the socket engine to wait on the active\r         * file descriptors. The socket engine has everything's\r         * descriptors in its list... dns, modules, users,\r      * servers... so its nice and easy, just one call.\r      * This will cause any read or write events to be\r       * dispatched to their handlers.\r        */\r    SE->DispatchEvents();\r\r /* if any users was quit, take them out */\r     GlobalCulls.Apply();\r\r  /* If any inspsockets closed, remove them */\r   for (std::map<InspSocket*,InspSocket*>::iterator x = SocketCull.begin(); x != SocketCull.end(); ++x)\r   {\r              SE->DelFd(x->second);\r          x->second->Close();\r            delete x->second;\r      }\r      SocketCull.clear();\r}\r\rint InspIRCd::Run()\r{\r   while (true)\r   {\r              DoOneIteration(true);\r  }\r      /* This is never reached -- we hope! */\r        return 0;\r}\r\r/**********************************************************************************/\r\r/**\r * An ircd in four lines! bwahahaha. ahahahahaha. ahahah *cough*.\r */\r\rint main(int argc, char** argv)\r{\r        SI = new InspIRCd(argc, argv);\r SI->Run();\r     delete SI;\r     return 0;\r}\r\r/* this returns true when all modules are satisfied that the user should be allowed onto the irc server\r * (until this returns true, a user will block in the waiting state, waiting to connect up to the\r * registration timeout maximum seconds)\r */\rbool InspIRCd::AllModulesReportReady(userrec* user)\r{\r      if (!Config->global_implementation[I_OnCheckReady])\r            return true;\r\r  for (int i = 0; i <= this->GetModuleCount(); i++)\r      {\r              if (Config->implement_lists[i][I_OnCheckReady])\r                {\r                      int res = modules[i]->OnCheckReady(user);\r                      if (!res)\r                              return false;\r          }\r      }\r      return true;\r}\r\rint InspIRCd::GetModuleCount()\r{\r       return this->ModCount;\r}\r\rtime_t InspIRCd::Time(bool delta)\r{\r  if (delta)\r             return TIME + time_delta;\r      return TIME;\r}\r\rint InspIRCd::SetTimeDelta(int delta)\r{\r        int old = time_delta;\r  time_delta = delta;\r    this->Log(DEBUG, "Time delta set to %d (was %d)", time_delta, old);\r    return old;\r}\r\rvoid InspIRCd::AddLocalClone(userrec* user)\r{\r   clonemap::iterator x = local_clones.find(user->GetIPString());\r if (x != local_clones.end())\r           x->second++;\r   else\r           local_clones[user->GetIPString()] = 1;\r}\r\rvoid InspIRCd::AddGlobalClone(userrec* user)\r{\r       clonemap::iterator y = global_clones.find(user->GetIPString());\r        if (y != global_clones.end())\r          y->second++;\r   else\r           global_clones[user->GetIPString()] = 1;\r}\r\rint InspIRCd::GetTimeDelta()\r{\r      return time_delta;\r}\r\rbool FileLogger::Readable()\r{\r    return false;\r}\r\rvoid FileLogger::HandleEvent(EventType et, int errornum)\r{\r    this->WriteLogLine("");\r        if (log)\r               ServerInstance->SE->DelFd(this);\r}\r\rvoid FileLogger::WriteLogLine(const std::string &line)\r{\r   if (line.length())\r             buffer.append(line);\r\r  if (log)\r       {\r              int written = fprintf(log,"%s",buffer.c_str());\r#ifdef WINDOWS\r         buffer.clear();\r#else\r          if ((written >= 0) && (written < (int)buffer.length()))\r                {\r                      buffer.erase(0, buffer.length());\r                      ServerInstance->SE->AddFd(this);\r               }\r              else if (written == -1)\r                {\r                      if (errno == EAGAIN)\r                           ServerInstance->SE->AddFd(this);\r               }\r              else\r           {\r                      /* Wrote the whole buffer, and no need for write callback */\r                   buffer.clear();\r                }\r#endif\r               if (writeops++ % 20)\r           {\r                      fflush(log);\r           }\r      }\r}\r\rvoid FileLogger::Close()\r{\r        if (log)\r       {\r              /* Burlex: Windows assumes nonblocking on FILE* pointers anyway, and also "file" fd's aren't the same\r           * as socket fd's. */\r#ifndef WIN32\r            int flags = fcntl(fileno(log), F_GETFL, 0);\r            fcntl(fileno(log), F_SETFL, flags ^ O_NONBLOCK);\r#endif\r                if (buffer.size())\r                     fprintf(log,"%s",buffer.c_str());\r\r#ifndef WINDOWS\r             ServerInstance->SE->DelFd(this);\r#endif\r\r               fflush(log);\r           fclose(log);\r   }\r\r     buffer.clear();\r}\r\rFileLogger::FileLogger(InspIRCd* Instance, FILE* logfile) : ServerInstance(Instance), log(logfile), writeops(0)\r{\r   if (log)\r       {\r              irc::sockets::NonBlocking(fileno(log));\r                this->SetFd(fileno(log));\r              buffer.clear();\r        }\r}\r\rFileLogger::~FileLogger()\r{\r       this->Close();\r}\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "configreader.h"
+#include <signal.h>
+
+#ifndef WIN32
+#include <dirent.h>
+#include <unistd.h>
+#include <sys/resource.h>
+#include <dlfcn.h>
+#include <getopt.h>
+
+/* Some systems don't define RUSAGE_SELF. This should fix them. */
+#ifndef RUSAGE_SELF
+       #define RUSAGE_SELF 0
+#endif
+
+#endif
+
+#include <exception>
+#include <fstream>
+#include "modules.h"
+#include "mode.h"
+#include "xline.h"
+#include "socketengine.h"
+#include "inspircd_se_config.h"
+#include "socket.h"
+#include "typedefs.h"
+#include "command_parse.h"
+#include "exitcodes.h"
+
+#ifdef WIN32
+
+/* This MUST remain static and delcared outside the class, so that WriteProcessMemory can reference it properly */
+static DWORD owner_processid = 0;
+
+DWORD WindowsForkStart(InspIRCd * Instance)
+{
+       /* Windows implementation of fork() :P */
+
+       char module[MAX_PATH];
+       if(!GetModuleFileName(NULL, module, MAX_PATH))
+       {
+               printf("GetModuleFileName() failed.\n");
+               return false;
+       }
+
+       STARTUPINFO startupinfo;
+       PROCESS_INFORMATION procinfo;
+       ZeroMemory(&startupinfo, sizeof(STARTUPINFO));
+       ZeroMemory(&procinfo, sizeof(PROCESS_INFORMATION));
+
+       // Fill in the startup info struct
+       GetStartupInfo(&startupinfo);
+
+       /* Default creation flags create the processes suspended */
+       DWORD startupflags = CREATE_SUSPENDED;
+
+       /* On windows 2003/XP and above, we can use the value
+        * CREATE_PRESERVE_CODE_AUTHZ_LEVEL which gives more access
+        * to the process which we may require on these operating systems.
+        */
+       OSVERSIONINFO vi;
+       vi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+       GetVersionEx(&vi);
+       if ((vi.dwMajorVersion >= 5) && (vi.dwMinorVersion > 0))
+               startupflags |= CREATE_PRESERVE_CODE_AUTHZ_LEVEL;
+
+       // Launch our "forked" process.
+       BOOL bSuccess = CreateProcess ( module, // Module (exe) filename
+               strdup(GetCommandLine()),       // Command line (exe plus parameters from the OS)
+                                               // NOTE: We cannot return the direct value of the
+                                               // GetCommandLine function here, as the pointer is
+                                               // passed straight to the child process, and will be
+                                               // invalid once we exit as it goes out of context.
+                                               // strdup() seems ok, though.
+               0,                              // PROCESS_SECURITY_ATTRIBUTES
+               0,                              // THREAD_SECURITY_ATTRIBUTES
+               TRUE,                           // We went to inherit handles.
+               startupflags,                   // Allow us full access to the process and suspend it.
+               0,                              // ENVIRONMENT
+               0,                              // CURRENT_DIRECTORY
+               &startupinfo,                   // startup info
+               &procinfo);                     // process info
+
+       if(!bSuccess)
+       {
+               printf("CreateProcess() error: %s\n", dlerror());
+               return false;
+       }
+
+       // Set the owner process id in the target process.
+       SIZE_T written = 0;
+       DWORD pid = GetCurrentProcessId();
+       if(!WriteProcessMemory(procinfo.hProcess, &owner_processid, &pid, sizeof(DWORD), &written) || written != sizeof(DWORD))
+       {
+               printf("WriteProcessMemory() failed: %s\n", dlerror());
+               return false;
+       }
+
+       // Resume the other thread (let it start)
+       ResumeThread(procinfo.hThread);
+
+       // Wait for the new process to kill us. If there is some error, the new process will end and we will end up at the next line.
+       WaitForSingleObject(procinfo.hProcess, INFINITE);
+
+       // If we hit this it means startup failed, default to 14 if this fails.
+       DWORD ExitCode = 14;
+       GetExitCodeProcess(procinfo.hProcess, &ExitCode);
+       CloseHandle(procinfo.hThread);
+       CloseHandle(procinfo.hProcess);
+       return ExitCode;
+}
+
+void WindowsForkKillOwner(InspIRCd * Instance)
+{
+       HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, owner_processid);
+       if(!hProcess || !owner_processid)
+       {
+               printf("Could not open process id %u: %s.\n", owner_processid, dlerror());
+               Instance->Exit(14);
+       }
+
+       // die die die
+       if(!TerminateProcess(hProcess, 0))
+       {
+               printf("Could not TerminateProcess(): %s\n", dlerror());
+               Instance->Exit(14);
+       }
+
+       CloseHandle(hProcess);
+}
+
+#endif
+
+using irc::sockets::NonBlocking;
+using irc::sockets::Blocking;
+using irc::sockets::insp_ntoa;
+using irc::sockets::insp_inaddr;
+using irc::sockets::insp_sockaddr;
+
+InspIRCd* SI = NULL;
+
+/* Burlex: Moved from exitcodes.h -- due to duplicate symbols */
+const char* ExitCodes[] =
+{
+               "No error", /* 0 */
+               "DIE command", /* 1 */
+               "execv() failed", /* 2 */
+               "Internal error", /* 3 */
+               "Config file error", /* 4 */
+               "Logfile error", /* 5 */
+               "POSIX fork failed", /* 6 */
+               "Bad commandline parameters", /* 7 */
+               "No ports could be bound", /* 8 */
+               "Can't write PID file", /* 9 */
+               "SocketEngine could not initialize", /* 10 */
+               "Refusing to start up as root", /* 11 */
+               "Found a <die> tag!", /* 12 */
+               "Couldn't load module on startup", /* 13 */
+               "Could not create windows forked process", /* 14 */
+               "Received SIGTERM", /* 15 */
+};
+
+void InspIRCd::AddServerName(const std::string &servername)
+{
+       servernamelist::iterator itr = servernames.begin();
+       for(; itr != servernames.end(); ++itr)
+               if(**itr == servername)
+                       return;
+
+       string * ns = new string(servername);
+       servernames.push_back(ns);
+}
+
+const char* InspIRCd::FindServerNamePtr(const std::string &servername)
+{
+       servernamelist::iterator itr = servernames.begin();
+       for(; itr != servernames.end(); ++itr)
+               if(**itr == servername)
+                       return (*itr)->c_str();
+
+       servernames.push_back(new string(servername));
+       itr = --servernames.end();
+       return (*itr)->c_str();
+}
+
+bool InspIRCd::FindServerName(const std::string &servername)
+{
+       servernamelist::iterator itr = servernames.begin();
+       for(; itr != servernames.end(); ++itr)
+               if(**itr == servername)
+                       return true;
+       return false;
+}
+
+void InspIRCd::Exit(int status)
+{
+#ifdef WINDOWS
+       CloseIPC();
+#endif
+       if (SI)
+       {
+               SI->SendError("Exiting with status " + ConvToStr(status) + " (" + std::string(ExitCodes[status]) + ")");
+               SI->Cleanup();
+       }
+       exit (status);
+}
+
+void InspIRCd::Cleanup()
+{
+       std::vector<std::string> mymodnames;
+       int MyModCount = this->GetModuleCount();
+
+       for (unsigned int i = 0; i < Config->ports.size(); i++)
+       {
+               /* This calls the constructor and closes the listening socket */
+               delete Config->ports[i];
+       }
+
+       Config->ports.clear();
+
+       /* Close all client sockets, or the new process inherits them */
+       for (std::vector<userrec*>::const_iterator i = this->local_users.begin(); i != this->local_users.end(); i++)
+       {
+               (*i)->SetWriteError("Server shutdown");
+               (*i)->CloseSocket();
+       }
+
+       /* We do this more than once, so that any service providers get a
+        * chance to be unhooked by the modules using them, but then get
+        * a chance to be removed themsleves.
+        */
+       for (int tries = 0; tries < 3; tries++)
+       {
+               MyModCount = this->GetModuleCount();
+               mymodnames.clear();
+
+               /* Unload all modules, so they get a chance to clean up their listeners */
+               for (int j = 0; j <= MyModCount; j++)
+                       mymodnames.push_back(Config->module_names[j]);
+
+               for (int k = 0; k <= MyModCount; k++)
+                       this->UnloadModule(mymodnames[k].c_str());
+       }
+
+       /* Close logging */
+       this->Logger->Close();
+
+       /* Cleanup Server Names */
+       for(servernamelist::iterator itr = servernames.begin(); itr != servernames.end(); ++itr)
+               delete (*itr);
+
+#ifdef WINDOWS
+       /* WSACleanup */
+       WSACleanup();
+#endif
+}
+
+void InspIRCd::Restart(const std::string &reason)
+{
+       /* SendError flushes each client's queue,
+        * regardless of writeability state
+        */
+       this->SendError(reason);
+
+       this->Cleanup();
+
+       /* Figure out our filename (if theyve renamed it, we're boned) */
+       std::string me;
+
+#ifdef WINDOWS
+       char module[MAX_PATH];
+       if (GetModuleFileName(NULL, module, MAX_PATH))
+               me = module;
+#else
+       me = Config->MyDir + "/inspircd";
+#endif
+
+       if (execv(me.c_str(), Config->argv) == -1)
+       {
+               /* Will raise a SIGABRT if not trapped */
+               throw CoreException(std::string("Failed to execv()! error: ") + strerror(errno));
+       }
+}
+
+void InspIRCd::Start()
+{
+       printf_c("\033[1;32mInspire Internet Relay Chat Server, compiled %s at %s\n",__DATE__,__TIME__);
+       printf_c("(C) InspIRCd Development Team.\033[0m\n\n");
+       printf_c("Developers:\t\t\033[1;32mBrain, FrostyCoolSlug, w00t, Om, Special, pippijn, peavey, Burlex\033[0m\n");
+       printf_c("Others:\t\t\t\033[1;32mSee /INFO Output\033[0m\n");
+}
+
+void InspIRCd::Rehash(int status)
+{
+       SI->WriteOpers("*** Rehashing config file %s due to SIGHUP",ServerConfig::CleanFilename(SI->ConfigFileName));
+       SI->CloseLog();
+       SI->OpenLog(SI->Config->argv, SI->Config->argc);
+       SI->RehashUsersAndChans();
+       FOREACH_MOD_I(SI, I_OnGarbageCollect, OnGarbageCollect());
+       SI->Config->Read(false,NULL);
+       SI->ResetMaxBans();
+       SI->Res->Rehash();
+       FOREACH_MOD_I(SI,I_OnRehash,OnRehash(NULL,""));
+       SI->BuildISupport();
+}
+
+void InspIRCd::ResetMaxBans()
+{
+       for (chan_hash::const_iterator i = chanlist->begin(); i != chanlist->end(); i++)
+               i->second->ResetMaxBans();
+}
+
+
+/** Because hash_map doesnt free its buckets when we delete items (this is a 'feature')
+ * we must occasionally rehash the hash (yes really).
+ * We do this by copying the entries from the old hash to a new hash, causing all
+ * empty buckets to be weeded out of the hash. We dont do this on a timer, as its
+ * very expensive, so instead we do it when the user types /REHASH and expects a
+ * short delay anyway.
+ */
+void InspIRCd::RehashUsersAndChans()
+{
+       user_hash* old_users = this->clientlist;
+       chan_hash* old_chans = this->chanlist;
+
+       this->clientlist = new user_hash();
+       this->chanlist = new chan_hash();
+
+       for (user_hash::const_iterator n = old_users->begin(); n != old_users->end(); n++)
+               this->clientlist->insert(*n);
+
+       delete old_users;
+
+       for (chan_hash::const_iterator n = old_chans->begin(); n != old_chans->end(); n++)
+               this->chanlist->insert(*n);
+
+       delete old_chans;
+}
+
+void InspIRCd::CloseLog()
+{
+       this->Logger->Close();
+}
+
+void InspIRCd::SetSignals()
+{
+#ifndef WIN32
+       signal(SIGALRM, SIG_IGN);
+       signal(SIGHUP, InspIRCd::Rehash);
+       signal(SIGPIPE, SIG_IGN);
+       signal(SIGCHLD, SIG_IGN);
+#endif
+       signal(SIGTERM, InspIRCd::Exit);
+}
+
+void InspIRCd::QuickExit(int status)
+{
+       exit(0);
+}
+
+bool InspIRCd::DaemonSeed()
+{
+#ifdef WINDOWS
+       printf_c("InspIRCd Process ID: \033[1;32m%lu\033[0m\n", GetCurrentProcessId());
+       return true;
+#else
+       signal(SIGTERM, InspIRCd::QuickExit);
+
+       int childpid;
+       if ((childpid = fork ()) < 0)
+               return false;
+       else if (childpid > 0)
+       {
+               /* We wait here for the child process to kill us,
+                * so that the shell prompt doesnt come back over
+                * the output.
+                * Sending a kill with a signal of 0 just checks
+                * if the child pid is still around. If theyre not,
+                * they threw an error and we should give up.
+                */
+               while (kill(childpid, 0) != -1)
+                       sleep(1);
+               exit(0);
+       }
+       setsid ();
+       umask (007);
+       printf("InspIRCd Process ID: \033[1;32m%lu\033[0m\n",(unsigned long)getpid());
+
+       signal(SIGTERM, InspIRCd::Exit);
+
+       rlimit rl;
+       if (getrlimit(RLIMIT_CORE, &rl) == -1)
+       {
+               this->Log(DEFAULT,"Failed to getrlimit()!");
+               return false;
+       }
+       else
+       {
+               rl.rlim_cur = rl.rlim_max;
+               if (setrlimit(RLIMIT_CORE, &rl) == -1)
+                       this->Log(DEFAULT,"setrlimit() failed, cannot increase coredump size.");
+       }
+
+       return true;
+#endif
+}
+
+void InspIRCd::WritePID(const std::string &filename)
+{
+       std::string fname = (filename.empty() ? "inspircd.pid" : filename);
+       if (*(fname.begin()) != '/')
+       {
+               std::string::size_type pos;
+               std::string confpath = this->ConfigFileName;
+               if ((pos = confpath.rfind("/")) != std::string::npos)
+               {
+                       /* Leaves us with just the path */
+                       fname = confpath.substr(0, pos) + std::string("/") + fname;
+               }
+       }
+       std::ofstream outfile(fname.c_str());
+       if (outfile.is_open())
+       {
+               outfile << getpid();
+               outfile.close();
+       }
+       else
+       {
+               printf("Failed to write PID-file '%s', exiting.\n",fname.c_str());
+               this->Log(DEFAULT,"Failed to write PID-file '%s', exiting.",fname.c_str());
+               Exit(EXIT_STATUS_PID);
+       }
+}
+
+std::string InspIRCd::GetRevision()
+{
+       return REVISION;
+}
+
+InspIRCd::InspIRCd(int argc, char** argv)
+       : ModCount(-1), GlobalCulls(this)
+{
+       int found_ports = 0;
+       FailedPortList pl;
+       int do_version = 0, do_nofork = 0, do_debug = 0, do_nolog = 0, do_root = 0;    /* flag variables */
+       char c = 0;
+
+       modules.resize(255);
+       factory.resize(255);
+       memset(&server, 0, sizeof(server));
+       memset(&client, 0, sizeof(client));
+
+       this->unregistered_count = 0;
+
+       this->clientlist = new user_hash();
+       this->chanlist = new chan_hash();
+
+       this->Config = new ServerConfig(this);
+
+       this->Config->argv = argv;
+       this->Config->argc = argc;
+
+       chdir(Config->GetFullProgDir().c_str());
+
+       this->Config->opertypes.clear();
+       this->Config->operclass.clear();
+       this->SNO = new SnomaskManager(this);
+       this->TIME = this->OLDTIME = this->startup_time = time(NULL);
+       this->time_delta = 0;
+       this->next_call = this->TIME + 3;
+       srand(this->TIME);
+
+       *this->LogFileName = 0;
+       strlcpy(this->ConfigFileName, CONFIG_FILE, MAXBUF);
+
+       struct option longopts[] =
+       {
+               { "nofork",     no_argument,            &do_nofork,     1       },
+               { "logfile",    required_argument,      NULL,           'f'     },
+               { "config",     required_argument,      NULL,           'c'     },
+               { "debug",      no_argument,            &do_debug,      1       },
+               { "nolog",      no_argument,            &do_nolog,      1       },
+               { "runasroot",  no_argument,            &do_root,       1       },
+               { "version",    no_argument,            &do_version,    1       },
+               { 0, 0, 0, 0 }
+       };
+
+       while ((c = getopt_long_only(argc, argv, ":f:", longopts, NULL)) != -1)
+       {
+               switch (c)
+               {
+                       case 'f':
+                               /* Log filename was set */
+                               strlcpy(LogFileName, optarg, MAXBUF);
+                       break;
+                       case 'c':
+                               /* Config filename was set */
+                               strlcpy(ConfigFileName, optarg, MAXBUF);
+                       break;
+                       case 0:
+                               /* getopt_long_only() set an int variable, just keep going */
+                       break;
+                       default:
+                               /* Unknown parameter! DANGER, INTRUDER.... err.... yeah. */
+                               printf("Usage: %s [--nofork] [--nolog] [--debug] [--logfile <filename>] [--runasroot] [--version] [--config <config>]\n", argv[0]);
+                               Exit(EXIT_STATUS_ARGV);
+                       break;
+               }
+       }
+
+       if (do_version)
+       {
+               printf("\n%s r%s\n", VERSION, REVISION);
+               Exit(EXIT_STATUS_NOERROR);
+       }
+
+#ifdef WIN32
+
+       // Handle forking
+       if(!do_nofork && !owner_processid)
+       {
+               DWORD ExitCode = WindowsForkStart(this);
+               if(ExitCode)
+                       Exit(ExitCode);
+       }
+
+       // Set up winsock
+       WSADATA wsadata;
+       WSAStartup(MAKEWORD(2,0), &wsadata);
+
+#endif
+       if (!ServerConfig::FileExists(this->ConfigFileName))
+       {
+               printf("ERROR: Cannot open config file: %s\nExiting...\n", this->ConfigFileName);
+               this->Log(DEFAULT,"Unable to open config file %s", this->ConfigFileName);
+               Exit(EXIT_STATUS_CONFIG);
+       }
+
+       this->Start();
+
+       /* Set the finished argument values */
+       Config->nofork = do_nofork;
+       Config->forcedebug = do_debug;
+       Config->writelog = !do_nolog;
+
+       strlcpy(Config->MyExecutable,argv[0],MAXBUF);
+
+       this->OpenLog(argv, argc);
+
+       this->stats = new serverstats();
+       this->Timers = new TimerManager(this);
+       this->Parser = new CommandParser(this);
+       this->XLines = new XLineManager(this);
+       Config->ClearStack();
+       Config->Read(true, NULL);
+
+       if (!do_root)
+               this->CheckRoot();
+       else
+       {
+               printf("* WARNING * WARNING * WARNING * WARNING * WARNING * \n\n");
+               printf("YOU ARE RUNNING INSPIRCD AS ROOT. THIS IS UNSUPPORTED\n");
+               printf("AND IF YOU ARE HACKED, CRACKED, SPINDLED OR MUTILATED\n");
+               printf("OR ANYTHING ELSE UNEXPECTED HAPPENS TO YOU OR YOUR\n");
+               printf("SERVER, THEN IT IS YOUR OWN FAULT. IF YOU DID NOT MEAN\n");
+               printf("TO START INSPIRCD AS ROOT, HIT CTRL+C NOW AND RESTART\n");
+               printf("THE PROGRAM AS A NORMAL USER. YOU HAVE BEEN WARNED!\n");
+               printf("\nInspIRCd starting in 20 seconds, ctrl+c to abort...\n");
+               sleep(20);
+       }
+
+       this->SetSignals();
+
+       if (!Config->nofork)
+       {
+               if (!this->DaemonSeed())
+               {
+                       printf("ERROR: could not go into daemon mode. Shutting down.\n");
+                       Log(DEFAULT,"ERROR: could not go into daemon mode. Shutting down.");
+                       Exit(EXIT_STATUS_FORK);
+               }
+       }
+
+
+       /* Because of limitations in kqueue on freebsd, we must fork BEFORE we
+        * initialize the socket engine.
+        */
+       SocketEngineFactory* SEF = new SocketEngineFactory();
+       SE = SEF->Create(this);
+       delete SEF;
+
+       this->Modes = new ModeParser(this);
+       this->AddServerName(Config->ServerName);
+       CheckDie();
+       int bounditems = BindPorts(true, found_ports, pl);
+
+       for(int t = 0; t < 255; t++)
+               Config->global_implementation[t] = 0;
+
+       memset(&Config->implement_lists,0,sizeof(Config->implement_lists));
+
+       printf("\n");
+
+       this->Res = new DNS(this);
+
+       this->LoadAllModules();
+       /* Just in case no modules were loaded - fix for bug #101 */
+       this->BuildISupport();
+       InitializeDisabledCommands(Config->DisabledCommands, this);
+
+       if ((Config->ports.size() == 0) && (found_ports > 0))
+       {
+               printf("\nERROR: I couldn't bind any ports! Are you sure you didn't start InspIRCd twice?\n");
+               Log(DEFAULT,"ERROR: I couldn't bind any ports! Are you sure you didn't start InspIRCd twice?");
+               Exit(EXIT_STATUS_BIND);
+       }
+
+       if (Config->ports.size() != (unsigned int)found_ports)
+       {
+               printf("\nWARNING: Not all your client ports could be bound --\nstarting anyway with %d of %d client ports bound.\n\n", bounditems, found_ports);
+               printf("The following port(s) failed to bind:\n");
+               int j = 1;
+               for (FailedPortList::iterator i = pl.begin(); i != pl.end(); i++, j++)
+               {
+                       printf("%d.\tIP: %s\tPort: %lu\n", j, i->first.empty() ? "<all>" : i->first.c_str(), (unsigned long)i->second);
+               }
+       }
+#ifndef WINDOWS
+       if (!Config->nofork)
+       {
+               if (kill(getppid(), SIGTERM) == -1)
+               {
+                       printf("Error killing parent process: %s\n",strerror(errno));
+                       Log(DEFAULT,"Error killing parent process: %s",strerror(errno));
+               }
+       }
+
+       if (isatty(0) && isatty(1) && isatty(2))
+       {
+               /* We didn't start from a TTY, we must have started from a background process -
+                * e.g. we are restarting, or being launched by cron. Dont kill parent, and dont
+                * close stdin/stdout
+                */
+               if (!do_nofork)
+               {
+                       fclose(stdin);
+                       fclose(stderr);
+                       fclose(stdout);
+               }
+               else
+               {
+                       Log(DEFAULT,"Keeping pseudo-tty open as we are running in the foreground.");
+               }
+       }
+#else
+       InitIPC();
+       if(!Config->nofork)
+       {
+               WindowsForkKillOwner(this);
+               FreeConsole();
+       }
+#endif
+       printf("\nInspIRCd is now running!\n");
+       Log(DEFAULT,"Startup complete.");
+
+       this->WritePID(Config->PID);
+}
+
+std::string InspIRCd::GetVersionString()
+{
+       char versiondata[MAXBUF];
+       char dnsengine[] = "singlethread-object";
+
+       if (*Config->CustomVersion)
+       {
+               snprintf(versiondata,MAXBUF,"%s %s :%s",VERSION,Config->ServerName,Config->CustomVersion);
+       }
+       else
+       {
+               snprintf(versiondata,MAXBUF,"%s %s :%s [FLAGS=%s,%s,%s]",VERSION,Config->ServerName,SYSTEM,REVISION,SE->GetName().c_str(),dnsengine);
+       }
+       return versiondata;
+}
+
+char* InspIRCd::ModuleError()
+{
+       return MODERR;
+}
+
+void InspIRCd::EraseFactory(int j)
+{
+       int v = 0;
+       for (std::vector<ircd_module*>::iterator t = factory.begin(); t != factory.end(); t++)
+       {
+               if (v == j)
+               {
+                       delete *t;
+                       factory.erase(t);
+                       factory.push_back(NULL);
+                       return;
+               }
+               v++;
+       }
+}
+
+void InspIRCd::EraseModule(int j)
+{
+       int v1 = 0;
+       for (ModuleList::iterator m = modules.begin(); m!= modules.end(); m++)
+       {
+               if (v1 == j)
+               {
+                       DELETE(*m);
+                       modules.erase(m);
+                       modules.push_back(NULL);
+                       break;
+               }
+               v1++;
+       }
+       int v2 = 0;
+       for (std::vector<std::string>::iterator v = Config->module_names.begin(); v != Config->module_names.end(); v++)
+       {
+               if (v2 == j)
+               {
+                       Config->module_names.erase(v);
+                       break;
+               }
+               v2++;
+       }
+
+}
+
+void InspIRCd::MoveTo(std::string modulename,int slot)
+{
+       unsigned int v2 = 256;
+       for (unsigned int v = 0; v < Config->module_names.size(); v++)
+       {
+               if (Config->module_names[v] == modulename)
+               {
+                       // found an instance, swap it with the item at the end
+                       v2 = v;
+                       break;
+               }
+       }
+       if ((v2 != (unsigned int)slot) && (v2 < 256))
+       {
+               // Swap the module names over
+               Config->module_names[v2] = Config->module_names[slot];
+               Config->module_names[slot] = modulename;
+               // now swap the module factories
+               ircd_module* temp = factory[v2];
+               factory[v2] = factory[slot];
+               factory[slot] = temp;
+               // now swap the module objects
+               Module* temp_module = modules[v2];
+               modules[v2] = modules[slot];
+               modules[slot] = temp_module;
+               // now swap the implement lists (we dont
+               // need to swap the global or recount it)
+               for (int n = 0; n < 255; n++)
+               {
+                       char x = Config->implement_lists[v2][n];
+                       Config->implement_lists[v2][n] = Config->implement_lists[slot][n];
+                       Config->implement_lists[slot][n] = x;
+               }
+       }
+}
+
+void InspIRCd::MoveAfter(std::string modulename, std::string after)
+{
+       for (unsigned int v = 0; v < Config->module_names.size(); v++)
+       {
+               if (Config->module_names[v] == after)
+               {
+                       MoveTo(modulename, v);
+                       return;
+               }
+       }
+}
+
+void InspIRCd::MoveBefore(std::string modulename, std::string before)
+{
+       for (unsigned int v = 0; v < Config->module_names.size(); v++)
+       {
+               if (Config->module_names[v] == before)
+               {
+                       if (v > 0)
+                       {
+                               MoveTo(modulename, v-1);
+                       }
+                       else
+                       {
+                               MoveTo(modulename, v);
+                       }
+                       return;
+               }
+       }
+}
+
+void InspIRCd::MoveToFirst(std::string modulename)
+{
+       MoveTo(modulename,0);
+}
+
+void InspIRCd::MoveToLast(std::string modulename)
+{
+       MoveTo(modulename,this->GetModuleCount());
+}
+
+void InspIRCd::BuildISupport()
+{
+       // the neatest way to construct the initial 005 numeric, considering the number of configure constants to go in it...
+       std::stringstream v;
+       v << "WALLCHOPS WALLVOICES MODES=" << MAXMODES-1 << " CHANTYPES=# PREFIX=" << this->Modes->BuildPrefixes() << " MAP MAXCHANNELS=" << Config->MaxChans << " MAXBANS=60 VBANLIST NICKLEN=" << NICKMAX-1;
+       v << " CASEMAPPING=rfc1459 STATUSMSG=@%+ CHARSET=ascii TOPICLEN=" << MAXTOPIC << " KICKLEN=" << MAXKICK << " MAXTARGETS=" << Config->MaxTargets << " AWAYLEN=";
+       v << MAXAWAY << " CHANMODES=" << this->Modes->ChanModes() << " FNC NETWORK=" << Config->Network << " MAXPARA=32 ELIST=MU";
+       Config->data005 = v.str();
+       FOREACH_MOD_I(this,I_On005Numeric,On005Numeric(Config->data005));
+       Config->Update005();
+}
+
+bool InspIRCd::UnloadModule(const char* filename)
+{
+       std::string filename_str = filename;
+       for (unsigned int j = 0; j != Config->module_names.size(); j++)
+       {
+               if (Config->module_names[j] == filename_str)
+               {
+                       if (modules[j]->GetVersion().Flags & VF_STATIC)
+                       {
+                               this->Log(DEFAULT,"Failed to unload STATIC module %s",filename);
+                               snprintf(MODERR,MAXBUF,"Module not unloadable (marked static)");
+                               return false;
+                       }
+                       std::pair<int,std::string> intercount = GetInterfaceInstanceCount(modules[j]);
+                       if (intercount.first > 0)
+                       {
+                               this->Log(DEFAULT,"Failed to unload module %s, being used by %d other(s) via interface '%s'",filename, intercount.first, intercount.second.c_str());
+                               snprintf(MODERR,MAXBUF,"Module not unloadable (Still in use by %d other module%s which %s using its interface '%s') -- unload dependent modules first!",
+                                               intercount.first,
+                                               intercount.first > 1 ? "s" : "",
+                                               intercount.first > 1 ? "are" : "is",
+                                               intercount.second.c_str());
+                               return false;
+                       }
+                       /* Give the module a chance to tidy out all its metadata */
+                       for (chan_hash::iterator c = this->chanlist->begin(); c != this->chanlist->end(); c++)
+                       {
+                               modules[j]->OnCleanup(TYPE_CHANNEL,c->second);
+                       }
+                       for (user_hash::iterator u = this->clientlist->begin(); u != this->clientlist->end(); u++)
+                       {
+                               modules[j]->OnCleanup(TYPE_USER,u->second);
+                       }
+
+                       /* Tidy up any dangling resolvers */
+                       this->Res->CleanResolvers(modules[j]);
+
+                       FOREACH_MOD_I(this,I_OnUnloadModule,OnUnloadModule(modules[j],Config->module_names[j]));
+
+                       for(int t = 0; t < 255; t++)
+                       {
+                               Config->global_implementation[t] -= Config->implement_lists[j][t];
+                       }
+
+                       /* We have to renumber implement_lists after unload because the module numbers change!
+                        */
+                       for(int j2 = j; j2 < 254; j2++)
+                       {
+                               for(int t = 0; t < 255; t++)
+                               {
+                                       Config->implement_lists[j2][t] = Config->implement_lists[j2+1][t];
+                               }
+                       }
+
+                       // found the module
+                       Parser->RemoveCommands(filename);
+                       this->EraseModule(j);
+                       this->EraseFactory(j);
+                       this->Log(DEFAULT,"Module %s unloaded",filename);
+                       this->ModCount--;
+                       BuildISupport();
+                       return true;
+               }
+       }
+       this->Log(DEFAULT,"Module %s is not loaded, cannot unload it!",filename);
+       snprintf(MODERR,MAXBUF,"Module not loaded");
+       return false;
+}
+
+bool InspIRCd::LoadModule(const char* filename)
+{
+       /* Do we have a glob pattern in the filename?
+        * The user wants to load multiple modules which
+        * match the pattern.
+        */
+       if (strchr(filename,'*') || (strchr(filename,'?')))
+       {
+               int n_match = 0;
+               DIR* library = opendir(Config->ModPath);
+               if (library)
+               {
+                       /* Try and locate and load all modules matching the pattern */
+                       dirent* entry = NULL;
+                       while ((entry = readdir(library)))
+                       {
+                               if (this->MatchText(entry->d_name, filename))
+                               {
+                                       if (!this->LoadModule(entry->d_name))
+                                               n_match++;
+                               }
+                       }
+                       closedir(library);
+               }
+               /* Loadmodule will now return false if any one of the modules failed
+                * to load (but wont abort when it encounters a bad one) and when 1 or
+                * more modules were actually loaded.
+                */
+               return (n_match > 0);
+       }
+
+       char modfile[MAXBUF];
+       snprintf(modfile,MAXBUF,"%s/%s",Config->ModPath,filename);
+       std::string filename_str = filename;
+
+       if (!ServerConfig::DirValid(modfile))
+       {
+               this->Log(DEFAULT,"Module %s is not within the modules directory.",modfile);
+               snprintf(MODERR,MAXBUF,"Module %s is not within the modules directory.",modfile);
+               return false;
+       }
+       if (ServerConfig::FileExists(modfile))
+       {
+
+               for (unsigned int j = 0; j < Config->module_names.size(); j++)
+               {
+                       if (Config->module_names[j] == filename_str)
+                       {
+                               this->Log(DEFAULT,"Module %s is already loaded, cannot load a module twice!",modfile);
+                               snprintf(MODERR,MAXBUF,"Module already loaded");
+                               return false;
+                       }
+               }
+               Module* m = NULL;
+               ircd_module* a = NULL;
+               try
+               {
+                       a = new ircd_module(this, modfile);
+                       factory[this->ModCount+1] = a;
+                       if (factory[this->ModCount+1]->LastError())
+                       {
+                               this->Log(DEFAULT,"Unable to load %s: %s",modfile,factory[this->ModCount+1]->LastError());
+                               snprintf(MODERR,MAXBUF,"Loader/Linker error: %s",factory[this->ModCount+1]->LastError());
+                               return false;
+                       }
+                       if ((long)factory[this->ModCount+1]->factory != -1)
+                       {
+                               m = factory[this->ModCount+1]->factory->CreateModule(this);
+
+                               Version v = m->GetVersion();
+
+                               if (v.API != API_VERSION)
+                               {
+                                       delete m;
+                                       this->Log(DEFAULT,"Unable to load %s: Incorrect module API version: %d (our version: %d)",modfile,v.API,API_VERSION);
+                                       snprintf(MODERR,MAXBUF,"Loader/Linker error: Incorrect module API version: %d (our version: %d)",v.API,API_VERSION);
+                                       return false;
+                               }
+                               else
+                               {
+                                       this->Log(DEFAULT,"New module introduced: %s (API version %d, Module version %d.%d.%d.%d)%s", filename, v.API, v.Major, v.Minor, v.Revision, v.Build, (!(v.Flags & VF_VENDOR) ? " [3rd Party]" : " [Vendor]"));
+                               }
+
+                               modules[this->ModCount+1] = m;
+                               /* save the module and the module's classfactory, if
+                                * this isnt done, random crashes can occur :/ */
+                               Config->module_names.push_back(filename);
+
+                               char* x = &Config->implement_lists[this->ModCount+1][0];
+                               for(int t = 0; t < 255; t++)
+                                       x[t] = 0;
+
+                               modules[this->ModCount+1]->Implements(x);
+
+                               for(int t = 0; t < 255; t++)
+                                       Config->global_implementation[t] += Config->implement_lists[this->ModCount+1][t];
+                       }
+                       else
+                       {
+                               this->Log(DEFAULT,"Unable to load %s",modfile);
+                               snprintf(MODERR,MAXBUF,"Factory function failed: Probably missing init_module() entrypoint.");
+                               return false;
+                       }
+               }
+               catch (CoreException& modexcept)
+               {
+                       this->Log(DEFAULT,"Unable to load %s: %s",modfile,modexcept.GetReason());
+                       snprintf(MODERR,MAXBUF,"Factory function of %s threw an exception: %s", modexcept.GetSource(), modexcept.GetReason());
+                       return false;
+               }
+       }
+       else
+       {
+               this->Log(DEFAULT,"InspIRCd: startup: Module Not Found %s",modfile);
+               snprintf(MODERR,MAXBUF,"Module file could not be found");
+               return false;
+       }
+       this->ModCount++;
+       FOREACH_MOD_I(this,I_OnLoadModule,OnLoadModule(modules[this->ModCount],filename_str));
+       // now work out which modules, if any, want to move to the back of the queue,
+       // and if they do, move them there.
+       std::vector<std::string> put_to_back;
+       std::vector<std::string> put_to_front;
+       std::map<std::string,std::string> put_before;
+       std::map<std::string,std::string> put_after;
+       for (unsigned int j = 0; j < Config->module_names.size(); j++)
+       {
+               if (modules[j]->Prioritize() == PRIORITY_LAST)
+                       put_to_back.push_back(Config->module_names[j]);
+               else if (modules[j]->Prioritize() == PRIORITY_FIRST)
+                       put_to_front.push_back(Config->module_names[j]);
+               else if ((modules[j]->Prioritize() & 0xFF) == PRIORITY_BEFORE)
+                       put_before[Config->module_names[j]] = Config->module_names[modules[j]->Prioritize() >> 8];
+               else if ((modules[j]->Prioritize() & 0xFF) == PRIORITY_AFTER)
+                       put_after[Config->module_names[j]] = Config->module_names[modules[j]->Prioritize() >> 8];
+       }
+       for (unsigned int j = 0; j < put_to_back.size(); j++)
+               MoveToLast(put_to_back[j]);
+       for (unsigned int j = 0; j < put_to_front.size(); j++)
+               MoveToFirst(put_to_front[j]);
+       for (std::map<std::string,std::string>::iterator j = put_before.begin(); j != put_before.end(); j++)
+               MoveBefore(j->first,j->second);
+       for (std::map<std::string,std::string>::iterator j = put_after.begin(); j != put_after.end(); j++)
+               MoveAfter(j->first,j->second);
+       BuildISupport();
+       return true;
+}
+
+void InspIRCd::DoOneIteration(bool process_module_sockets)
+{
+#ifndef WIN32
+       static rusage ru;
+#else
+       static time_t uptime;
+       static struct tm * stime;
+       static char window_title[100];
+#endif
+
+       /* time() seems to be a pretty expensive syscall, so avoid calling it too much.
+        * Once per loop iteration is pleanty.
+        */
+       OLDTIME = TIME;
+       TIME = time(NULL);
+
+       /* Run background module timers every few seconds
+        * (the docs say modules shouldnt rely on accurate
+        * timing using this event, so we dont have to
+        * time this exactly).
+        */
+       if (TIME != OLDTIME)
+       {
+               if (TIME < OLDTIME)
+                       WriteOpers("*** \002EH?!\002 -- Time is flowing BACKWARDS in this dimension! Clock drifted backwards %d secs.",abs(OLDTIME-TIME));
+               if ((TIME % 3600) == 0)
+               {
+                       this->RehashUsersAndChans();
+                       FOREACH_MOD_I(this, I_OnGarbageCollect, OnGarbageCollect());
+               }
+               Timers->TickTimers(TIME);
+               this->DoBackgroundUserStuff(TIME);
+
+               if ((TIME % 5) == 0)
+               {
+                       XLines->expire_lines();
+                       FOREACH_MOD_I(this,I_OnBackgroundTimer,OnBackgroundTimer(TIME));
+                       Timers->TickMissedTimers(TIME);
+               }
+#ifndef WIN32
+               /* Same change as in cmd_stats.cpp, use RUSAGE_SELF rather than '0' -- Om */
+               if (!getrusage(RUSAGE_SELF, &ru))
+               {
+                       gettimeofday(&this->stats->LastSampled, NULL);
+                       this->stats->LastCPU = ru.ru_utime;
+               }
+#else
+               CheckIPC(this);
+
+               if(Config->nofork)
+               {
+                       uptime = Time() - startup_time;
+                       stime = gmtime(&uptime);
+                       snprintf(window_title, 100, "InspIRCd - %u clients, %u accepted connections - Up %u days, %.2u:%.2u:%.2u",
+                               LocalUserCount(), stats->statsAccept, stime->tm_yday, stime->tm_hour, stime->tm_min, stime->tm_sec);
+                       SetConsoleTitle(window_title);
+               }
+#endif
+       }
+
+       /* Call the socket engine to wait on the active
+        * file descriptors. The socket engine has everything's
+        * descriptors in its list... dns, modules, users,
+        * servers... so its nice and easy, just one call.
+        * This will cause any read or write events to be
+        * dispatched to their handlers.
+        */
+       SE->DispatchEvents();
+
+       /* if any users was quit, take them out */
+       GlobalCulls.Apply();
+
+       /* If any inspsockets closed, remove them */
+       for (std::map<InspSocket*,InspSocket*>::iterator x = SocketCull.begin(); x != SocketCull.end(); ++x)
+       {
+               SE->DelFd(x->second);
+               x->second->Close();
+               delete x->second;
+       }
+       SocketCull.clear();
+}
+
+int InspIRCd::Run()
+{
+       while (true)
+       {
+               DoOneIteration(true);
+       }
+       /* This is never reached -- we hope! */
+       return 0;
+}
+
+/**********************************************************************************/
+
+/**
+ * An ircd in four lines! bwahahaha. ahahahahaha. ahahah *cough*.
+ */
+
+int main(int argc, char** argv)
+{
+       SI = new InspIRCd(argc, argv);
+       SI->Run();
+       delete SI;
+       return 0;
+}
+
+/* this returns true when all modules are satisfied that the user should be allowed onto the irc server
+ * (until this returns true, a user will block in the waiting state, waiting to connect up to the
+ * registration timeout maximum seconds)
+ */
+bool InspIRCd::AllModulesReportReady(userrec* user)
+{
+       if (!Config->global_implementation[I_OnCheckReady])
+               return true;
+
+       for (int i = 0; i <= this->GetModuleCount(); i++)
+       {
+               if (Config->implement_lists[i][I_OnCheckReady])
+               {
+                       int res = modules[i]->OnCheckReady(user);
+                       if (!res)
+                               return false;
+               }
+       }
+       return true;
+}
+
+int InspIRCd::GetModuleCount()
+{
+       return this->ModCount;
+}
+
+time_t InspIRCd::Time(bool delta)
+{
+       if (delta)
+               return TIME + time_delta;
+       return TIME;
+}
+
+int InspIRCd::SetTimeDelta(int delta)
+{
+       int old = time_delta;
+       time_delta = delta;
+       this->Log(DEBUG, "Time delta set to %d (was %d)", time_delta, old);
+       return old;
+}
+
+void InspIRCd::AddLocalClone(userrec* user)
+{
+       clonemap::iterator x = local_clones.find(user->GetIPString());
+       if (x != local_clones.end())
+               x->second++;
+       else
+               local_clones[user->GetIPString()] = 1;
+}
+
+void InspIRCd::AddGlobalClone(userrec* user)
+{
+       clonemap::iterator y = global_clones.find(user->GetIPString());
+       if (y != global_clones.end())
+               y->second++;
+       else
+               global_clones[user->GetIPString()] = 1;
+}
+
+int InspIRCd::GetTimeDelta()
+{
+       return time_delta;
+}
+
+bool FileLogger::Readable()
+{
+       return false;
+}
+
+void FileLogger::HandleEvent(EventType et, int errornum)
+{
+       this->WriteLogLine("");
+       if (log)
+               ServerInstance->SE->DelFd(this);
+}
+
+void FileLogger::WriteLogLine(const std::string &line)
+{
+       if (line.length())
+               buffer.append(line);
+
+       if (log)
+       {
+               int written = fprintf(log,"%s",buffer.c_str());
+#ifdef WINDOWS
+               buffer.clear();
+#else
+               if ((written >= 0) && (written < (int)buffer.length()))
+               {
+                       buffer.erase(0, buffer.length());
+                       ServerInstance->SE->AddFd(this);
+               }
+               else if (written == -1)
+               {
+                       if (errno == EAGAIN)
+                               ServerInstance->SE->AddFd(this);
+               }
+               else
+               {
+                       /* Wrote the whole buffer, and no need for write callback */
+                       buffer.clear();
+               }
+#endif
+               if (writeops++ % 20)
+               {
+                       fflush(log);
+               }
+       }
+}
+
+void FileLogger::Close()
+{
+       if (log)
+       {
+               /* Burlex: Windows assumes nonblocking on FILE* pointers anyway, and also "file" fd's aren't the same
+                * as socket fd's. */
+#ifndef WIN32
+               int flags = fcntl(fileno(log), F_GETFL, 0);
+               fcntl(fileno(log), F_SETFL, flags ^ O_NONBLOCK);
+#endif
+               if (buffer.size())
+                       fprintf(log,"%s",buffer.c_str());
+
+#ifndef WINDOWS
+               ServerInstance->SE->DelFd(this);
+#endif
+
+               fflush(log);
+               fclose(log);
+       }
+
+       buffer.clear();
+}
+
+FileLogger::FileLogger(InspIRCd* Instance, FILE* logfile) : ServerInstance(Instance), log(logfile), writeops(0)
+{
+       if (log)
+       {
+               irc::sockets::NonBlocking(fileno(log));
+               this->SetFd(fileno(log));
+               buffer.clear();
+       }
+}
+
+FileLogger::~FileLogger()
+{
+       this->Close();
+}
+
index a2c5cc47f7acfa40290029c83c1326cf4eb25eb6..f29366c73bad71ab7b400309f0b939f0ff9feabc 100644 (file)
@@ -1 +1,750 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "socket.h"\r#include "configreader.h"\r#include "inspstring.h"\r#include "socketengine.h"\r#include "inspircd.h"\r\rusing irc::sockets::OpenTCPSocket;\r\rbool InspSocket::Readable()\r{\r  return ((this->state != I_CONNECTING) && (this->WaitingForWriteEvent == false));\r}\r\rInspSocket::InspSocket(InspIRCd* SI)\r{\r     this->Timeout = NULL;\r  this->state = I_DISCONNECTED;\r  this->fd = -1;\r this->WaitingForWriteEvent = false;\r    this->Instance = SI;\r   this->IsIOHooked = false;\r}\r\rInspSocket::InspSocket(InspIRCd* SI, int newfd, const char* ip)\r{\r this->Timeout = NULL;\r  this->fd = newfd;\r      this->state = I_CONNECTED;\r     strlcpy(this->IP,ip,MAXBUF);\r   this->WaitingForWriteEvent = false;\r    this->Instance = SI;\r   this->IsIOHooked = false;\r      if (this->fd > -1)\r             this->Instance->SE->AddFd(this);\r}\r\rInspSocket::InspSocket(InspIRCd* SI, const std::string &ipaddr, int aport, bool listening, unsigned long maxtime, const std::string &connectbindip)\r{\r      this->cbindip = connectbindip;\r this->fd = -1;\r this->Instance = SI;\r   strlcpy(host,ipaddr.c_str(),MAXBUF);\r   this->WaitingForWriteEvent = false;\r    this->IsIOHooked = false;\r      this->Timeout = NULL;\r  if (listening)\r {\r              if ((this->fd = OpenTCPSocket(host)) == ERROR)\r         {\r                      this->fd = -1;\r                 this->state = I_ERROR;\r                 this->OnError(I_ERR_SOCKET);\r                   return;\r                }\r              else\r           {\r                      if (!SI->BindSocket(this->fd,aport,(char*)ipaddr.c_str()))\r                     {\r                              this->Close();\r                         this->fd = -1;\r                         this->state = I_ERROR;\r                         this->OnError(I_ERR_BIND);\r                             this->ClosePending = true;\r                             return;\r                        }\r                      else\r                   {\r                              this->state = I_LISTENING;\r                             this->port = aport;\r                            if (this->fd > -1)\r                             {\r                                      if (!this->Instance->SE->AddFd(this))\r                                  {\r                                              this->Close();\r                                         this->state = I_ERROR;\r                                         this->OnError(I_ERR_NOMOREFDS);\r                                        }\r                              }\r                              return;\r                        }\r              }\r      }\r      else\r   {\r              strlcpy(this->host,ipaddr.c_str(),MAXBUF);\r             this->port = aport;\r\r           bool ipvalid = true;\r#ifdef IPV6\r               if (strchr(host,':'))\r          {\r                      in6_addr n;\r                    if (inet_pton(AF_INET6, host, &n) < 1)\r                         ipvalid = false;\r               }\r              else\r#endif\r            {\r                      in_addr n;\r                     if (inet_aton(host,&n) < 1)\r                            ipvalid = false;\r               }\r              if (!ipvalid)\r          {\r                      this->Instance->Log(DEBUG,"BUG: Hostname passed to InspSocket, rather than an IP address!");\r                   this->OnError(I_ERR_CONNECT);\r                  this->Close();\r                 this->fd = -1;\r                 this->state = I_ERROR;\r                 return;\r                }\r              else\r           {\r                      strlcpy(this->IP,host,MAXBUF);\r                 timeout_val = maxtime;\r                 if (!this->DoConnect())\r                        {\r                              this->OnError(I_ERR_CONNECT);\r                          this->Close();\r                         this->fd = -1;\r                         this->state = I_ERROR;\r                         return;\r                        }\r              }\r      }\r}\r\rvoid InspSocket::WantWrite()\r{\r    this->Instance->SE->WantWrite(this);\r   this->WaitingForWriteEvent = true;\r}\r\rvoid InspSocket::SetQueues(int nfd)\r{\r    // attempt to increase socket sendq and recvq as high as its possible\r  int sendbuf = 32768;\r   int recvbuf = 32768;\r   setsockopt(nfd,SOL_SOCKET,SO_SNDBUF,(const char *)&sendbuf,sizeof(sendbuf));\r   setsockopt(nfd,SOL_SOCKET,SO_RCVBUF,(const char *)&recvbuf,sizeof(sendbuf));\r}\r\r/* Most irc servers require you to specify the ip you want to bind to.\r * If you dont specify an IP, they rather dumbly bind to the first IP\r * of the box (e.g. INADDR_ANY). In InspIRCd, we scan thought the IP\r * addresses we've bound server ports to, and we try and bind our outbound\r * connections to the first usable non-loopback and non-any IP we find.\r * This is easier to configure when you have a lot of links and a lot\r * of servers to configure.\r */\rbool InspSocket::BindAddr(const std::string &ip)\r{\r  ConfigReader Conf(this->Instance);\r     socklen_t size = sizeof(sockaddr_in);\r#ifdef IPV6\r      bool v6 = false;\r       /* Are we looking for a binding to fit an ipv6 host? */\r        if ((ip.empty()) || (ip.find(':') != std::string::npos))\r               v6 = true;\r#endif\r      int j = 0;\r     while (j < Conf.Enumerate("bind") || (!ip.empty()))\r    {\r              std::string IP = ip.empty() ? Conf.ReadValue("bind","address",j) : ip;\r         if (!ip.empty() || Conf.ReadValue("bind","type",j) == "servers")\r               {\r                      if (!ip.empty() || ((IP != "*") && (IP != "127.0.0.1") && (!IP.empty()) && (IP != "::1")))\r                     {\r                              sockaddr* s = new sockaddr[2];\r#ifdef IPV6\r                             if (v6)\r                                {\r                                      in6_addr n;\r                                    if (inet_pton(AF_INET6, IP.c_str(), &n) > 0)\r                                   {\r                                              memcpy(&((sockaddr_in6*)s)->sin6_addr, &n, sizeof(n));\r                                         ((sockaddr_in6*)s)->sin6_port = 0;\r                                             ((sockaddr_in6*)s)->sin6_family = AF_INET6;\r                                            size = sizeof(sockaddr_in6);\r                                   }\r                                      else\r                                   {\r                                              delete[] s;\r                                            j++;\r                                           continue;\r                                      }\r                              }\r                              else\r#endif\r                            {\r                                      in_addr n;\r                                     if (inet_aton(IP.c_str(), &n) > 0)\r                                     {\r                                              ((sockaddr_in*)s)->sin_addr = n;\r                                               ((sockaddr_in*)s)->sin_port = 0;\r                                               ((sockaddr_in*)s)->sin_family = AF_INET;\r                                       }\r                                      else\r                                   {\r                                              delete[] s;\r                                            j++;\r                                           continue;\r                                      }\r                              }\r\r                             if (bind(this->fd, s, size) < 0)\r                               {\r                                      this->state = I_ERROR;\r                                 this->OnError(I_ERR_BIND);\r                                     this->fd = -1;\r                                 delete[] s;\r                                    return false;\r                          }\r\r                             delete[] s;\r                            return true;\r                   }\r              }\r              j++;\r   }\r      return true;\r}\r\rbool InspSocket::DoConnect()\r{\r sockaddr* addr = new sockaddr[2];\r      socklen_t size = sizeof(sockaddr_in);\r#ifdef IPV6\r      bool v6 = false;\r       if ((!*this->host) || strchr(this->host, ':'))\r         v6 = true;\r\r    if (v6)\r        {\r              this->fd = socket(AF_INET6, SOCK_STREAM, 0);\r           if ((this->fd > -1) && ((strstr(this->IP,"::ffff:") != (char*)&this->IP) && (strstr(this->IP,"::FFFF:") != (char*)&this->IP)))\r         {\r                      if (!this->BindAddr(this->cbindip))\r                    {\r                              delete[] addr;\r                         return false;\r                  }\r              }\r      }\r      else\r#endif\r    {\r              this->fd = socket(AF_INET, SOCK_STREAM, 0);\r            if (this->fd > -1)\r             {\r                      if (!this->BindAddr(this->cbindip))\r                    {\r                              delete[] addr;\r                         return false;\r                  }\r              }\r      }\r\r     if (this->fd == -1)\r    {\r              this->state = I_ERROR;\r         this->OnError(I_ERR_SOCKET);\r           delete[] addr;\r         return false;\r  }\r\r#ifdef IPV6\r if (v6)\r        {\r              in6_addr addy;\r         if (inet_pton(AF_INET6, this->host, &addy) > 0)\r                {\r                      ((sockaddr_in6*)addr)->sin6_family = AF_INET6;\r                 memcpy(&((sockaddr_in6*)addr)->sin6_addr, &addy, sizeof(addy));\r                        ((sockaddr_in6*)addr)->sin6_port = htons(this->port);\r                  size = sizeof(sockaddr_in6);\r           }\r      }\r      else\r#endif\r    {\r              in_addr addy;\r          if (inet_aton(this->host, &addy) > 0)\r          {\r                      ((sockaddr_in*)addr)->sin_family = AF_INET;\r                    ((sockaddr_in*)addr)->sin_addr = addy;\r                 ((sockaddr_in*)addr)->sin_port = htons(this->port);\r            }\r      }\r#ifndef WIN32\r        int flags = fcntl(this->fd, F_GETFL, 0);\r       fcntl(this->fd, F_SETFL, flags | O_NONBLOCK);\r#else\r    unsigned long flags = 0;\r       ioctlsocket(this->fd, FIONBIO, &flags);\r#endif\r if (connect(this->fd, (sockaddr*)addr, size) == -1)\r    {\r              if (errno != EINPROGRESS)\r              {\r                      this->OnError(I_ERR_CONNECT);\r                  this->Close();\r                 this->state = I_ERROR;\r                 return false;\r          }\r\r             this->Timeout = new SocketTimeout(this->GetFd(), this->Instance, this, timeout_val, this->Instance->Time());\r           this->Instance->Timers->AddTimer(this->Timeout);\r       }\r      this->state = I_CONNECTING;\r    if (this->fd > -1)\r     {\r              if (!this->Instance->SE->AddFd(this))\r          {\r                      this->OnError(I_ERR_NOMOREFDS);\r                        this->Close();\r                 this->state = I_ERROR;\r                 return false;\r          }\r              this->SetQueues(this->fd);\r     }\r      return true;\r}\r\r\rvoid InspSocket::Close()\r{\r    /* Save this, so we dont lose it,\r       * otherise on failure, error messages\r  * might be inaccurate.\r         */\r    int save = errno;\r      if (this->fd > -1)\r     {\r              if (this->IsIOHooked && Instance->Config->GetIOHook(this))\r             {\r                      try\r                    {\r                              Instance->Config->GetIOHook(this)->OnRawSocketClose(this->fd);\r                 }\r                      catch (CoreException& modexcept)\r                       {\r                              Instance->Log(DEFAULT,"%s threw an exception: %s", modexcept.GetSource(), modexcept.GetReason());\r                      }\r              }\r              this->OnClose();\r               shutdown(this->fd,2);\r          close(this->fd);\r\r              if (Instance->SocketCull.find(this) == Instance->SocketCull.end())\r                     Instance->SocketCull[this] = this;\r     }\r      errno = save;\r}\r\rstd::string InspSocket::GetIP()\r{\r     return this->IP;\r}\r\rchar* InspSocket::Read()\r{\r#ifdef WINDOWS\r  if ((fd < 0) || (m_internalFd > MAX_DESCRIPTORS))\r#else\r        if ((fd < 0) || (fd > MAX_DESCRIPTORS))\r#endif\r         return NULL;\r\r  int n = 0;\r\r    if (this->IsIOHooked)\r  {\r              int result2 = 0;\r               int MOD_RESULT = 0;\r            try\r            {\r                      MOD_RESULT = Instance->Config->GetIOHook(this)->OnRawSocketRead(this->fd,this->ibuf,sizeof(this->ibuf),result2);\r               }\r              catch (CoreException& modexcept)\r               {\r                      Instance->Log(DEFAULT,"%s threw an exception: %s", modexcept.GetSource(), modexcept.GetReason());\r              }\r              if (MOD_RESULT < 0)\r            {\r                      n = -1;\r                        errno = EAGAIN;\r                }\r              else\r           {\r                      n = result2;\r           }\r      }\r      else\r   {\r              n = recv(this->fd,this->ibuf,sizeof(this->ibuf),0);\r    }\r\r     if ((n > 0) && (n <= (int)sizeof(this->ibuf)))\r {\r              ibuf[n] = 0;\r           return ibuf;\r   }\r      else\r   {\r              int err = errno;\r               if (err == EAGAIN)\r                     return "";\r             else\r                   return NULL;\r   }\r}\r\rvoid InspSocket::MarkAsClosed()\r{\r}\r\r// There are two possible outcomes to this function.\r// It will either write all of the data, or an undefined amount.\r// If an undefined amount is written the connection has failed\r// and should be aborted.\rint InspSocket::Write(const std::string &data)\r{\r      /* Try and append the data to the back of the queue, and send it on its way\r     */\r    outbuffer.push_back(data);\r     this->Instance->SE->WantWrite(this);\r   return (!this->FlushWriteBuffer());\r}\r\rbool InspSocket::FlushWriteBuffer()\r{\r   errno = 0;\r     if ((this->fd > -1) && (this->state == I_CONNECTED))\r   {\r              if (this->IsIOHooked)\r          {\r                      while (outbuffer.size() && (errno != EAGAIN))\r                  {\r                              try\r                            {\r                                      /* XXX: The lack of buffering here is NOT a bug, modules implementing this interface have to\r                                    * implement their own buffering mechanisms\r                                     */\r                                    Instance->Config->GetIOHook(this)->OnRawSocketWrite(this->fd, outbuffer[0].c_str(), outbuffer[0].length());\r                                    outbuffer.pop_front();\r                         }\r                              catch (CoreException& modexcept)\r                               {\r                                      Instance->Log(DEBUG,"%s threw an exception: %s", modexcept.GetSource(), modexcept.GetReason());\r                                        return true;\r                           }\r                      }\r              }\r              else\r           {\r                      /* If we have multiple lines, try to send them all,\r                     * not just the first one -- Brain\r                      */\r                    while (outbuffer.size() && (errno != EAGAIN))\r                  {\r                              /* Send a line */\r#ifndef WIN32\r                                int result = write(this->fd,outbuffer[0].c_str(),outbuffer[0].length());\r#else\r                         int result = send(this->fd,outbuffer[0].c_str(),outbuffer[0].length(), 0);\r#endif\r                              if (result > 0)\r                                {\r                                      if ((unsigned int)result >= outbuffer[0].length())\r                                     {\r                                              /* The whole block was written (usually a line)\r                                                 * Pop the block off the front of the queue,\r                                            * dont set errno, because we are clear of errors\r                                               * and want to try and write the next block too.\r                                                */\r                                            outbuffer.pop_front();\r                                 }\r                                      else\r                                   {\r                                              std::string temp = outbuffer[0].substr(result);\r                                                outbuffer[0] = temp;\r                                           /* We didnt get the whole line out. arses.\r                                              * Try again next time, i guess. Set errno,\r                                             * because we shouldnt be writing any more now,\r                                                 * until the socketengine says its safe to do so.\r                                               */\r                                            errno = EAGAIN;\r                                        }\r                              }\r                              else if ((result == -1) && (errno != EAGAIN))\r                          {\r                                      this->OnError(I_ERR_WRITE);\r                                    this->state = I_ERROR;\r                                 this->Instance->SE->DelFd(this);\r                                       this->Close();\r                                 return true;\r                           }\r                      }\r              }\r      }\r\r     if ((errno == EAGAIN) && (fd > -1))\r    {\r              this->Instance->SE->WantWrite(this);\r   }\r\r     return (fd < 0);\r}\r\rvoid SocketTimeout::Tick(time_t now)\r{\r     if (ServerInstance->SE->GetRef(this->sfd) != this->sock)\r               return;\r\r       if (this->sock->state == I_CONNECTING)\r {\r              // for non-listening sockets, the timeout can occur\r            // which causes termination of the connection after\r            // the given number of seconds without a successful\r            // connection.\r         this->sock->OnTimeout();\r               this->sock->OnError(I_ERR_TIMEOUT);\r            this->sock->timeout = true;\r\r           /* NOTE: We must set this AFTER DelFd, as we added\r              * this socket whilst writeable. This means that we\r             * must DELETE the socket whilst writeable too!\r                 */\r            this->sock->state = I_ERROR;\r\r          if (ServerInstance->SocketCull.find(this->sock) == ServerInstance->SocketCull.end())\r                   ServerInstance->SocketCull[this->sock] = this->sock;\r   }\r\r     this->sock->Timeout = NULL;\r}\r\rbool InspSocket::Poll()\r{\r#ifdef WINDOWS\r        if(Instance->SE->GetRef(this->fd) != this)\r             return false;\r  int incoming = -1;\r#else\r       if (this->Instance->SE->GetRef(this->fd) != this)\r              return false;\r\r int incoming = -1;\r\r    if ((fd < 0) || (fd > MAX_DESCRIPTORS))\r                return false;\r#endif\r   switch (this->state)\r   {\r              case I_CONNECTING:\r                     /* Our socket was in write-state, so delete it and re-add it\r                    * in read-state.\r                       */\r#ifndef WINDOWS\r                    if (this->fd > -1)\r                     {\r                              this->Instance->SE->DelFd(this);\r                               this->SetState(I_CONNECTED);\r                           if (!this->Instance->SE->AddFd(this))\r                                  return false;\r                  }\r#else\r                        this->SetState(I_CONNECTED);\r#endif\r                    Instance->Log(DEBUG,"Inspsocket I_CONNECTING state");\r                  if (Instance->Config->GetIOHook(this))\r                 {\r                              Instance->Log(DEBUG,"Hook for raw connect");\r                           try\r                            {\r                                      Instance->Config->GetIOHook(this)->OnRawSocketConnect(this->fd);\r                               }\r                              catch (CoreException& modexcept)\r                               {\r                                      Instance->Log(DEBUG,"%s threw an exception: %s", modexcept.GetSource(), modexcept.GetReason());\r                                }\r                      }\r                      return this->OnConnected();\r            break;\r         case I_LISTENING:\r              {\r                      sockaddr* client = new sockaddr[2];\r                    length = sizeof (sockaddr_in);\r                 std::string recvip;\r#ifdef IPV6\r                        if ((!*this->host) || strchr(this->host, ':'))\r                         length = sizeof(sockaddr_in6);\r#endif\r                  incoming = _accept (this->fd, client, &length);\r#ifdef IPV6\r                    if ((!*this->host) || strchr(this->host, ':'))\r                 {\r                              char buf[1024];\r                                recvip = inet_ntop(AF_INET6, &((sockaddr_in6*)client)->sin6_addr, buf, sizeof(buf));\r                   }\r                      else\r#endif\r                    recvip = inet_ntoa(((sockaddr_in*)client)->sin_addr);\r                  this->OnIncomingConnection(incoming, (char*)recvip.c_str());\r\r                  if (this->IsIOHooked)\r                  {\r                              try\r                            {\r                                      Instance->Config->GetIOHook(this)->OnRawSocketAccept(incoming, recvip.c_str(), this->port);\r                            }\r                              catch (CoreException& modexcept)\r                               {\r                                      Instance->Log(DEBUG,"%s threw an exception: %s", modexcept.GetSource(), modexcept.GetReason());\r                                }\r                      }\r\r                     this->SetQueues(incoming);\r\r                    delete[] client;\r                       return true;\r           }\r              break;\r         case I_CONNECTED:\r                      /* Process the read event */\r                   return this->OnDataReady();\r            break;\r         default:\r               break;\r }\r      return true;\r}\r\rvoid InspSocket::SetState(InspSocketState s)\r{\r this->state = s;\r}\r\rInspSocketState InspSocket::GetState()\r{\r   return this->state;\r}\r\rint InspSocket::GetFd()\r{\r       return this->fd;\r}\r\rbool InspSocket::OnConnected() { return true; }\rvoid InspSocket::OnError(InspSocketError e) { return; }\rint InspSocket::OnDisconnect() { return 0; }\rint InspSocket::OnIncomingConnection(int newfd, char* ip) { return 0; }\rbool InspSocket::OnDataReady() { return true; }\rbool InspSocket::OnWriteReady() { return true; }\rvoid InspSocket::OnTimeout() { return; }\rvoid InspSocket::OnClose() { return; }\r\rInspSocket::~InspSocket()\r{\r this->Close();\r if (Timeout)\r   {\r              Instance->Timers->DelTimer(Timeout);\r           Timeout = NULL;\r        }\r}\r\rvoid InspSocket::HandleEvent(EventType et, int errornum)\r{\r        switch (et)\r    {\r              case EVENT_ERROR:\r                      switch (errornum)\r                      {\r                              case ETIMEDOUT:\r                                        this->OnError(I_ERR_TIMEOUT);\r                          break;\r                         case ECONNREFUSED:\r                             case 0:\r                                        this->OnError(this->state == I_CONNECTING ? I_ERR_CONNECT : I_ERR_WRITE);\r                              break;\r                         case EADDRINUSE:\r                                       this->OnError(I_ERR_BIND);\r                             break;\r                         case EPIPE:\r                            case EIO:\r                                      this->OnError(I_ERR_WRITE);\r                            break;\r                 }\r                      if (this->Instance->SocketCull.find(this) == this->Instance->SocketCull.end())\r                         this->Instance->SocketCull[this] = this;\r                       return;\r                break;\r         case EVENT_READ:\r                       if (!this->Poll())\r                     {\r                              if (this->Instance->SocketCull.find(this) == this->Instance->SocketCull.end())\r                                 this->Instance->SocketCull[this] = this;\r                               return;\r                        }\r              break;\r         case EVENT_WRITE:\r                      if (this->WaitingForWriteEvent)\r                        {\r                              this->WaitingForWriteEvent = false;\r                            if (!this->OnWriteReady())\r                             {\r                                      if (this->Instance->SocketCull.find(this) == this->Instance->SocketCull.end())\r                                         this->Instance->SocketCull[this] = this;\r                                       return;\r                                }\r                      }\r                      if (this->state == I_CONNECTING)\r                       {\r                              /* This might look wrong as if we should be actually calling\r                            * with EVENT_WRITE, but trust me it is correct. There are some\r                                 * writeability-state things in the read code, because of how\r                           * InspSocket used to work regarding write buffering in previous\r                                * versions of InspIRCd. - Brain\r                                */\r                            this->HandleEvent(EVENT_READ);\r                         return;\r                        }\r                      else\r                   {\r                              if (this->FlushWriteBuffer())\r                          {\r                                      if (this->Instance->SocketCull.find(this) == this->Instance->SocketCull.end())\r                                         this->Instance->SocketCull[this] = this;\r                                       return;\r                                }\r                      }\r              break;\r }\r}\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "socket.h"
+#include "configreader.h"
+#include "inspstring.h"
+#include "socketengine.h"
+#include "inspircd.h"
+
+using irc::sockets::OpenTCPSocket;
+
+bool InspSocket::Readable()
+{
+       return ((this->state != I_CONNECTING) && (this->WaitingForWriteEvent == false));
+}
+
+InspSocket::InspSocket(InspIRCd* SI)
+{
+       this->Timeout = NULL;
+       this->state = I_DISCONNECTED;
+       this->fd = -1;
+       this->WaitingForWriteEvent = false;
+       this->Instance = SI;
+       this->IsIOHooked = false;
+}
+
+InspSocket::InspSocket(InspIRCd* SI, int newfd, const char* ip)
+{
+       this->Timeout = NULL;
+       this->fd = newfd;
+       this->state = I_CONNECTED;
+       strlcpy(this->IP,ip,MAXBUF);
+       this->WaitingForWriteEvent = false;
+       this->Instance = SI;
+       this->IsIOHooked = false;
+       if (this->fd > -1)
+               this->Instance->SE->AddFd(this);
+}
+
+InspSocket::InspSocket(InspIRCd* SI, const std::string &ipaddr, int aport, bool listening, unsigned long maxtime, const std::string &connectbindip)
+{
+       this->cbindip = connectbindip;
+       this->fd = -1;
+       this->Instance = SI;
+       strlcpy(host,ipaddr.c_str(),MAXBUF);
+       this->WaitingForWriteEvent = false;
+       this->IsIOHooked = false;
+       this->Timeout = NULL;
+       if (listening)
+       {
+               if ((this->fd = OpenTCPSocket(host)) == ERROR)
+               {
+                       this->fd = -1;
+                       this->state = I_ERROR;
+                       this->OnError(I_ERR_SOCKET);
+                       return;
+               }
+               else
+               {
+                       if (!SI->BindSocket(this->fd,aport,(char*)ipaddr.c_str()))
+                       {
+                               this->Close();
+                               this->fd = -1;
+                               this->state = I_ERROR;
+                               this->OnError(I_ERR_BIND);
+                               this->ClosePending = true;
+                               return;
+                       }
+                       else
+                       {
+                               this->state = I_LISTENING;
+                               this->port = aport;
+                               if (this->fd > -1)
+                               {
+                                       if (!this->Instance->SE->AddFd(this))
+                                       {
+                                               this->Close();
+                                               this->state = I_ERROR;
+                                               this->OnError(I_ERR_NOMOREFDS);
+                                       }
+                               }
+                               return;
+                       }
+               }
+       }
+       else
+       {
+               strlcpy(this->host,ipaddr.c_str(),MAXBUF);
+               this->port = aport;
+
+               bool ipvalid = true;
+#ifdef IPV6
+               if (strchr(host,':'))
+               {
+                       in6_addr n;
+                       if (inet_pton(AF_INET6, host, &n) < 1)
+                               ipvalid = false;
+               }
+               else
+#endif
+               {
+                       in_addr n;
+                       if (inet_aton(host,&n) < 1)
+                               ipvalid = false;
+               }
+               if (!ipvalid)
+               {
+                       this->Instance->Log(DEBUG,"BUG: Hostname passed to InspSocket, rather than an IP address!");
+                       this->OnError(I_ERR_CONNECT);
+                       this->Close();
+                       this->fd = -1;
+                       this->state = I_ERROR;
+                       return;
+               }
+               else
+               {
+                       strlcpy(this->IP,host,MAXBUF);
+                       timeout_val = maxtime;
+                       if (!this->DoConnect())
+                       {
+                               this->OnError(I_ERR_CONNECT);
+                               this->Close();
+                               this->fd = -1;
+                               this->state = I_ERROR;
+                               return;
+                       }
+               }
+       }
+}
+
+void InspSocket::WantWrite()
+{
+       this->Instance->SE->WantWrite(this);
+       this->WaitingForWriteEvent = true;
+}
+
+void InspSocket::SetQueues(int nfd)
+{
+       // attempt to increase socket sendq and recvq as high as its possible
+       int sendbuf = 32768;
+       int recvbuf = 32768;
+       setsockopt(nfd,SOL_SOCKET,SO_SNDBUF,(const char *)&sendbuf,sizeof(sendbuf));
+       setsockopt(nfd,SOL_SOCKET,SO_RCVBUF,(const char *)&recvbuf,sizeof(sendbuf));
+}
+
+/* Most irc servers require you to specify the ip you want to bind to.
+ * If you dont specify an IP, they rather dumbly bind to the first IP
+ * of the box (e.g. INADDR_ANY). In InspIRCd, we scan thought the IP
+ * addresses we've bound server ports to, and we try and bind our outbound
+ * connections to the first usable non-loopback and non-any IP we find.
+ * This is easier to configure when you have a lot of links and a lot
+ * of servers to configure.
+ */
+bool InspSocket::BindAddr(const std::string &ip)
+{
+       ConfigReader Conf(this->Instance);
+       socklen_t size = sizeof(sockaddr_in);
+#ifdef IPV6
+       bool v6 = false;
+       /* Are we looking for a binding to fit an ipv6 host? */
+       if ((ip.empty()) || (ip.find(':') != std::string::npos))
+               v6 = true;
+#endif
+       int j = 0;
+       while (j < Conf.Enumerate("bind") || (!ip.empty()))
+       {
+               std::string IP = ip.empty() ? Conf.ReadValue("bind","address",j) : ip;
+               if (!ip.empty() || Conf.ReadValue("bind","type",j) == "servers")
+               {
+                       if (!ip.empty() || ((IP != "*") && (IP != "127.0.0.1") && (!IP.empty()) && (IP != "::1")))
+                       {
+                               sockaddr* s = new sockaddr[2];
+#ifdef IPV6
+                               if (v6)
+                               {
+                                       in6_addr n;
+                                       if (inet_pton(AF_INET6, IP.c_str(), &n) > 0)
+                                       {
+                                               memcpy(&((sockaddr_in6*)s)->sin6_addr, &n, sizeof(n));
+                                               ((sockaddr_in6*)s)->sin6_port = 0;
+                                               ((sockaddr_in6*)s)->sin6_family = AF_INET6;
+                                               size = sizeof(sockaddr_in6);
+                                       }
+                                       else
+                                       {
+                                               delete[] s;
+                                               j++;
+                                               continue;
+                                       }
+                               }
+                               else
+#endif
+                               {
+                                       in_addr n;
+                                       if (inet_aton(IP.c_str(), &n) > 0)
+                                       {
+                                               ((sockaddr_in*)s)->sin_addr = n;
+                                               ((sockaddr_in*)s)->sin_port = 0;
+                                               ((sockaddr_in*)s)->sin_family = AF_INET;
+                                       }
+                                       else
+                                       {
+                                               delete[] s;
+                                               j++;
+                                               continue;
+                                       }
+                               }
+
+                               if (bind(this->fd, s, size) < 0)
+                               {
+                                       this->state = I_ERROR;
+                                       this->OnError(I_ERR_BIND);
+                                       this->fd = -1;
+                                       delete[] s;
+                                       return false;
+                               }
+
+                               delete[] s;
+                               return true;
+                       }
+               }
+               j++;
+       }
+       return true;
+}
+
+bool InspSocket::DoConnect()
+{
+       sockaddr* addr = new sockaddr[2];
+       socklen_t size = sizeof(sockaddr_in);
+#ifdef IPV6
+       bool v6 = false;
+       if ((!*this->host) || strchr(this->host, ':'))
+               v6 = true;
+
+       if (v6)
+       {
+               this->fd = socket(AF_INET6, SOCK_STREAM, 0);
+               if ((this->fd > -1) && ((strstr(this->IP,"::ffff:") != (char*)&this->IP) && (strstr(this->IP,"::FFFF:") != (char*)&this->IP)))
+               {
+                       if (!this->BindAddr(this->cbindip))
+                       {
+                               delete[] addr;
+                               return false;
+                       }
+               }
+       }
+       else
+#endif
+       {
+               this->fd = socket(AF_INET, SOCK_STREAM, 0);
+               if (this->fd > -1)
+               {
+                       if (!this->BindAddr(this->cbindip))
+                       {
+                               delete[] addr;
+                               return false;
+                       }
+               }
+       }
+
+       if (this->fd == -1)
+       {
+               this->state = I_ERROR;
+               this->OnError(I_ERR_SOCKET);
+               delete[] addr;
+               return false;
+       }
+
+#ifdef IPV6
+       if (v6)
+       {
+               in6_addr addy;
+               if (inet_pton(AF_INET6, this->host, &addy) > 0)
+               {
+                       ((sockaddr_in6*)addr)->sin6_family = AF_INET6;
+                       memcpy(&((sockaddr_in6*)addr)->sin6_addr, &addy, sizeof(addy));
+                       ((sockaddr_in6*)addr)->sin6_port = htons(this->port);
+                       size = sizeof(sockaddr_in6);
+               }
+       }
+       else
+#endif
+       {
+               in_addr addy;
+               if (inet_aton(this->host, &addy) > 0)
+               {
+                       ((sockaddr_in*)addr)->sin_family = AF_INET;
+                       ((sockaddr_in*)addr)->sin_addr = addy;
+                       ((sockaddr_in*)addr)->sin_port = htons(this->port);
+               }
+       }
+#ifndef WIN32
+       int flags = fcntl(this->fd, F_GETFL, 0);
+       fcntl(this->fd, F_SETFL, flags | O_NONBLOCK);
+#else
+       unsigned long flags = 0;
+       ioctlsocket(this->fd, FIONBIO, &flags);
+#endif
+       if (connect(this->fd, (sockaddr*)addr, size) == -1)
+       {
+               if (errno != EINPROGRESS)
+               {
+                       this->OnError(I_ERR_CONNECT);
+                       this->Close();
+                       this->state = I_ERROR;
+                       return false;
+               }
+
+               this->Timeout = new SocketTimeout(this->GetFd(), this->Instance, this, timeout_val, this->Instance->Time());
+               this->Instance->Timers->AddTimer(this->Timeout);
+       }
+       this->state = I_CONNECTING;
+       if (this->fd > -1)
+       {
+               if (!this->Instance->SE->AddFd(this))
+               {
+                       this->OnError(I_ERR_NOMOREFDS);
+                       this->Close();
+                       this->state = I_ERROR;
+                       return false;
+               }
+               this->SetQueues(this->fd);
+       }
+       return true;
+}
+
+
+void InspSocket::Close()
+{
+       /* Save this, so we dont lose it,
+        * otherise on failure, error messages
+        * might be inaccurate.
+        */
+       int save = errno;
+       if (this->fd > -1)
+       {
+               if (this->IsIOHooked && Instance->Config->GetIOHook(this))
+               {
+                       try
+                       {
+                               Instance->Config->GetIOHook(this)->OnRawSocketClose(this->fd);
+                       }
+                       catch (CoreException& modexcept)
+                       {
+                               Instance->Log(DEFAULT,"%s threw an exception: %s", modexcept.GetSource(), modexcept.GetReason());
+                       }
+               }
+               this->OnClose();
+               shutdown(this->fd,2);
+               close(this->fd);
+
+               if (Instance->SocketCull.find(this) == Instance->SocketCull.end())
+                       Instance->SocketCull[this] = this;
+       }
+       errno = save;
+}
+
+std::string InspSocket::GetIP()
+{
+       return this->IP;
+}
+
+char* InspSocket::Read()
+{
+#ifdef WINDOWS
+       if ((fd < 0) || (m_internalFd > MAX_DESCRIPTORS))
+#else
+       if ((fd < 0) || (fd > MAX_DESCRIPTORS))
+#endif
+               return NULL;
+
+       int n = 0;
+
+       if (this->IsIOHooked)
+       {
+               int result2 = 0;
+               int MOD_RESULT = 0;
+               try
+               {
+                       MOD_RESULT = Instance->Config->GetIOHook(this)->OnRawSocketRead(this->fd,this->ibuf,sizeof(this->ibuf),result2);
+               }
+               catch (CoreException& modexcept)
+               {
+                       Instance->Log(DEFAULT,"%s threw an exception: %s", modexcept.GetSource(), modexcept.GetReason());
+               }
+               if (MOD_RESULT < 0)
+               {
+                       n = -1;
+                       errno = EAGAIN;
+               }
+               else
+               {
+                       n = result2;
+               }
+       }
+       else
+       {
+               n = recv(this->fd,this->ibuf,sizeof(this->ibuf),0);
+       }
+
+       if ((n > 0) && (n <= (int)sizeof(this->ibuf)))
+       {
+               ibuf[n] = 0;
+               return ibuf;
+       }
+       else
+       {
+               int err = errno;
+               if (err == EAGAIN)
+                       return "";
+               else
+                       return NULL;
+       }
+}
+
+void InspSocket::MarkAsClosed()
+{
+}
+
+// There are two possible outcomes to this function.
+// It will either write all of the data, or an undefined amount.
+// If an undefined amount is written the connection has failed
+// and should be aborted.
+int InspSocket::Write(const std::string &data)
+{
+       /* Try and append the data to the back of the queue, and send it on its way
+        */
+       outbuffer.push_back(data);
+       this->Instance->SE->WantWrite(this);
+       return (!this->FlushWriteBuffer());
+}
+
+bool InspSocket::FlushWriteBuffer()
+{
+       errno = 0;
+       if ((this->fd > -1) && (this->state == I_CONNECTED))
+       {
+               if (this->IsIOHooked)
+               {
+                       while (outbuffer.size() && (errno != EAGAIN))
+                       {
+                               try
+                               {
+                                       /* XXX: The lack of buffering here is NOT a bug, modules implementing this interface have to
+                                        * implement their own buffering mechanisms
+                                        */
+                                       Instance->Config->GetIOHook(this)->OnRawSocketWrite(this->fd, outbuffer[0].c_str(), outbuffer[0].length());
+                                       outbuffer.pop_front();
+                               }
+                               catch (CoreException& modexcept)
+                               {
+                                       Instance->Log(DEBUG,"%s threw an exception: %s", modexcept.GetSource(), modexcept.GetReason());
+                                       return true;
+                               }
+                       }
+               }
+               else
+               {
+                       /* If we have multiple lines, try to send them all,
+                        * not just the first one -- Brain
+                        */
+                       while (outbuffer.size() && (errno != EAGAIN))
+                       {
+                               /* Send a line */
+#ifndef WIN32
+                               int result = write(this->fd,outbuffer[0].c_str(),outbuffer[0].length());
+#else
+                               int result = send(this->fd,outbuffer[0].c_str(),outbuffer[0].length(), 0);
+#endif
+                               if (result > 0)
+                               {
+                                       if ((unsigned int)result >= outbuffer[0].length())
+                                       {
+                                               /* The whole block was written (usually a line)
+                                                * Pop the block off the front of the queue,
+                                                * dont set errno, because we are clear of errors
+                                                * and want to try and write the next block too.
+                                                */
+                                               outbuffer.pop_front();
+                                       }
+                                       else
+                                       {
+                                               std::string temp = outbuffer[0].substr(result);
+                                               outbuffer[0] = temp;
+                                               /* We didnt get the whole line out. arses.
+                                                * Try again next time, i guess. Set errno,
+                                                * because we shouldnt be writing any more now,
+                                                * until the socketengine says its safe to do so.
+                                                */
+                                               errno = EAGAIN;
+                                       }
+                               }
+                               else if ((result == -1) && (errno != EAGAIN))
+                               {
+                                       this->OnError(I_ERR_WRITE);
+                                       this->state = I_ERROR;
+                                       this->Instance->SE->DelFd(this);
+                                       this->Close();
+                                       return true;
+                               }
+                       }
+               }
+       }
+
+       if ((errno == EAGAIN) && (fd > -1))
+       {
+               this->Instance->SE->WantWrite(this);
+       }
+
+       return (fd < 0);
+}
+
+void SocketTimeout::Tick(time_t now)
+{
+       if (ServerInstance->SE->GetRef(this->sfd) != this->sock)
+               return;
+
+       if (this->sock->state == I_CONNECTING)
+       {
+               // for non-listening sockets, the timeout can occur
+               // which causes termination of the connection after
+               // the given number of seconds without a successful
+               // connection.
+               this->sock->OnTimeout();
+               this->sock->OnError(I_ERR_TIMEOUT);
+               this->sock->timeout = true;
+
+               /* NOTE: We must set this AFTER DelFd, as we added
+                * this socket whilst writeable. This means that we
+                * must DELETE the socket whilst writeable too!
+                */
+               this->sock->state = I_ERROR;
+
+               if (ServerInstance->SocketCull.find(this->sock) == ServerInstance->SocketCull.end())
+                       ServerInstance->SocketCull[this->sock] = this->sock;
+       }
+
+       this->sock->Timeout = NULL;
+}
+
+bool InspSocket::Poll()
+{
+#ifdef WINDOWS
+       if(Instance->SE->GetRef(this->fd) != this)
+               return false;
+       int incoming = -1;
+#else
+       if (this->Instance->SE->GetRef(this->fd) != this)
+               return false;
+
+       int incoming = -1;
+
+       if ((fd < 0) || (fd > MAX_DESCRIPTORS))
+               return false;
+#endif
+       switch (this->state)
+       {
+               case I_CONNECTING:
+                       /* Our socket was in write-state, so delete it and re-add it
+                        * in read-state.
+                        */
+#ifndef WINDOWS
+                       if (this->fd > -1)
+                       {
+                               this->Instance->SE->DelFd(this);
+                               this->SetState(I_CONNECTED);
+                               if (!this->Instance->SE->AddFd(this))
+                                       return false;
+                       }
+#else
+                       this->SetState(I_CONNECTED);
+#endif
+                       Instance->Log(DEBUG,"Inspsocket I_CONNECTING state");
+                       if (Instance->Config->GetIOHook(this))
+                       {
+                               Instance->Log(DEBUG,"Hook for raw connect");
+                               try
+                               {
+                                       Instance->Config->GetIOHook(this)->OnRawSocketConnect(this->fd);
+                               }
+                               catch (CoreException& modexcept)
+                               {
+                                       Instance->Log(DEBUG,"%s threw an exception: %s", modexcept.GetSource(), modexcept.GetReason());
+                               }
+                       }
+                       return this->OnConnected();
+               break;
+               case I_LISTENING:
+               {
+                       sockaddr* client = new sockaddr[2];
+                       length = sizeof (sockaddr_in);
+                       std::string recvip;
+#ifdef IPV6
+                       if ((!*this->host) || strchr(this->host, ':'))
+                               length = sizeof(sockaddr_in6);
+#endif
+                       incoming = _accept (this->fd, client, &length);
+#ifdef IPV6
+                       if ((!*this->host) || strchr(this->host, ':'))
+                       {
+                               char buf[1024];
+                               recvip = inet_ntop(AF_INET6, &((sockaddr_in6*)client)->sin6_addr, buf, sizeof(buf));
+                       }
+                       else
+#endif
+                       recvip = inet_ntoa(((sockaddr_in*)client)->sin_addr);
+                       this->OnIncomingConnection(incoming, (char*)recvip.c_str());
+
+                       if (this->IsIOHooked)
+                       {
+                               try
+                               {
+                                       Instance->Config->GetIOHook(this)->OnRawSocketAccept(incoming, recvip.c_str(), this->port);
+                               }
+                               catch (CoreException& modexcept)
+                               {
+                                       Instance->Log(DEBUG,"%s threw an exception: %s", modexcept.GetSource(), modexcept.GetReason());
+                               }
+                       }
+
+                       this->SetQueues(incoming);
+
+                       delete[] client;
+                       return true;
+               }
+               break;
+               case I_CONNECTED:
+                       /* Process the read event */
+                       return this->OnDataReady();
+               break;
+               default:
+               break;
+       }
+       return true;
+}
+
+void InspSocket::SetState(InspSocketState s)
+{
+       this->state = s;
+}
+
+InspSocketState InspSocket::GetState()
+{
+       return this->state;
+}
+
+int InspSocket::GetFd()
+{
+       return this->fd;
+}
+
+bool InspSocket::OnConnected() { return true; }
+void InspSocket::OnError(InspSocketError e) { return; }
+int InspSocket::OnDisconnect() { return 0; }
+int InspSocket::OnIncomingConnection(int newfd, char* ip) { return 0; }
+bool InspSocket::OnDataReady() { return true; }
+bool InspSocket::OnWriteReady() { return true; }
+void InspSocket::OnTimeout() { return; }
+void InspSocket::OnClose() { return; }
+
+InspSocket::~InspSocket()
+{
+       this->Close();
+       if (Timeout)
+       {
+               Instance->Timers->DelTimer(Timeout);
+               Timeout = NULL;
+       }
+}
+
+void InspSocket::HandleEvent(EventType et, int errornum)
+{
+       switch (et)
+       {
+               case EVENT_ERROR:
+                       switch (errornum)
+                       {
+                               case ETIMEDOUT:
+                                       this->OnError(I_ERR_TIMEOUT);
+                               break;
+                               case ECONNREFUSED:
+                               case 0:
+                                       this->OnError(this->state == I_CONNECTING ? I_ERR_CONNECT : I_ERR_WRITE);
+                               break;
+                               case EADDRINUSE:
+                                       this->OnError(I_ERR_BIND);
+                               break;
+                               case EPIPE:
+                               case EIO:
+                                       this->OnError(I_ERR_WRITE);
+                               break;
+                       }
+                       if (this->Instance->SocketCull.find(this) == this->Instance->SocketCull.end())
+                               this->Instance->SocketCull[this] = this;
+                       return;
+               break;
+               case EVENT_READ:
+                       if (!this->Poll())
+                       {
+                               if (this->Instance->SocketCull.find(this) == this->Instance->SocketCull.end())
+                                       this->Instance->SocketCull[this] = this;
+                               return;
+                       }
+               break;
+               case EVENT_WRITE:
+                       if (this->WaitingForWriteEvent)
+                       {
+                               this->WaitingForWriteEvent = false;
+                               if (!this->OnWriteReady())
+                               {
+                                       if (this->Instance->SocketCull.find(this) == this->Instance->SocketCull.end())
+                                               this->Instance->SocketCull[this] = this;
+                                       return;
+                               }
+                       }
+                       if (this->state == I_CONNECTING)
+                       {
+                               /* This might look wrong as if we should be actually calling
+                                * with EVENT_WRITE, but trust me it is correct. There are some
+                                * writeability-state things in the read code, because of how
+                                * InspSocket used to work regarding write buffering in previous
+                                * versions of InspIRCd. - Brain
+                                */
+                               this->HandleEvent(EVENT_READ);
+                               return;
+                       }
+                       else
+                       {
+                               if (this->FlushWriteBuffer())
+                               {
+                                       if (this->Instance->SocketCull.find(this) == this->Instance->SocketCull.end())
+                                               this->Instance->SocketCull[this] = this;
+                                       return;
+                               }
+                       }
+               break;
+       }
+}
+
index b5278a6adad5146cceb7d09e3b54042ef46cc373..98e7228d51ffefb23dcb9a7147660bbd498efc31 100644 (file)
@@ -1 +1,137 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspstring.h"\r\r/*\r * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>\r * All rights reserved.\r *\r * Redistribution and use in source and binary forms, with or without\r * modification, are permitted provided that the following conditions\r * are met:\r * 1. Redistributions of source code must retain the above copyright\r *    notice, this list of conditions and the following disclaimer.\r * 2. Redistributions in binary form must reproduce the above copyright    \r *    notice, this list of conditions and the following disclaimer in the  \r *    documentation and/or other materials provided with the distribution. \r * 3. The name of the author may not be used to endorse or promote products\r *    derived from this software without specific prior written permission.\r *\r * THIS SOFTWARE IS PROVIDED `AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,\r * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY\r * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL\r * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\r * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;\r * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\r * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\r * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF\r * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r */\r \r#ifndef HAS_STRLCPY\rCoreExport size_t strlcat(char *dst, const char *src, size_t siz)\r{\r     char *d = dst;\r const char *s = src;\r   size_t n = siz, dlen;\r\r while (n-- != 0 && *d != '\0')\r         d++;\r\r  dlen = d - dst;\r        n = siz - dlen;\r\r       if (n == 0)\r            return(dlen + strlen(s));\r\r     while (*s != '\0')\r     {\r              if (n != 1)\r            {\r                      *d++ = *s;\r                     n--;\r           }\r\r             s++;\r   }\r\r     *d = '\0';\r     return(dlen + (s - src)); /* count does not include NUL */\r}\r\rCoreExport size_t strlcpy(char *dst, const char *src, size_t siz)\r{\r      char *d = dst;\r const char *s = src;\r   size_t n = siz;\r\r       /* Copy as many bytes as will fit */\r   if (n != 0 && --n != 0)\r        {\r              do\r             {\r                      if ((*d++ = *s++) == 0)\r                                break;\r         } while (--n != 0);\r    }\r\r     /* Not enough room in dst, add NUL and traverse rest of src */\r if (n == 0)\r    {\r              if (siz != 0)\r                  *d = '\0'; /* NUL-terminate dst */\r             while (*s++);\r  }\r\r     return(s - src - 1); /* count does not include NUL */\r}\r#endif\r\rCoreExport int charlcat(char* x,char y,int z)\r{\r        char* x__n = x;\r        int v = 0;\r\r    while(*x__n++)\r         v++;\r\r  if (v < z - 1)\r {\r              *--x__n = y;\r           *++x__n = 0;\r   }\r\r     return v;\r}\r\rCoreExport bool charremove(char* mp, char remove)\r{\r       char* mptr = mp;\r       bool shift_down = false;\r\r      while (*mptr)\r  {\r              if (*mptr == remove)\r           shift_down = true;\r\r            if (shift_down)\r                        *mptr = *(mptr+1);\r\r            mptr++;\r        }\r\r     return shift_down;\r}\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspstring.h"
+
+/*
+ * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright    
+ *    notice, this list of conditions and the following disclaimer in the  
+ *    documentation and/or other materials provided with the distribution. 
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED `AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef HAS_STRLCPY
+CoreExport size_t strlcat(char *dst, const char *src, size_t siz)
+{
+       char *d = dst;
+       const char *s = src;
+       size_t n = siz, dlen;
+
+       while (n-- != 0 && *d != '\0')
+               d++;
+
+       dlen = d - dst;
+       n = siz - dlen;
+
+       if (n == 0)
+               return(dlen + strlen(s));
+
+       while (*s != '\0')
+       {
+               if (n != 1)
+               {
+                       *d++ = *s;
+                       n--;
+               }
+
+               s++;
+       }
+
+       *d = '\0';
+       return(dlen + (s - src)); /* count does not include NUL */
+}
+
+CoreExport size_t strlcpy(char *dst, const char *src, size_t siz)
+{
+       char *d = dst;
+       const char *s = src;
+       size_t n = siz;
+
+       /* Copy as many bytes as will fit */
+       if (n != 0 && --n != 0)
+       {
+               do
+               {
+                       if ((*d++ = *s++) == 0)
+                               break;
+               } while (--n != 0);
+       }
+
+       /* Not enough room in dst, add NUL and traverse rest of src */
+       if (n == 0)
+       {
+               if (siz != 0)
+                       *d = '\0'; /* NUL-terminate dst */
+               while (*s++);
+       }
+
+       return(s - src - 1); /* count does not include NUL */
+}
+#endif
+
+CoreExport int charlcat(char* x,char y,int z)
+{
+       char* x__n = x;
+       int v = 0;
+
+       while(*x__n++)
+               v++;
+
+       if (v < z - 1)
+       {
+               *--x__n = y;
+               *++x__n = 0;
+       }
+
+       return v;
+}
+
+CoreExport bool charremove(char* mp, char remove)
+{
+       char* mptr = mp;
+       bool shift_down = false;
+
+       while (*mptr)
+       {
+               if (*mptr == remove)
+               shift_down = true;
+
+               if (shift_down)
+                       *mptr = *(mptr+1);
+
+               mptr++;
+       }
+
+       return shift_down;
+}
+
index cfb009273684ab0f97cefe527672e7f471f125f7..db120cfe587a59be26b676815fbc44f4002b8f90 100644 (file)
@@ -1 +1,1066 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "modules.h"\r#include "inspstring.h"\r#include "mode.h"\r\r/* +s (secret) */\r#include "modes/cmode_s.h"\r/* +p (private) */\r#include "modes/cmode_p.h"\r/* +b (bans) */\r#include "modes/cmode_b.h"\r/* +m (moderated) */\r#include "modes/cmode_m.h"\r/* +t (only (half) ops can change topic) */\r#include "modes/cmode_t.h"\r/* +n (no external messages) */\r#include "modes/cmode_n.h"\r/* +i (invite only) */\r#include "modes/cmode_i.h"\r/* +k (keyed channel) */\r#include "modes/cmode_k.h"\r/* +l (channel user limit) */\r#include "modes/cmode_l.h"\r/* +o (channel op) */\r#include "modes/cmode_o.h"\r/* +h (channel halfop) */\r#include "modes/cmode_h.h"\r/* +v (channel voice) */\r#include "modes/cmode_v.h"\r/* +s (server notices) */\r#include "modes/umode_s.h"\r/* +w (see wallops) */\r#include "modes/umode_w.h"\r/* +i (invisible) */\r#include "modes/umode_i.h"\r/* +o (operator) */\r#include "modes/umode_o.h"\r/* +n (notice mask - our implementation of snomasks) */\r#include "modes/umode_n.h"\r\rModeHandler::ModeHandler(InspIRCd* Instance, char modeletter, int parameters_on, int parameters_off, bool listmode, ModeType type, bool operonly, char mprefix)\r       : ServerInstance(Instance), mode(modeletter), n_params_on(parameters_on), n_params_off(parameters_off), list(listmode), m_type(type), oper(operonly), prefix(mprefix), count(0)\r{\r}\r\rModeHandler::~ModeHandler()\r{\r}\r\rbool ModeHandler::IsListMode()\r{\r return list;\r}\r\runsigned int ModeHandler::GetPrefixRank()\r{\r    return 0;\r}\r\runsigned int ModeHandler::GetCount()\r{\r    return 0;\r}\r\rvoid ModeHandler::ChangeCount(int modifier)\r{\r     count += modifier;\r}\r\rModeType ModeHandler::GetModeType()\r{\r    return m_type;\r}\r\rbool ModeHandler::NeedsOper()\r{\r      return oper;\r}\r\rchar ModeHandler::GetPrefix()\r{\r        return prefix;\r}\r\rint ModeHandler::GetNumParams(bool adding)\r{\r return adding ? n_params_on : n_params_off;\r}\r\rchar ModeHandler::GetModeChar()\r{\r       return mode;\r}\r\rModeAction ModeHandler::OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)\r{\r  return MODEACTION_DENY;\r}\r\rModePair ModeHandler::ModeSet(userrec* source, userrec* dest, chanrec* channel, const std::string &parameter)\r{\r     if (dest)\r      {\r              return std::make_pair(dest->IsModeSet(this->mode), "");\r        }\r      else\r   {\r              return std::make_pair(channel->IsModeSet(this->mode), "");\r     }\r}\r\rvoid ModeHandler::DisplayList(userrec* user, chanrec* channel)\r{\r}\r\rbool ModeHandler::CheckTimeStamp(time_t theirs, time_t ours, const std::string &their_param, const std::string &our_param, chanrec* channel)\r{\r        return (ours < theirs);\r}\r\rModeWatcher::ModeWatcher(InspIRCd* Instance, char modeletter, ModeType type) : ServerInstance(Instance), mode(modeletter), m_type(type)\r{\r}\r\rModeWatcher::~ModeWatcher()\r{\r}\r\rchar ModeWatcher::GetModeChar()\r{\r     return mode;\r}\r\rModeType ModeWatcher::GetModeType()\r{\r  return m_type;\r}\r\rbool ModeWatcher::BeforeMode(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding, ModeType type)\r{\r return true;\r}\r\rvoid ModeWatcher::AfterMode(userrec* source, userrec* dest, chanrec* channel, const std::string &parameter, bool adding, ModeType type)\r{\r}\r\ruserrec* ModeParser::SanityChecks(userrec *user,const char *dest,chanrec *chan,int status)\r{\r      userrec *d;\r    if ((!user) || (!dest) || (!chan) || (!*dest))\r {\r              return NULL;\r   }\r      d = ServerInstance->FindNick(dest);\r    if (!d)\r        {\r              user->WriteServ("401 %s %s :No such nick/channel",user->nick, dest);\r           return NULL;\r   }\r      return d;\r}\r\rconst char* ModeParser::Grant(userrec *d,chanrec *chan,int MASK)\r{\r        if (!chan)\r             return "";\r\r    UCListIter n = d->chans.find(chan);\r    if (n != d->chans.end())\r       {\r              if (n->second & MASK)\r          {\r                      return "";\r             }\r              n->second = n->second | MASK;\r          switch (MASK)\r          {\r                      case UCMODE_OP:\r                                n->first->AddOppedUser(d);\r                     break;\r                 case UCMODE_HOP:\r                               n->first->AddHalfoppedUser(d);\r                 break;\r                 case UCMODE_VOICE:\r                             n->first->AddVoicedUser(d);\r                    break;\r         }\r              return d->nick;\r        }\r      return "";\r}\r\rconst char* ModeParser::Revoke(userrec *d,chanrec *chan,int MASK)\r{\r      if (!chan)\r             return "";\r\r    UCListIter n = d->chans.find(chan);\r    if (n != d->chans.end())\r       {\r              if ((n->second & MASK) == 0)\r           {\r                      return "";\r             }\r              n->second ^= MASK;\r             switch (MASK)\r          {\r                      case UCMODE_OP:\r                                n->first->DelOppedUser(d);\r                     break;\r                 case UCMODE_HOP:\r                               n->first->DelHalfoppedUser(d);\r                 break;\r                 case UCMODE_VOICE:\r                             n->first->DelVoicedUser(d);\r                    break;\r         }\r              return d->nick;\r        }\r      return "";\r}\r\rvoid ModeParser::DisplayCurrentModes(userrec *user, userrec* targetuser, chanrec* targetchannel, const char* text)\r{\r     if (targetchannel)\r     {\r              /* Display channel's current mode string */\r            user->WriteServ("324 %s %s +%s",user->nick, targetchannel->name, targetchannel->ChanModes(targetchannel->HasUser(user)));\r              user->WriteServ("329 %s %s %lu", user->nick, targetchannel->name, (unsigned long)targetchannel->age);\r          return;\r        }\r      else if (targetuser)\r   {\r              if (targetuser->Visibility && !targetuser->Visibility->VisibleTo(user))\r                {\r                      user->WriteServ("401 %s %s :No such nick/channel",user->nick, text);\r                   return;\r                }\r\r             if ((targetuser == user) || (IS_OPER(user)))\r           {\r                      /* Display user's current mode string */\r                       user->WriteServ("221 %s :+%s",targetuser->nick,targetuser->FormatModes());\r                     if (IS_OPER(targetuser))\r                               user->WriteServ("008 %s +%s :Server notice mask", targetuser->nick, targetuser->FormatNoticeMasks());\r                  return;\r                }\r              else\r           {\r                      user->WriteServ("502 %s :Can't change mode for other users", user->nick);\r                      return;\r                }\r      }\r\r     /* No such nick/channel */\r     user->WriteServ("401 %s %s :No such nick/channel",user->nick, text);\r   return;\r}\r\rvoid ModeParser::Process(const char** parameters, int pcnt, userrec *user, bool servermode)\r{\r       std::string target = parameters[0];\r    ModeType type = MODETYPE_USER;\r unsigned char mask = 0;\r        chanrec* targetchannel = ServerInstance->FindChan(parameters[0]);\r      userrec* targetuser  = ServerInstance->FindNick(parameters[0]);\r\r       LastParse.clear();\r\r    /* Special case for displaying the list for listmodes,\r  * e.g. MODE #chan b, or MODE #chan +b without a parameter\r      */\r    if ((targetchannel) && (pcnt == 2))\r    {\r              const char* mode = parameters[1];\r              int nonlistmodes_found = 0;\r            bool sent[256];\r\r               mask = MASK_CHANNEL;\r\r          memset(&sent, 0, 256);\r         \r               while (mode && *mode)\r          {\r                      unsigned char mletter = *mode;\r\r                        if (*mode == '+')\r                      {\r                              mode++;\r                                continue;\r                      }\r\r                     /* Ensure the user doesnt request the same mode twice,\r                  * so they cant flood themselves off out of idiocy.\r                     */\r                    if (!sent[mletter])\r                    {\r                              sent[mletter] = true;\r                  }\r                      else\r                   {\r                              mode++;\r                                continue;\r                      }\r\r                     ModeHandler *mh = this->FindMode(*mode, MODETYPE_CHANNEL);\r                     bool display = true;\r\r                  if ((mh) && (mh->IsListMode()))\r                        {\r                              if (ServerInstance->Config->HideModeLists[mletter] && (targetchannel->GetStatus(user) < STATUS_HOP))\r                           {\r                                      user->WriteServ("482 %s %s :Only half-operators and above may view the +%c list",user->nick, targetchannel->name, *mode++);\r                                    continue;\r                              }\r\r                             /** See below for a description of what craq this is :D\r                                 */\r                            unsigned char handler_id = (*mode - 65) | mask;\r\r                               for(ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)\r                         {\r                                      std::string dummyparam;\r                                        \r                                       if (!((*watchers)->BeforeMode(user, NULL, targetchannel, dummyparam, true, MODETYPE_CHANNEL)))\r                                         display = false;\r                               }\r\r                             if (display)\r                                   mh->DisplayList(user, targetchannel);\r                  }\r                      else\r                           nonlistmodes_found++;\r\r                 mode++;\r                }\r\r             /* We didnt have any modes that were non-list, we can return here */\r           if (!nonlistmodes_found)\r                       return;\r        }\r\r     if (pcnt == 1)\r {\r              this->DisplayCurrentModes(user, targetuser, targetchannel, parameters[0]);\r     }\r      else if (pcnt > 1)\r     {\r              if (targetchannel)\r             {\r                      type = MODETYPE_CHANNEL;\r                       mask = MASK_CHANNEL;\r\r                  /* Extra security checks on channel modes\r                       * (e.g. are they a (half)op?\r                   */\r\r                   if ((IS_LOCAL(user)) && (targetchannel->GetStatus(user) < STATUS_HOP))\r                 {\r                              /* We don't have halfop */\r                             int MOD_RESULT = 0;\r                            FOREACH_RESULT(I_OnAccessCheck,OnAccessCheck(user, NULL, targetchannel, AC_GENERAL_MODE));\r                             if (MOD_RESULT == ACR_DENY)\r                                    return;\r\r                               if (MOD_RESULT == ACR_DEFAULT)\r                         {\r                                      /* Are we a uline or is it a servermode? */\r                                    if ((!ServerInstance->ULine(user->server)) && (!servermode))\r                                   {\r                                              /* Not enough permission:\r                                               * NOT a uline and NOT a servermode,\r                                            * OR, NOT halfop or above.\r                                             */\r                                            user->WriteServ("482 %s %s :You're not a channel (half)operator",user->nick, targetchannel->name);\r                                             return;\r                                        }\r                              }\r                      }\r              }\r              else if (targetuser)\r           {\r                      type = MODETYPE_USER;\r                  mask = MASK_USER;\r                      if ((user != targetuser) && (!ServerInstance->ULine(user->server)))\r                    {\r                              user->WriteServ("502 %s :Can't change mode for other users", user->nick);\r                              return;\r                        }\r              }\r              else\r           {\r                      /* No such nick/channel */\r                     user->WriteServ("401 %s %s :No such nick/channel",user->nick, parameters[0]);\r                  return;\r                }\r\r             std::string mode_sequence = parameters[1];\r             std::string parameter;\r         std::ostringstream parameter_list;\r             std::string output_sequence;\r           bool adding = true, state_change = false;\r              unsigned char handler_id = 0;\r          int parameter_counter = 2; /* Index of first parameter */\r              int parameter_count = 0;\r               bool last_successful_state_change = false;\r\r            /* A mode sequence that doesnt start with + or -. Assume +. - Thanks for the suggestion spike (bug#132) */\r             if ((*mode_sequence.begin() != '+') && (*mode_sequence.begin() != '-'))\r                        mode_sequence.insert(0, "+");\r\r         for (std::string::const_iterator letter = mode_sequence.begin(); letter != mode_sequence.end(); letter++)\r              {\r                      unsigned char modechar = *letter;\r\r                     switch (modechar)\r                      {\r                              /* NB:\r                          * For + and - mode characters, we don't just stick the character into the output sequence.\r                             * This is because the user may do something dumb, like: +-+ooo or +oo-+. To prevent this\r                               * appearing in the output sequence, we store a flag which says there was a state change,\r                               * which is set on any + or -, however, the + or - that we finish on is only appended to\r                                * the output stream in the event it is followed by a non "+ or -" character, such as o or v.\r                           */\r                            case '+':\r                                      /* The following expression prevents: +o+o nick nick, compressing it to +oo nick nick,\r                                  * however, will allow the + if it is the first item in the sequence, regardless.\r                                       */\r                                    if ((!adding) || (!output_sequence.length()))\r                                          state_change = true;\r                                   adding = true;\r                                 if (!output_sequence.length())\r                                         last_successful_state_change = false;\r                                  continue;\r                              break;\r                         case '-':\r                                      if ((adding) || (!output_sequence.length()))\r                                           state_change = true;\r                                   adding = false;\r                                        if (!output_sequence.length())\r                                         last_successful_state_change = true;\r                                   continue;\r                              break;\r                         default:\r\r                                      /**\r                                     * Watch carefully for the sleight of hand trick.\r                                       * 65 is the ascii value of 'A'. We take this from\r                                      * the char we're looking at to get a number between\r                                    * 1 and 127. We then logic-or it to get the hashed\r                                     * position, dependent on wether its a channel or\r                                       * a user mode. This is a little stranger, but a lot\r                                    * faster, than using a map of pairs.\r                                   */\r                                    handler_id = (modechar - 65) | mask;\r\r                                  if (modehandlers[handler_id])\r                                  {\r                                              bool abort = false;\r\r                                           if (modehandlers[handler_id]->GetModeType() == type)\r                                           {\r                                                      if (modehandlers[handler_id]->GetNumParams(adding))\r                                                    {\r                                                              /* This mode expects a parameter, do we have any parameters left in our list to use? */\r                                                                if (parameter_counter < pcnt)\r                                                          {\r                                                                      parameter = parameters[parameter_counter++];\r\r                                                                  /* Yerk, invalid! */\r                                                                   if ((parameter.find(':') == 0) || (parameter.rfind(' ') != std::string::npos))\r                                                                         parameter.clear();\r                                                             }\r                                                              else\r                                                           {\r                                                                      /* No parameter, continue to the next mode */\r                                                                  continue;\r                                                              }\r\r                                                             bool had_parameter = !parameter.empty();\r                                                               \r                                                               for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)\r                                                                {\r                                                                      if ((*watchers)->BeforeMode(user, targetuser, targetchannel, parameter, adding, type) == false)\r                                                                        {\r                                                                              abort = true;\r                                                                          break;\r                                                                 }\r                                                                      /* A module whacked the parameter completely, and there was one. abort. */\r                                                                     if ((had_parameter) && (parameter.empty()))\r                                                                    {\r                                                                              abort = true;\r                                                                          break;\r                                                                 }\r                                                              }\r\r                                                             if (abort)\r                                                                     continue;\r                                                      }\r                                                      else\r                                                   {\r                                                              /* Fix by brain: mode watchers not being called for parameterless modes */\r                                                             for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)\r                                                                {\r                                                                      if ((*watchers)->BeforeMode(user, targetuser, targetchannel, parameter, adding, type) == false)\r                                                                        {\r                                                                              abort = true;\r                                                                          break;\r                                                                 }\r                                                              }\r\r                                                             if (abort)\r                                                                     continue;\r                                                      }\r\r                                                     /* It's an oper only mode, check if theyre an oper. If they arent,\r                                                      * eat any parameter that  came with the mode, and continue to next\r                                                     */\r                                                    if ((IS_LOCAL(user)) && (modehandlers[handler_id]->NeedsOper()) && (!IS_OPER(user)))\r                                                   {\r                                                              user->WriteServ("481 %s :Permission Denied - Only IRC operators may %sset %s mode %c", user->nick,\r                                                                             adding ? "" : "un", type == MODETYPE_CHANNEL ? "channel" : "user",\r                                                                             modehandlers[handler_id]->GetModeChar());\r                                                              continue;\r                                                      }\r\r                                                     /* Call the handler for the mode */\r                                                    ModeAction ma = modehandlers[handler_id]->OnModeChange(user, targetuser, targetchannel, parameter, adding);\r\r                                                   if ((modehandlers[handler_id]->GetNumParams(adding)) && (parameter.empty()))\r                                                   {\r                                                              /* The handler nuked the parameter and they are supposed to have one.\r                                                           * We CANT continue now, even if they actually returned MODEACTION_ALLOW,\r                                                               * so we bail to the next mode character.\r                                                               */\r                                                            continue;\r                                                      }\r\r                                                     if (ma == MODEACTION_ALLOW)\r                                                    {\r                                                              /* We're about to output a valid mode letter - was there previously a pending state-change? */\r                                                         if (state_change)\r                                                              {\r                                                                      if (adding != last_successful_state_change)\r                                                                            output_sequence.append(adding ? "+" : "-");\r                                                                    last_successful_state_change = adding;\r                                                         }\r                                                              \r                                                               /* Add the mode letter */\r                                                              output_sequence.push_back(modechar);\r\r                                                          /* Is there a valid parameter for this mode? If so add it to the parameter list */\r                                                             if ((modehandlers[handler_id]->GetNumParams(adding)) && (!parameter.empty()))\r                                                          {\r                                                                      parameter_list << " " << parameter;\r                                                                    parameter_count++;\r                                                                     /* Does this mode have a prefix? */\r                                                                    if (modehandlers[handler_id]->GetPrefix() && targetchannel)\r                                                                    {\r                                                                              userrec* user_to_prefix = ServerInstance->FindNick(parameter);\r                                                                         if (user_to_prefix)\r                                                                                    targetchannel->SetPrefix(user_to_prefix, modehandlers[handler_id]->GetPrefix(),\r                                                                                                        modehandlers[handler_id]->GetPrefixRank(), adding);\r                                                                    }\r                                                              }\r\r                                                             /* Call all the AfterMode events in the mode watchers for this mode */\r                                                         for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)\r                                                                        (*watchers)->AfterMode(user, targetuser, targetchannel, parameter, adding, type);\r\r                                                             /* Reset the state change flag */\r                                                              state_change = false;\r\r                                                         if ((output_sequence.length() + parameter_list.str().length() > 450) || (output_sequence.length() > 100)\r                                                                               || (parameter_count > MAXMODES))\r                                                               {\r                                                                      /* We cant have a mode sequence this long */\r                                                                   letter = mode_sequence.end() - 1;\r                                                                      continue;\r                                                              }\r                                                      }\r                                              }\r                                      }\r                                      else\r                                   {\r                                              /* No mode handler? Unknown mode character then. */\r                                            user->WriteServ("472 %s %c :is unknown mode char to me",user->nick, modechar);\r                                 }\r                              break;\r                 }\r              }\r\r             /* Was there at least one valid mode in the sequence? */\r               if (!output_sequence.empty())\r          {\r                      if (servermode)\r                        {\r                              if (type == MODETYPE_CHANNEL)\r                          {\r                                      targetchannel->WriteChannelWithServ(ServerInstance->Config->ServerName, "MODE %s %s%s", targetchannel->name, output_sequence.c_str(), parameter_list.str().c_str());\r                                   this->LastParse = targetchannel->name;\r                         }\r                              else\r                           {\r                                      targetuser->WriteServ("MODE %s %s%s",targetuser->nick,output_sequence.c_str(), parameter_list.str().c_str());\r                                  this->LastParse = targetuser->nick;\r                            }\r                      }\r                      else\r                   {\r                              if (type == MODETYPE_CHANNEL)\r                          {\r                                      targetchannel->WriteChannel(user,"MODE %s %s%s",targetchannel->name,output_sequence.c_str(),parameter_list.str().c_str());\r                                     FOREACH_MOD(I_OnMode,OnMode(user, targetchannel, TYPE_CHANNEL, output_sequence + parameter_list.str()));\r                                       this->LastParse = targetchannel->name;\r                         }\r                              else\r                           {\r                                      user->WriteTo(targetuser,"MODE %s %s%s",targetuser->nick,output_sequence.c_str(), parameter_list.str().c_str());\r                                       FOREACH_MOD(I_OnMode,OnMode(user, targetuser, TYPE_USER, output_sequence + parameter_list.str()));\r                                     this->LastParse = targetuser->nick;\r                            }\r                      }\r\r                     LastParse.append(" ");\r                 LastParse.append(output_sequence);\r                     LastParse.append(parameter_list.str());\r                }\r      }\r}\r\rconst std::string& ModeParser::GetLastParse()\r{\r   return LastParse;\r}\r\rvoid ModeParser::CleanMask(std::string &mask)\r{\r   std::string::size_type pos_of_pling = mask.find_first_of('!');\r std::string::size_type pos_of_at = mask.find_first_of('@');\r    std::string::size_type pos_of_dot = mask.find_first_of('.');\r   std::string::size_type pos_of_colon = mask.find_first_of(':'); /* Because ipv6 addresses are colon delimited */\r\r       if ((pos_of_pling == std::string::npos) && (pos_of_at == std::string::npos))\r   {\r              /* Just a nick, or just a host */\r              if ((pos_of_dot == std::string::npos) && (pos_of_colon == std::string::npos))\r          {\r                      /* It has no '.' in it, it must be a nick. */\r                  mask.append("!*@*");\r           }\r              else\r           {\r                      /* Got a dot in it? Has to be a host */\r                        mask = "*!*@" + mask;\r          }\r      }\r      else if ((pos_of_pling == std::string::npos) && (pos_of_at != std::string::npos))\r      {\r              /* Has an @ but no !, its a user@host */\r                mask = "*!" + mask;\r   }\r      else if ((pos_of_pling != std::string::npos) && (pos_of_at == std::string::npos))\r      {\r              /* Has a ! but no @, it must be a nick!ident */\r                mask.append("@*");\r     }\r}\r\rbool ModeParser::AddMode(ModeHandler* mh, unsigned const char modeletter)\r{\r       unsigned char mask = 0;\r        unsigned char pos = 0;\r\r        /* Yes, i know, this might let people declare modes like '_' or '^'.\r    * If they do that, thats their problem, and if i ever EVER see an\r      * official InspIRCd developer do that, i'll beat them with a paddle!\r   */\r    if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z') || (mh->GetPrefix() > 126))\r         return false;\r\r /* A mode prefix of ',' is not acceptable, it would fuck up server to server.\r   * A mode prefix of ':' will fuck up both server to server, and client to server.\r       * A mode prefix of '#' will mess up /whois and /privmsg\r        */\r    if ((mh->GetPrefix() == ',') || (mh->GetPrefix() == ':') || (mh->GetPrefix() == '#'))\r          return false;\r\r mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;\r   pos = (mh->GetModeChar()-65) | mask;\r\r  if (modehandlers[pos])\r         return false;\r\r modehandlers[pos] = mh;\r        return true;\r}\r\rbool ModeParser::DelMode(ModeHandler* mh)\r{\r    unsigned char mask = 0;\r        unsigned char pos = 0;\r\r        if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z'))\r            return false;\r\r mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;\r   pos = (mh->GetModeChar()-65) | mask;\r\r  if (!modehandlers[pos])\r                return false;\r\r switch (mh->GetModeType())\r     {\r              case MODETYPE_USER:\r                    for (user_hash::iterator i = ServerInstance->clientlist->begin(); i != ServerInstance->clientlist->end(); i++)\r                 {\r                              mh->RemoveMode(i->second);\r                     }\r              break;\r         case MODETYPE_CHANNEL:\r                 for (chan_hash::iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++)\r                     {\r                              mh->RemoveMode(i->second);\r                     }\r              break;\r }\r\r     modehandlers[pos] = NULL;\r\r     return true;\r}\r\rModeHandler* ModeParser::FindMode(unsigned const char modeletter, ModeType mt)\r{\r       unsigned char mask = 0;\r        unsigned char pos = 0;\r\r        if ((modeletter < 'A') || (modeletter > 'z'))\r          return NULL;\r\r  mt == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;\r  pos = (modeletter-65) | mask;\r\r return modehandlers[pos];\r}\r\rstd::string ModeParser::UserModeList()\r{\r  char modestr[256];\r     int pointer = 0;\r\r      for (unsigned char mode = 'A'; mode <= 'z'; mode++)\r    {\r              unsigned char pos = (mode-65) | MASK_USER;\r\r            if (modehandlers[pos])\r                 modestr[pointer++] = mode;\r     }\r      modestr[pointer++] = 0;\r        return modestr;\r}\r\rstd::string ModeParser::ChannelModeList()\r{\r char modestr[256];\r     int pointer = 0;\r\r      for (unsigned char mode = 'A'; mode <= 'z'; mode++)\r    {\r              if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))\r                   continue;\r\r             unsigned char pos = (mode-65) | MASK_CHANNEL;\r\r         if (modehandlers[pos])\r                 modestr[pointer++] = mode;\r     }\r      modestr[pointer++] = 0;\r        return modestr;\r}\r\rstd::string ModeParser::ParaModeList()\r{\r    char modestr[256];\r     int pointer = 0;\r\r      for (unsigned char mode = 'A'; mode <= 'z'; mode++)\r    {\r              if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))\r                   continue;\r\r             unsigned char pos = (mode-65) | MASK_CHANNEL;\r\r         if ((modehandlers[pos]) && (modehandlers[pos]->GetNumParams(true)))\r                    modestr[pointer++] = mode;\r     }\r      modestr[pointer++] = 0;\r        return modestr;\r}\r\rModeHandler* ModeParser::FindPrefix(unsigned const char pfxletter)\r{\r        for (unsigned char mode = 'A'; mode <= 'z'; mode++)\r    {\r              unsigned char pos = (mode-65) | MASK_CHANNEL;\r\r         if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix() == pfxletter))\r              {\r                      return modehandlers[pos];\r              }\r      }\r      return NULL;\r}\r\rstd::string ModeParser::ModeString(userrec* user, chanrec* channel)\r{\r  std::string types;\r     std::string pars;\r\r     if (!channel || !user)\r         return "";\r\r    for (unsigned char mode = 'A'; mode <= 'z'; mode++)\r    {\r              unsigned char pos = (mode-65) | MASK_CHANNEL;\r          ModeHandler* mh = modehandlers[pos];\r           if ((mh) && (mh->GetNumParams(true)) && (mh->GetNumParams(false)))\r             {\r                      ModePair ret;\r                  ret = mh->ModeSet(NULL, user, channel, user->nick);\r                    if ((ret.first) && (ret.second == user->nick))\r                 {\r                              pars.append(" ");\r                              pars.append(user->nick);\r                               types.push_back(mh->GetModeChar());\r                    }\r              }\r      }\r\r     return types+pars;\r}\r\rstd::string ModeParser::ChanModes()\r{\r    std::string type1;      /* Listmodes EXCEPT those with a prefix */\r     std::string type2;      /* Modes that take a param when adding or removing */\r  std::string type3;      /* Modes that only take a param when adding */\r std::string type4;      /* Modes that dont take a param */\r\r    for (unsigned char mode = 'A'; mode <= 'z'; mode++)\r    {\r              if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))\r                   continue;\r\r             unsigned char pos = (mode-65) | MASK_CHANNEL;\r           /* One parameter when adding */\r               if (modehandlers[pos])\r         {       \r                       if (modehandlers[pos]->GetNumParams(true))\r                     {\r                              if ((modehandlers[pos]->IsListMode()) && (!modehandlers[pos]->GetPrefix()))\r                            {\r                                      type1 += modehandlers[pos]->GetModeChar();\r                             }\r                              else\r                           {\r                                      /* ... and one parameter when removing */\r                                      if (modehandlers[pos]->GetNumParams(false))\r                                    {\r                                              /* But not a list mode */\r                                              if (!modehandlers[pos]->GetPrefix())\r                                           {\r                                                      type2 += modehandlers[pos]->GetModeChar();\r                                             }\r                                      }\r                                      else\r                                   {\r                                              /* No parameters when removing */\r                                              type3 += modehandlers[pos]->GetModeChar();\r                                     }\r                              }\r                      }\r                      else\r                   {\r                              type4 += modehandlers[pos]->GetModeChar();\r                     }\r              }\r                       \r      }\r\r     return type1 + "," + type2 + "," + type3 + "," + type4;\r}\r\rbool ModeParser::PrefixComparison(prefixtype one, prefixtype two)\r{       \r  return one.second > two.second;\r}\r\rstd::string ModeParser::BuildPrefixes()\r{\r   std::string mletters;\r  std::string mprefixes;\r pfxcontainer pfx;\r      std::map<char,char> prefix_to_mode;\r\r   for (unsigned char mode = 'A'; mode <= 'z'; mode++)\r    {\r              if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))\r                   continue;\r\r             unsigned char pos = (mode-65) | MASK_CHANNEL;\r\r         if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix()))\r           {\r                      pfx.push_back(std::make_pair<char,unsigned int>(modehandlers[pos]->GetPrefix(), modehandlers[pos]->GetPrefixRank()));\r                  prefix_to_mode[modehandlers[pos]->GetPrefix()] = modehandlers[pos]->GetModeChar();\r             }\r      }\r\r     sort(pfx.begin(), pfx.end(), ModeParser::PrefixComparison);\r\r   for (pfxcontainer::iterator n = pfx.begin(); n != pfx.end(); n++)\r      {\r              mletters = mletters + n->first;\r                mprefixes = mprefixes + prefix_to_mode.find(n->first)->second;\r }\r\r     return "(" + mprefixes + ")" + mletters;\r}\r\rbool ModeParser::AddModeWatcher(ModeWatcher* mw)\r{\r unsigned char mask = 0;\r        unsigned char pos = 0;\r\r        if (!mw)\r               return false;\r\r if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))\r            return false;\r\r mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;\r   pos = (mw->GetModeChar()-65) | mask;\r\r  modewatchers[pos].push_back(mw);\r\r      return true;\r}\r\rbool ModeParser::DelModeWatcher(ModeWatcher* mw)\r{\r     unsigned char mask = 0;\r        unsigned char pos = 0;\r\r        if (!mw)\r               return false;\r\r if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))\r            return false;\r\r mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;\r   pos = (mw->GetModeChar()-65) | mask;\r\r  ModeWatchIter a = find(modewatchers[pos].begin(),modewatchers[pos].end(),mw);\r\r if (a == modewatchers[pos].end())\r      {\r              return false;\r  }\r\r     modewatchers[pos].erase(a);\r\r   return true;\r}\r\r/** This default implementation can remove simple user modes\r */\rvoid ModeHandler::RemoveMode(userrec* user)\r{\r char moderemove[MAXBUF];\r       const char* parameters[] = { user->nick, moderemove };\r\r        if (user->IsModeSet(this->GetModeChar()))\r      {\r              sprintf(moderemove,"-%c",this->GetModeChar());\r         ServerInstance->Parser->CallHandler("MODE", parameters, 2, user);\r      }\r}\r\r/** This default implementation can remove simple channel modes\r * (no parameters)\r */\rvoid ModeHandler::RemoveMode(chanrec* channel)\r{\r   char moderemove[MAXBUF];\r       const char* parameters[] = { channel->name, moderemove };\r\r     if (channel->IsModeSet(this->GetModeChar()))\r   {\r              userrec* n = new userrec(ServerInstance);\r\r             sprintf(moderemove,"-%c",this->GetModeChar());\r         n->SetFd(FD_MAGIC_NUMBER);\r\r            ServerInstance->SendMode(parameters, 2, n);\r\r           delete n;\r      }\r}\r\rModeParser::ModeParser(InspIRCd* Instance) : ServerInstance(Instance)\r{\r   struct Initializer\r     {\r              char modechar;\r         ModeHandler* handler;\r  };\r\r    Initializer modes[] = {\r                { 's', new ModeChannelSecret(Instance) },\r              { 'p', new ModeChannelPrivate(Instance) },\r             { 'm', new ModeChannelModerated(Instance) },\r           { 't', new ModeChannelTopicOps(Instance) },\r            { 'n', new ModeChannelNoExternal(Instance) },\r          { 'i', new ModeChannelInviteOnly(Instance) },\r          { 'k', new ModeChannelKey(Instance) },\r         { 'l', new ModeChannelLimit(Instance) },\r               { 'b', new ModeChannelBan(Instance) },\r         { 'o', new ModeChannelOp(Instance) },\r          { 'h', new ModeChannelHalfOp(Instance) },\r              { 'v', new ModeChannelVoice(Instance) },\r               { 's', new ModeUserServerNotice(Instance) },\r           { 'w', new ModeUserWallops(Instance) },\r                { 'i', new ModeUserInvisible(Instance) },\r              { 'o', new ModeUserOperator(Instance) },\r               { 'n', new ModeUserServerNoticeMask(Instance) },\r               { 0, NULL }\r    };\r\r    /* Clear mode list */\r  memset(modehandlers, 0, sizeof(modehandlers));\r memset(modewatchers, 0, sizeof(modewatchers));\r\r        /* Last parse string */\r        LastParse.clear();\r\r    /* Initialise the RFC mode letters */\r  for (int index = 0; modes[index].modechar; index++)\r            this->AddMode(modes[index].handler, modes[index].modechar);\r}\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "modules.h"
+#include "inspstring.h"
+#include "mode.h"
+
+/* +s (secret) */
+#include "modes/cmode_s.h"
+/* +p (private) */
+#include "modes/cmode_p.h"
+/* +b (bans) */
+#include "modes/cmode_b.h"
+/* +m (moderated) */
+#include "modes/cmode_m.h"
+/* +t (only (half) ops can change topic) */
+#include "modes/cmode_t.h"
+/* +n (no external messages) */
+#include "modes/cmode_n.h"
+/* +i (invite only) */
+#include "modes/cmode_i.h"
+/* +k (keyed channel) */
+#include "modes/cmode_k.h"
+/* +l (channel user limit) */
+#include "modes/cmode_l.h"
+/* +o (channel op) */
+#include "modes/cmode_o.h"
+/* +h (channel halfop) */
+#include "modes/cmode_h.h"
+/* +v (channel voice) */
+#include "modes/cmode_v.h"
+/* +s (server notices) */
+#include "modes/umode_s.h"
+/* +w (see wallops) */
+#include "modes/umode_w.h"
+/* +i (invisible) */
+#include "modes/umode_i.h"
+/* +o (operator) */
+#include "modes/umode_o.h"
+/* +n (notice mask - our implementation of snomasks) */
+#include "modes/umode_n.h"
+
+ModeHandler::ModeHandler(InspIRCd* Instance, char modeletter, int parameters_on, int parameters_off, bool listmode, ModeType type, bool operonly, char mprefix)
+       : ServerInstance(Instance), mode(modeletter), n_params_on(parameters_on), n_params_off(parameters_off), list(listmode), m_type(type), oper(operonly), prefix(mprefix), count(0)
+{
+}
+
+ModeHandler::~ModeHandler()
+{
+}
+
+bool ModeHandler::IsListMode()
+{
+       return list;
+}
+
+unsigned int ModeHandler::GetPrefixRank()
+{
+       return 0;
+}
+
+unsigned int ModeHandler::GetCount()
+{
+       return 0;
+}
+
+void ModeHandler::ChangeCount(int modifier)
+{
+       count += modifier;
+}
+
+ModeType ModeHandler::GetModeType()
+{
+       return m_type;
+}
+
+bool ModeHandler::NeedsOper()
+{
+       return oper;
+}
+
+char ModeHandler::GetPrefix()
+{
+       return prefix;
+}
+
+int ModeHandler::GetNumParams(bool adding)
+{
+       return adding ? n_params_on : n_params_off;
+}
+
+char ModeHandler::GetModeChar()
+{
+       return mode;
+}
+
+ModeAction ModeHandler::OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)
+{
+       return MODEACTION_DENY;
+}
+
+ModePair ModeHandler::ModeSet(userrec* source, userrec* dest, chanrec* channel, const std::string &parameter)
+{
+       if (dest)
+       {
+               return std::make_pair(dest->IsModeSet(this->mode), "");
+       }
+       else
+       {
+               return std::make_pair(channel->IsModeSet(this->mode), "");
+       }
+}
+
+void ModeHandler::DisplayList(userrec* user, chanrec* channel)
+{
+}
+
+bool ModeHandler::CheckTimeStamp(time_t theirs, time_t ours, const std::string &their_param, const std::string &our_param, chanrec* channel)
+{
+       return (ours < theirs);
+}
+
+ModeWatcher::ModeWatcher(InspIRCd* Instance, char modeletter, ModeType type) : ServerInstance(Instance), mode(modeletter), m_type(type)
+{
+}
+
+ModeWatcher::~ModeWatcher()
+{
+}
+
+char ModeWatcher::GetModeChar()
+{
+       return mode;
+}
+
+ModeType ModeWatcher::GetModeType()
+{
+       return m_type;
+}
+
+bool ModeWatcher::BeforeMode(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding, ModeType type)
+{
+       return true;
+}
+
+void ModeWatcher::AfterMode(userrec* source, userrec* dest, chanrec* channel, const std::string &parameter, bool adding, ModeType type)
+{
+}
+
+userrec* ModeParser::SanityChecks(userrec *user,const char *dest,chanrec *chan,int status)
+{
+       userrec *d;
+       if ((!user) || (!dest) || (!chan) || (!*dest))
+       {
+               return NULL;
+       }
+       d = ServerInstance->FindNick(dest);
+       if (!d)
+       {
+               user->WriteServ("401 %s %s :No such nick/channel",user->nick, dest);
+               return NULL;
+       }
+       return d;
+}
+
+const char* ModeParser::Grant(userrec *d,chanrec *chan,int MASK)
+{
+       if (!chan)
+               return "";
+
+       UCListIter n = d->chans.find(chan);
+       if (n != d->chans.end())
+       {
+               if (n->second & MASK)
+               {
+                       return "";
+               }
+               n->second = n->second | MASK;
+               switch (MASK)
+               {
+                       case UCMODE_OP:
+                               n->first->AddOppedUser(d);
+                       break;
+                       case UCMODE_HOP:
+                               n->first->AddHalfoppedUser(d);
+                       break;
+                       case UCMODE_VOICE:
+                               n->first->AddVoicedUser(d);
+                       break;
+               }
+               return d->nick;
+       }
+       return "";
+}
+
+const char* ModeParser::Revoke(userrec *d,chanrec *chan,int MASK)
+{
+       if (!chan)
+               return "";
+
+       UCListIter n = d->chans.find(chan);
+       if (n != d->chans.end())
+       {
+               if ((n->second & MASK) == 0)
+               {
+                       return "";
+               }
+               n->second ^= MASK;
+               switch (MASK)
+               {
+                       case UCMODE_OP:
+                               n->first->DelOppedUser(d);
+                       break;
+                       case UCMODE_HOP:
+                               n->first->DelHalfoppedUser(d);
+                       break;
+                       case UCMODE_VOICE:
+                               n->first->DelVoicedUser(d);
+                       break;
+               }
+               return d->nick;
+       }
+       return "";
+}
+
+void ModeParser::DisplayCurrentModes(userrec *user, userrec* targetuser, chanrec* targetchannel, const char* text)
+{
+       if (targetchannel)
+       {
+               /* Display channel's current mode string */
+               user->WriteServ("324 %s %s +%s",user->nick, targetchannel->name, targetchannel->ChanModes(targetchannel->HasUser(user)));
+               user->WriteServ("329 %s %s %lu", user->nick, targetchannel->name, (unsigned long)targetchannel->age);
+               return;
+       }
+       else if (targetuser)
+       {
+               if (targetuser->Visibility && !targetuser->Visibility->VisibleTo(user))
+               {
+                       user->WriteServ("401 %s %s :No such nick/channel",user->nick, text);
+                       return;
+               }
+
+               if ((targetuser == user) || (IS_OPER(user)))
+               {
+                       /* Display user's current mode string */
+                       user->WriteServ("221 %s :+%s",targetuser->nick,targetuser->FormatModes());
+                       if (IS_OPER(targetuser))
+                               user->WriteServ("008 %s +%s :Server notice mask", targetuser->nick, targetuser->FormatNoticeMasks());
+                       return;
+               }
+               else
+               {
+                       user->WriteServ("502 %s :Can't change mode for other users", user->nick);
+                       return;
+               }
+       }
+
+       /* No such nick/channel */
+       user->WriteServ("401 %s %s :No such nick/channel",user->nick, text);
+       return;
+}
+
+void ModeParser::Process(const char** parameters, int pcnt, userrec *user, bool servermode)
+{
+       std::string target = parameters[0];
+       ModeType type = MODETYPE_USER;
+       unsigned char mask = 0;
+       chanrec* targetchannel = ServerInstance->FindChan(parameters[0]);
+       userrec* targetuser  = ServerInstance->FindNick(parameters[0]);
+
+       LastParse.clear();
+
+       /* Special case for displaying the list for listmodes,
+        * e.g. MODE #chan b, or MODE #chan +b without a parameter
+        */
+       if ((targetchannel) && (pcnt == 2))
+       {
+               const char* mode = parameters[1];
+               int nonlistmodes_found = 0;
+               bool sent[256];
+
+               mask = MASK_CHANNEL;
+
+               memset(&sent, 0, 256);
+               
+               while (mode && *mode)
+               {
+                       unsigned char mletter = *mode;
+
+                       if (*mode == '+')
+                       {
+                               mode++;
+                               continue;
+                       }
+
+                       /* Ensure the user doesnt request the same mode twice,
+                        * so they cant flood themselves off out of idiocy.
+                        */
+                       if (!sent[mletter])
+                       {
+                               sent[mletter] = true;
+                       }
+                       else
+                       {
+                               mode++;
+                               continue;
+                       }
+
+                       ModeHandler *mh = this->FindMode(*mode, MODETYPE_CHANNEL);
+                       bool display = true;
+
+                       if ((mh) && (mh->IsListMode()))
+                       {
+                               if (ServerInstance->Config->HideModeLists[mletter] && (targetchannel->GetStatus(user) < STATUS_HOP))
+                               {
+                                       user->WriteServ("482 %s %s :Only half-operators and above may view the +%c list",user->nick, targetchannel->name, *mode++);
+                                       continue;
+                               }
+
+                               /** See below for a description of what craq this is :D
+                                */
+                               unsigned char handler_id = (*mode - 65) | mask;
+
+                               for(ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
+                               {
+                                       std::string dummyparam;
+                                       
+                                       if (!((*watchers)->BeforeMode(user, NULL, targetchannel, dummyparam, true, MODETYPE_CHANNEL)))
+                                               display = false;
+                               }
+
+                               if (display)
+                                       mh->DisplayList(user, targetchannel);
+                       }
+                       else
+                               nonlistmodes_found++;
+
+                       mode++;
+               }
+
+               /* We didnt have any modes that were non-list, we can return here */
+               if (!nonlistmodes_found)
+                       return;
+       }
+
+       if (pcnt == 1)
+       {
+               this->DisplayCurrentModes(user, targetuser, targetchannel, parameters[0]);
+       }
+       else if (pcnt > 1)
+       {
+               if (targetchannel)
+               {
+                       type = MODETYPE_CHANNEL;
+                       mask = MASK_CHANNEL;
+
+                       /* Extra security checks on channel modes
+                        * (e.g. are they a (half)op?
+                        */
+
+                       if ((IS_LOCAL(user)) && (targetchannel->GetStatus(user) < STATUS_HOP))
+                       {
+                               /* We don't have halfop */
+                               int MOD_RESULT = 0;
+                               FOREACH_RESULT(I_OnAccessCheck,OnAccessCheck(user, NULL, targetchannel, AC_GENERAL_MODE));
+                               if (MOD_RESULT == ACR_DENY)
+                                       return;
+
+                               if (MOD_RESULT == ACR_DEFAULT)
+                               {
+                                       /* Are we a uline or is it a servermode? */
+                                       if ((!ServerInstance->ULine(user->server)) && (!servermode))
+                                       {
+                                               /* Not enough permission:
+                                                * NOT a uline and NOT a servermode,
+                                                * OR, NOT halfop or above.
+                                                */
+                                               user->WriteServ("482 %s %s :You're not a channel (half)operator",user->nick, targetchannel->name);
+                                               return;
+                                       }
+                               }
+                       }
+               }
+               else if (targetuser)
+               {
+                       type = MODETYPE_USER;
+                       mask = MASK_USER;
+                       if ((user != targetuser) && (!ServerInstance->ULine(user->server)))
+                       {
+                               user->WriteServ("502 %s :Can't change mode for other users", user->nick);
+                               return;
+                       }
+               }
+               else
+               {
+                       /* No such nick/channel */
+                       user->WriteServ("401 %s %s :No such nick/channel",user->nick, parameters[0]);
+                       return;
+               }
+
+               std::string mode_sequence = parameters[1];
+               std::string parameter;
+               std::ostringstream parameter_list;
+               std::string output_sequence;
+               bool adding = true, state_change = false;
+               unsigned char handler_id = 0;
+               int parameter_counter = 2; /* Index of first parameter */
+               int parameter_count = 0;
+               bool last_successful_state_change = false;
+
+               /* A mode sequence that doesnt start with + or -. Assume +. - Thanks for the suggestion spike (bug#132) */
+               if ((*mode_sequence.begin() != '+') && (*mode_sequence.begin() != '-'))
+                       mode_sequence.insert(0, "+");
+
+               for (std::string::const_iterator letter = mode_sequence.begin(); letter != mode_sequence.end(); letter++)
+               {
+                       unsigned char modechar = *letter;
+
+                       switch (modechar)
+                       {
+                               /* NB:
+                                * For + and - mode characters, we don't just stick the character into the output sequence.
+                                * This is because the user may do something dumb, like: +-+ooo or +oo-+. To prevent this
+                                * appearing in the output sequence, we store a flag which says there was a state change,
+                                * which is set on any + or -, however, the + or - that we finish on is only appended to
+                                * the output stream in the event it is followed by a non "+ or -" character, such as o or v.
+                                */
+                               case '+':
+                                       /* The following expression prevents: +o+o nick nick, compressing it to +oo nick nick,
+                                        * however, will allow the + if it is the first item in the sequence, regardless.
+                                        */
+                                       if ((!adding) || (!output_sequence.length()))
+                                               state_change = true;
+                                       adding = true;
+                                       if (!output_sequence.length())
+                                               last_successful_state_change = false;
+                                       continue;
+                               break;
+                               case '-':
+                                       if ((adding) || (!output_sequence.length()))
+                                               state_change = true;
+                                       adding = false;
+                                       if (!output_sequence.length())
+                                               last_successful_state_change = true;
+                                       continue;
+                               break;
+                               default:
+
+                                       /**
+                                        * Watch carefully for the sleight of hand trick.
+                                        * 65 is the ascii value of 'A'. We take this from
+                                        * the char we're looking at to get a number between
+                                        * 1 and 127. We then logic-or it to get the hashed
+                                        * position, dependent on wether its a channel or
+                                        * a user mode. This is a little stranger, but a lot
+                                        * faster, than using a map of pairs.
+                                        */
+                                       handler_id = (modechar - 65) | mask;
+
+                                       if (modehandlers[handler_id])
+                                       {
+                                               bool abort = false;
+
+                                               if (modehandlers[handler_id]->GetModeType() == type)
+                                               {
+                                                       if (modehandlers[handler_id]->GetNumParams(adding))
+                                                       {
+                                                               /* This mode expects a parameter, do we have any parameters left in our list to use? */
+                                                               if (parameter_counter < pcnt)
+                                                               {
+                                                                       parameter = parameters[parameter_counter++];
+
+                                                                       /* Yerk, invalid! */
+                                                                       if ((parameter.find(':') == 0) || (parameter.rfind(' ') != std::string::npos))
+                                                                               parameter.clear();
+                                                               }
+                                                               else
+                                                               {
+                                                                       /* No parameter, continue to the next mode */
+                                                                       continue;
+                                                               }
+
+                                                               bool had_parameter = !parameter.empty();
+                                                               
+                                                               for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
+                                                               {
+                                                                       if ((*watchers)->BeforeMode(user, targetuser, targetchannel, parameter, adding, type) == false)
+                                                                       {
+                                                                               abort = true;
+                                                                               break;
+                                                                       }
+                                                                       /* A module whacked the parameter completely, and there was one. abort. */
+                                                                       if ((had_parameter) && (parameter.empty()))
+                                                                       {
+                                                                               abort = true;
+                                                                               break;
+                                                                       }
+                                                               }
+
+                                                               if (abort)
+                                                                       continue;
+                                                       }
+                                                       else
+                                                       {
+                                                               /* Fix by brain: mode watchers not being called for parameterless modes */
+                                                               for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
+                                                               {
+                                                                       if ((*watchers)->BeforeMode(user, targetuser, targetchannel, parameter, adding, type) == false)
+                                                                       {
+                                                                               abort = true;
+                                                                               break;
+                                                                       }
+                                                               }
+
+                                                               if (abort)
+                                                                       continue;
+                                                       }
+
+                                                       /* It's an oper only mode, check if theyre an oper. If they arent,
+                                                        * eat any parameter that  came with the mode, and continue to next
+                                                        */
+                                                       if ((IS_LOCAL(user)) && (modehandlers[handler_id]->NeedsOper()) && (!IS_OPER(user)))
+                                                       {
+                                                               user->WriteServ("481 %s :Permission Denied - Only IRC operators may %sset %s mode %c", user->nick,
+                                                                               adding ? "" : "un", type == MODETYPE_CHANNEL ? "channel" : "user",
+                                                                               modehandlers[handler_id]->GetModeChar());
+                                                               continue;
+                                                       }
+
+                                                       /* Call the handler for the mode */
+                                                       ModeAction ma = modehandlers[handler_id]->OnModeChange(user, targetuser, targetchannel, parameter, adding);
+
+                                                       if ((modehandlers[handler_id]->GetNumParams(adding)) && (parameter.empty()))
+                                                       {
+                                                               /* The handler nuked the parameter and they are supposed to have one.
+                                                                * We CANT continue now, even if they actually returned MODEACTION_ALLOW,
+                                                                * so we bail to the next mode character.
+                                                                */
+                                                               continue;
+                                                       }
+
+                                                       if (ma == MODEACTION_ALLOW)
+                                                       {
+                                                               /* We're about to output a valid mode letter - was there previously a pending state-change? */
+                                                               if (state_change)
+                                                               {
+                                                                       if (adding != last_successful_state_change)
+                                                                               output_sequence.append(adding ? "+" : "-");
+                                                                       last_successful_state_change = adding;
+                                                               }
+                                                               
+                                                               /* Add the mode letter */
+                                                               output_sequence.push_back(modechar);
+
+                                                               /* Is there a valid parameter for this mode? If so add it to the parameter list */
+                                                               if ((modehandlers[handler_id]->GetNumParams(adding)) && (!parameter.empty()))
+                                                               {
+                                                                       parameter_list << " " << parameter;
+                                                                       parameter_count++;
+                                                                       /* Does this mode have a prefix? */
+                                                                       if (modehandlers[handler_id]->GetPrefix() && targetchannel)
+                                                                       {
+                                                                               userrec* user_to_prefix = ServerInstance->FindNick(parameter);
+                                                                               if (user_to_prefix)
+                                                                                       targetchannel->SetPrefix(user_to_prefix, modehandlers[handler_id]->GetPrefix(),
+                                                                                                       modehandlers[handler_id]->GetPrefixRank(), adding);
+                                                                       }
+                                                               }
+
+                                                               /* Call all the AfterMode events in the mode watchers for this mode */
+                                                               for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
+                                                                       (*watchers)->AfterMode(user, targetuser, targetchannel, parameter, adding, type);
+
+                                                               /* Reset the state change flag */
+                                                               state_change = false;
+
+                                                               if ((output_sequence.length() + parameter_list.str().length() > 450) || (output_sequence.length() > 100)
+                                                                               || (parameter_count > MAXMODES))
+                                                               {
+                                                                       /* We cant have a mode sequence this long */
+                                                                       letter = mode_sequence.end() - 1;
+                                                                       continue;
+                                                               }
+                                                       }
+                                               }
+                                       }
+                                       else
+                                       {
+                                               /* No mode handler? Unknown mode character then. */
+                                               user->WriteServ("472 %s %c :is unknown mode char to me",user->nick, modechar);
+                                       }
+                               break;
+                       }
+               }
+
+               /* Was there at least one valid mode in the sequence? */
+               if (!output_sequence.empty())
+               {
+                       if (servermode)
+                       {
+                               if (type == MODETYPE_CHANNEL)
+                               {
+                                       targetchannel->WriteChannelWithServ(ServerInstance->Config->ServerName, "MODE %s %s%s", targetchannel->name, output_sequence.c_str(), parameter_list.str().c_str());
+                                       this->LastParse = targetchannel->name;
+                               }
+                               else
+                               {
+                                       targetuser->WriteServ("MODE %s %s%s",targetuser->nick,output_sequence.c_str(), parameter_list.str().c_str());
+                                       this->LastParse = targetuser->nick;
+                               }
+                       }
+                       else
+                       {
+                               if (type == MODETYPE_CHANNEL)
+                               {
+                                       targetchannel->WriteChannel(user,"MODE %s %s%s",targetchannel->name,output_sequence.c_str(),parameter_list.str().c_str());
+                                       FOREACH_MOD(I_OnMode,OnMode(user, targetchannel, TYPE_CHANNEL, output_sequence + parameter_list.str()));
+                                       this->LastParse = targetchannel->name;
+                               }
+                               else
+                               {
+                                       user->WriteTo(targetuser,"MODE %s %s%s",targetuser->nick,output_sequence.c_str(), parameter_list.str().c_str());
+                                       FOREACH_MOD(I_OnMode,OnMode(user, targetuser, TYPE_USER, output_sequence + parameter_list.str()));
+                                       this->LastParse = targetuser->nick;
+                               }
+                       }
+
+                       LastParse.append(" ");
+                       LastParse.append(output_sequence);
+                       LastParse.append(parameter_list.str());
+               }
+       }
+}
+
+const std::string& ModeParser::GetLastParse()
+{
+       return LastParse;
+}
+
+void ModeParser::CleanMask(std::string &mask)
+{
+       std::string::size_type pos_of_pling = mask.find_first_of('!');
+       std::string::size_type pos_of_at = mask.find_first_of('@');
+       std::string::size_type pos_of_dot = mask.find_first_of('.');
+       std::string::size_type pos_of_colon = mask.find_first_of(':'); /* Because ipv6 addresses are colon delimited */
+
+       if ((pos_of_pling == std::string::npos) && (pos_of_at == std::string::npos))
+       {
+               /* Just a nick, or just a host */
+               if ((pos_of_dot == std::string::npos) && (pos_of_colon == std::string::npos))
+               {
+                       /* It has no '.' in it, it must be a nick. */
+                       mask.append("!*@*");
+               }
+               else
+               {
+                       /* Got a dot in it? Has to be a host */
+                       mask = "*!*@" + mask;
+               }
+       }
+       else if ((pos_of_pling == std::string::npos) && (pos_of_at != std::string::npos))
+       {
+               /* Has an @ but no !, its a user@host */
+                mask = "*!" + mask;
+       }
+       else if ((pos_of_pling != std::string::npos) && (pos_of_at == std::string::npos))
+       {
+               /* Has a ! but no @, it must be a nick!ident */
+               mask.append("@*");
+       }
+}
+
+bool ModeParser::AddMode(ModeHandler* mh, unsigned const char modeletter)
+{
+       unsigned char mask = 0;
+       unsigned char pos = 0;
+
+       /* Yes, i know, this might let people declare modes like '_' or '^'.
+        * If they do that, thats their problem, and if i ever EVER see an
+        * official InspIRCd developer do that, i'll beat them with a paddle!
+        */
+       if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z') || (mh->GetPrefix() > 126))
+               return false;
+
+       /* A mode prefix of ',' is not acceptable, it would fuck up server to server.
+        * A mode prefix of ':' will fuck up both server to server, and client to server.
+        * A mode prefix of '#' will mess up /whois and /privmsg
+        */
+       if ((mh->GetPrefix() == ',') || (mh->GetPrefix() == ':') || (mh->GetPrefix() == '#'))
+               return false;
+
+       mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
+       pos = (mh->GetModeChar()-65) | mask;
+
+       if (modehandlers[pos])
+               return false;
+
+       modehandlers[pos] = mh;
+       return true;
+}
+
+bool ModeParser::DelMode(ModeHandler* mh)
+{
+       unsigned char mask = 0;
+       unsigned char pos = 0;
+
+       if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z'))
+               return false;
+
+       mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
+       pos = (mh->GetModeChar()-65) | mask;
+
+       if (!modehandlers[pos])
+               return false;
+
+       switch (mh->GetModeType())
+       {
+               case MODETYPE_USER:
+                       for (user_hash::iterator i = ServerInstance->clientlist->begin(); i != ServerInstance->clientlist->end(); i++)
+                       {
+                               mh->RemoveMode(i->second);
+                       }
+               break;
+               case MODETYPE_CHANNEL:
+                       for (chan_hash::iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++)
+                       {
+                               mh->RemoveMode(i->second);
+                       }
+               break;
+       }
+
+       modehandlers[pos] = NULL;
+
+       return true;
+}
+
+ModeHandler* ModeParser::FindMode(unsigned const char modeletter, ModeType mt)
+{
+       unsigned char mask = 0;
+       unsigned char pos = 0;
+
+       if ((modeletter < 'A') || (modeletter > 'z'))
+               return NULL;
+
+       mt == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
+       pos = (modeletter-65) | mask;
+
+       return modehandlers[pos];
+}
+
+std::string ModeParser::UserModeList()
+{
+       char modestr[256];
+       int pointer = 0;
+
+       for (unsigned char mode = 'A'; mode <= 'z'; mode++)
+       {
+               unsigned char pos = (mode-65) | MASK_USER;
+
+               if (modehandlers[pos])
+                       modestr[pointer++] = mode;
+       }
+       modestr[pointer++] = 0;
+       return modestr;
+}
+
+std::string ModeParser::ChannelModeList()
+{
+       char modestr[256];
+       int pointer = 0;
+
+       for (unsigned char mode = 'A'; mode <= 'z'; mode++)
+       {
+               if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
+                       continue;
+
+               unsigned char pos = (mode-65) | MASK_CHANNEL;
+
+               if (modehandlers[pos])
+                       modestr[pointer++] = mode;
+       }
+       modestr[pointer++] = 0;
+       return modestr;
+}
+
+std::string ModeParser::ParaModeList()
+{
+       char modestr[256];
+       int pointer = 0;
+
+       for (unsigned char mode = 'A'; mode <= 'z'; mode++)
+       {
+               if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
+                       continue;
+
+               unsigned char pos = (mode-65) | MASK_CHANNEL;
+
+               if ((modehandlers[pos]) && (modehandlers[pos]->GetNumParams(true)))
+                       modestr[pointer++] = mode;
+       }
+       modestr[pointer++] = 0;
+       return modestr;
+}
+
+ModeHandler* ModeParser::FindPrefix(unsigned const char pfxletter)
+{
+       for (unsigned char mode = 'A'; mode <= 'z'; mode++)
+       {
+               unsigned char pos = (mode-65) | MASK_CHANNEL;
+
+               if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix() == pfxletter))
+               {
+                       return modehandlers[pos];
+               }
+       }
+       return NULL;
+}
+
+std::string ModeParser::ModeString(userrec* user, chanrec* channel)
+{
+       std::string types;
+       std::string pars;
+
+       if (!channel || !user)
+               return "";
+
+       for (unsigned char mode = 'A'; mode <= 'z'; mode++)
+       {
+               unsigned char pos = (mode-65) | MASK_CHANNEL;
+               ModeHandler* mh = modehandlers[pos];
+               if ((mh) && (mh->GetNumParams(true)) && (mh->GetNumParams(false)))
+               {
+                       ModePair ret;
+                       ret = mh->ModeSet(NULL, user, channel, user->nick);
+                       if ((ret.first) && (ret.second == user->nick))
+                       {
+                               pars.append(" ");
+                               pars.append(user->nick);
+                               types.push_back(mh->GetModeChar());
+                       }
+               }
+       }
+
+       return types+pars;
+}
+
+std::string ModeParser::ChanModes()
+{
+       std::string type1;      /* Listmodes EXCEPT those with a prefix */
+       std::string type2;      /* Modes that take a param when adding or removing */
+       std::string type3;      /* Modes that only take a param when adding */
+       std::string type4;      /* Modes that dont take a param */
+
+       for (unsigned char mode = 'A'; mode <= 'z'; mode++)
+       {
+               if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
+                       continue;
+
+               unsigned char pos = (mode-65) | MASK_CHANNEL;
+                /* One parameter when adding */
+               if (modehandlers[pos])
+               {       
+                       if (modehandlers[pos]->GetNumParams(true))
+                       {
+                               if ((modehandlers[pos]->IsListMode()) && (!modehandlers[pos]->GetPrefix()))
+                               {
+                                       type1 += modehandlers[pos]->GetModeChar();
+                               }
+                               else
+                               {
+                                       /* ... and one parameter when removing */
+                                       if (modehandlers[pos]->GetNumParams(false))
+                                       {
+                                               /* But not a list mode */
+                                               if (!modehandlers[pos]->GetPrefix())
+                                               {
+                                                       type2 += modehandlers[pos]->GetModeChar();
+                                               }
+                                       }
+                                       else
+                                       {
+                                               /* No parameters when removing */
+                                               type3 += modehandlers[pos]->GetModeChar();
+                                       }
+                               }
+                       }
+                       else
+                       {
+                               type4 += modehandlers[pos]->GetModeChar();
+                       }
+               }
+                        
+       }
+
+       return type1 + "," + type2 + "," + type3 + "," + type4;
+}
+
+bool ModeParser::PrefixComparison(prefixtype one, prefixtype two)
+{       
+       return one.second > two.second;
+}
+
+std::string ModeParser::BuildPrefixes()
+{
+       std::string mletters;
+       std::string mprefixes;
+       pfxcontainer pfx;
+       std::map<char,char> prefix_to_mode;
+
+       for (unsigned char mode = 'A'; mode <= 'z'; mode++)
+       {
+               if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
+                       continue;
+
+               unsigned char pos = (mode-65) | MASK_CHANNEL;
+
+               if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix()))
+               {
+                       pfx.push_back(std::make_pair<char,unsigned int>(modehandlers[pos]->GetPrefix(), modehandlers[pos]->GetPrefixRank()));
+                       prefix_to_mode[modehandlers[pos]->GetPrefix()] = modehandlers[pos]->GetModeChar();
+               }
+       }
+
+       sort(pfx.begin(), pfx.end(), ModeParser::PrefixComparison);
+
+       for (pfxcontainer::iterator n = pfx.begin(); n != pfx.end(); n++)
+       {
+               mletters = mletters + n->first;
+               mprefixes = mprefixes + prefix_to_mode.find(n->first)->second;
+       }
+
+       return "(" + mprefixes + ")" + mletters;
+}
+
+bool ModeParser::AddModeWatcher(ModeWatcher* mw)
+{
+       unsigned char mask = 0;
+       unsigned char pos = 0;
+
+       if (!mw)
+               return false;
+
+       if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
+               return false;
+
+       mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
+       pos = (mw->GetModeChar()-65) | mask;
+
+       modewatchers[pos].push_back(mw);
+
+       return true;
+}
+
+bool ModeParser::DelModeWatcher(ModeWatcher* mw)
+{
+       unsigned char mask = 0;
+       unsigned char pos = 0;
+
+       if (!mw)
+               return false;
+
+       if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
+               return false;
+
+       mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
+       pos = (mw->GetModeChar()-65) | mask;
+
+       ModeWatchIter a = find(modewatchers[pos].begin(),modewatchers[pos].end(),mw);
+
+       if (a == modewatchers[pos].end())
+       {
+               return false;
+       }
+
+       modewatchers[pos].erase(a);
+
+       return true;
+}
+
+/** This default implementation can remove simple user modes
+ */
+void ModeHandler::RemoveMode(userrec* user)
+{
+       char moderemove[MAXBUF];
+       const char* parameters[] = { user->nick, moderemove };
+
+       if (user->IsModeSet(this->GetModeChar()))
+       {
+               sprintf(moderemove,"-%c",this->GetModeChar());
+               ServerInstance->Parser->CallHandler("MODE", parameters, 2, user);
+       }
+}
+
+/** This default implementation can remove simple channel modes
+ * (no parameters)
+ */
+void ModeHandler::RemoveMode(chanrec* channel)
+{
+       char moderemove[MAXBUF];
+       const char* parameters[] = { channel->name, moderemove };
+
+       if (channel->IsModeSet(this->GetModeChar()))
+       {
+               userrec* n = new userrec(ServerInstance);
+
+               sprintf(moderemove,"-%c",this->GetModeChar());
+               n->SetFd(FD_MAGIC_NUMBER);
+
+               ServerInstance->SendMode(parameters, 2, n);
+
+               delete n;
+       }
+}
+
+ModeParser::ModeParser(InspIRCd* Instance) : ServerInstance(Instance)
+{
+       struct Initializer
+       {
+               char modechar;
+               ModeHandler* handler;
+       };
+
+       Initializer modes[] = {
+               { 's', new ModeChannelSecret(Instance) },
+               { 'p', new ModeChannelPrivate(Instance) },
+               { 'm', new ModeChannelModerated(Instance) },
+               { 't', new ModeChannelTopicOps(Instance) },
+               { 'n', new ModeChannelNoExternal(Instance) },
+               { 'i', new ModeChannelInviteOnly(Instance) },
+               { 'k', new ModeChannelKey(Instance) },
+               { 'l', new ModeChannelLimit(Instance) },
+               { 'b', new ModeChannelBan(Instance) },
+               { 'o', new ModeChannelOp(Instance) },
+               { 'h', new ModeChannelHalfOp(Instance) },
+               { 'v', new ModeChannelVoice(Instance) },
+               { 's', new ModeUserServerNotice(Instance) },
+               { 'w', new ModeUserWallops(Instance) },
+               { 'i', new ModeUserInvisible(Instance) },
+               { 'o', new ModeUserOperator(Instance) },
+               { 'n', new ModeUserServerNoticeMask(Instance) },
+               { 0, NULL }
+       };
+
+       /* Clear mode list */
+       memset(modehandlers, 0, sizeof(modehandlers));
+       memset(modewatchers, 0, sizeof(modewatchers));
+
+       /* Last parse string */
+       LastParse.clear();
+
+       /* Initialise the RFC mode letters */
+       for (int index = 0; modes[index].modechar; index++)
+               this->AddMode(modes[index].handler, modes[index].modechar);
+}
index 1b7743649017d8cd0d4f4643fbeac9930b112655..8839168b75412d85383420f3d2ebe6e0ac2a3c30 100644 (file)
@@ -1 +1,65 @@
-CC = i am cornholio\rCXXFLAGS = -I../../include ${FLAGS}\r\rall: umode_w.o umode_s.o umode_o.o umode_n.o umode_i.o cmode_v.o cmode_t.o cmode_s.o cmode_p.o cmode_o.o cmode_n.o cmode_m.o cmode_l.o cmode_k.o cmode_i.o cmode_h.o cmode_b.o modeclasses.a\r\rumode_w.o: umode_w.cpp ../../include/base.h ../../include/modules.h ../../include/inspircd.h ../../include/channels.h ../../include/users.h ../../include/inspircd_config.h ../../include/mode.h\r       $(CC) -pipe -I../../include $(FLAGS) -export-dynamic -c umode_w.cpp\r\rumode_s.o: umode_s.cpp ../../include/base.h ../../include/modules.h ../../include/inspircd.h ../../include/channels.h ../../include/users.h ../../include/inspircd_config.h ../../include/mode.h\r  $(CC) -pipe -I../../include $(FLAGS) -export-dynamic -c umode_s.cpp\r\rumode_o.o: umode_o.cpp ../../include/base.h ../../include/modules.h ../../include/inspircd.h ../../include/channels.h ../../include/users.h ../../include/inspircd_config.h ../../include/mode.h\r  $(CC) -pipe -I../../include $(FLAGS) -export-dynamic -c umode_o.cpp\r\rumode_n.o: umode_n.cpp ../../include/base.h ../../include/modules.h ../../include/inspircd.h ../../include/channels.h ../../include/users.h ../../include/inspircd_config.h ../../include/mode.h\r  $(CC) -pipe -I../../include $(FLAGS) -export-dynamic -c umode_n.cpp\r\rumode_i.o: umode_i.cpp ../../include/base.h ../../include/modules.h ../../include/inspircd.h ../../include/channels.h ../../include/users.h ../../include/inspircd_config.h ../../include/mode.h\r  $(CC) -pipe -I../../include $(FLAGS) -export-dynamic -c umode_i.cpp\r\rcmode_v.o: cmode_v.cpp ../../include/base.h ../../include/modules.h ../../include/inspircd.h ../../include/channels.h ../../include/users.h ../../include/inspircd_config.h ../../include/mode.h\r  $(CC) -pipe -I../../include $(FLAGS) -export-dynamic -c cmode_v.cpp\r\rcmode_t.o: cmode_t.cpp ../../include/base.h ../../include/modules.h ../../include/inspircd.h ../../include/channels.h ../../include/users.h ../../include/inspircd_config.h ../../include/mode.h\r  $(CC) -pipe -I../../include $(FLAGS) -export-dynamic -c cmode_t.cpp\r\rcmode_s.o: cmode_s.cpp ../../include/base.h ../../include/modules.h ../../include/inspircd.h ../../include/channels.h ../../include/users.h ../../include/inspircd_config.h ../../include/mode.h\r  $(CC) -pipe -I../../include $(FLAGS) -export-dynamic -c cmode_s.cpp\r\rcmode_p.o: cmode_p.cpp ../../include/base.h ../../include/modules.h ../../include/inspircd.h ../../include/channels.h ../../include/users.h ../../include/inspircd_config.h ../../include/mode.h\r  $(CC) -pipe -I../../include $(FLAGS) -export-dynamic -c cmode_p.cpp\r\rcmode_o.o: cmode_o.cpp ../../include/base.h ../../include/modules.h ../../include/inspircd.h ../../include/channels.h ../../include/users.h ../../include/inspircd_config.h ../../include/mode.h\r  $(CC) -pipe -I../../include $(FLAGS) -export-dynamic -c cmode_o.cpp\r\rcmode_n.o: cmode_n.cpp ../../include/base.h ../../include/modules.h ../../include/inspircd.h ../../include/channels.h ../../include/users.h ../../include/inspircd_config.h ../../include/mode.h\r  $(CC) -pipe -I../../include $(FLAGS) -export-dynamic -c cmode_n.cpp\r\rcmode_m.o: cmode_m.cpp ../../include/base.h ../../include/modules.h ../../include/inspircd.h ../../include/channels.h ../../include/users.h ../../include/inspircd_config.h ../../include/mode.h\r  $(CC) -pipe -I../../include $(FLAGS) -export-dynamic -c cmode_m.cpp\r\rcmode_l.o: cmode_l.cpp ../../include/base.h ../../include/modules.h ../../include/inspircd.h ../../include/channels.h ../../include/users.h ../../include/inspircd_config.h ../../include/mode.h\r  $(CC) -pipe -I../../include $(FLAGS) -export-dynamic -c cmode_l.cpp\r\rcmode_k.o: cmode_k.cpp ../../include/base.h ../../include/modules.h ../../include/inspircd.h ../../include/channels.h ../../include/users.h ../../include/inspircd_config.h ../../include/mode.h\r  $(CC) -pipe -I../../include $(FLAGS) -export-dynamic -c cmode_k.cpp\r\rcmode_i.o: cmode_i.cpp ../../include/base.h ../../include/modules.h ../../include/inspircd.h ../../include/channels.h ../../include/users.h ../../include/inspircd_config.h ../../include/mode.h\r  $(CC) -pipe -I../../include $(FLAGS) -export-dynamic -c cmode_i.cpp\r\rcmode_h.o: cmode_h.cpp ../../include/base.h ../../include/modules.h ../../include/inspircd.h ../../include/channels.h ../../include/users.h ../../include/inspircd_config.h ../../include/mode.h\r  $(CC) -pipe -I../../include $(FLAGS) -export-dynamic -c cmode_h.cpp\r\rcmode_b.o: cmode_b.cpp ../../include/base.h ../../include/modules.h ../../include/inspircd.h ../../include/channels.h ../../include/users.h ../../include/inspircd_config.h ../../include/mode.h\r  $(CC) -pipe -I../../include $(FLAGS) -export-dynamic -c cmode_b.cpp\r\rmodeclasses.a: umode_w.o umode_s.o umode_o.o umode_n.o umode_i.o cmode_v.o cmode_t.o cmode_s.o cmode_p.o cmode_o.o cmode_n.o cmode_m.o cmode_l.o cmode_k.o cmode_i.o cmode_h.o cmode_b.o\r  @-rm -rf modeclasses.a\r ar r modeclasses.a *.o\r ranlib modeclasses.a\r\rclean:\r   @-rm *.o\r       @-rm modeclasses.a\r\r
\ No newline at end of file
+CC = i am cornholio
+CXXFLAGS = -I../../include ${FLAGS}
+
+all: umode_w.o umode_s.o umode_o.o umode_n.o umode_i.o cmode_v.o cmode_t.o cmode_s.o cmode_p.o cmode_o.o cmode_n.o cmode_m.o cmode_l.o cmode_k.o cmode_i.o cmode_h.o cmode_b.o modeclasses.a
+
+umode_w.o: umode_w.cpp ../../include/base.h ../../include/modules.h ../../include/inspircd.h ../../include/channels.h ../../include/users.h ../../include/inspircd_config.h ../../include/mode.h
+       $(CC) -pipe -I../../include $(FLAGS) -export-dynamic -c umode_w.cpp
+
+umode_s.o: umode_s.cpp ../../include/base.h ../../include/modules.h ../../include/inspircd.h ../../include/channels.h ../../include/users.h ../../include/inspircd_config.h ../../include/mode.h
+       $(CC) -pipe -I../../include $(FLAGS) -export-dynamic -c umode_s.cpp
+
+umode_o.o: umode_o.cpp ../../include/base.h ../../include/modules.h ../../include/inspircd.h ../../include/channels.h ../../include/users.h ../../include/inspircd_config.h ../../include/mode.h
+       $(CC) -pipe -I../../include $(FLAGS) -export-dynamic -c umode_o.cpp
+
+umode_n.o: umode_n.cpp ../../include/base.h ../../include/modules.h ../../include/inspircd.h ../../include/channels.h ../../include/users.h ../../include/inspircd_config.h ../../include/mode.h
+       $(CC) -pipe -I../../include $(FLAGS) -export-dynamic -c umode_n.cpp
+
+umode_i.o: umode_i.cpp ../../include/base.h ../../include/modules.h ../../include/inspircd.h ../../include/channels.h ../../include/users.h ../../include/inspircd_config.h ../../include/mode.h
+       $(CC) -pipe -I../../include $(FLAGS) -export-dynamic -c umode_i.cpp
+
+cmode_v.o: cmode_v.cpp ../../include/base.h ../../include/modules.h ../../include/inspircd.h ../../include/channels.h ../../include/users.h ../../include/inspircd_config.h ../../include/mode.h
+       $(CC) -pipe -I../../include $(FLAGS) -export-dynamic -c cmode_v.cpp
+
+cmode_t.o: cmode_t.cpp ../../include/base.h ../../include/modules.h ../../include/inspircd.h ../../include/channels.h ../../include/users.h ../../include/inspircd_config.h ../../include/mode.h
+       $(CC) -pipe -I../../include $(FLAGS) -export-dynamic -c cmode_t.cpp
+
+cmode_s.o: cmode_s.cpp ../../include/base.h ../../include/modules.h ../../include/inspircd.h ../../include/channels.h ../../include/users.h ../../include/inspircd_config.h ../../include/mode.h
+       $(CC) -pipe -I../../include $(FLAGS) -export-dynamic -c cmode_s.cpp
+
+cmode_p.o: cmode_p.cpp ../../include/base.h ../../include/modules.h ../../include/inspircd.h ../../include/channels.h ../../include/users.h ../../include/inspircd_config.h ../../include/mode.h
+       $(CC) -pipe -I../../include $(FLAGS) -export-dynamic -c cmode_p.cpp
+
+cmode_o.o: cmode_o.cpp ../../include/base.h ../../include/modules.h ../../include/inspircd.h ../../include/channels.h ../../include/users.h ../../include/inspircd_config.h ../../include/mode.h
+       $(CC) -pipe -I../../include $(FLAGS) -export-dynamic -c cmode_o.cpp
+
+cmode_n.o: cmode_n.cpp ../../include/base.h ../../include/modules.h ../../include/inspircd.h ../../include/channels.h ../../include/users.h ../../include/inspircd_config.h ../../include/mode.h
+       $(CC) -pipe -I../../include $(FLAGS) -export-dynamic -c cmode_n.cpp
+
+cmode_m.o: cmode_m.cpp ../../include/base.h ../../include/modules.h ../../include/inspircd.h ../../include/channels.h ../../include/users.h ../../include/inspircd_config.h ../../include/mode.h
+       $(CC) -pipe -I../../include $(FLAGS) -export-dynamic -c cmode_m.cpp
+
+cmode_l.o: cmode_l.cpp ../../include/base.h ../../include/modules.h ../../include/inspircd.h ../../include/channels.h ../../include/users.h ../../include/inspircd_config.h ../../include/mode.h
+       $(CC) -pipe -I../../include $(FLAGS) -export-dynamic -c cmode_l.cpp
+
+cmode_k.o: cmode_k.cpp ../../include/base.h ../../include/modules.h ../../include/inspircd.h ../../include/channels.h ../../include/users.h ../../include/inspircd_config.h ../../include/mode.h
+       $(CC) -pipe -I../../include $(FLAGS) -export-dynamic -c cmode_k.cpp
+
+cmode_i.o: cmode_i.cpp ../../include/base.h ../../include/modules.h ../../include/inspircd.h ../../include/channels.h ../../include/users.h ../../include/inspircd_config.h ../../include/mode.h
+       $(CC) -pipe -I../../include $(FLAGS) -export-dynamic -c cmode_i.cpp
+
+cmode_h.o: cmode_h.cpp ../../include/base.h ../../include/modules.h ../../include/inspircd.h ../../include/channels.h ../../include/users.h ../../include/inspircd_config.h ../../include/mode.h
+       $(CC) -pipe -I../../include $(FLAGS) -export-dynamic -c cmode_h.cpp
+
+cmode_b.o: cmode_b.cpp ../../include/base.h ../../include/modules.h ../../include/inspircd.h ../../include/channels.h ../../include/users.h ../../include/inspircd_config.h ../../include/mode.h
+       $(CC) -pipe -I../../include $(FLAGS) -export-dynamic -c cmode_b.cpp
+
+modeclasses.a: umode_w.o umode_s.o umode_o.o umode_n.o umode_i.o cmode_v.o cmode_t.o cmode_s.o cmode_p.o cmode_o.o cmode_n.o cmode_m.o cmode_l.o cmode_k.o cmode_i.o cmode_h.o cmode_b.o
+       @-rm -rf modeclasses.a
+       ar r modeclasses.a *.o
+       ranlib modeclasses.a
+
+clean:
+       @-rm *.o
+       @-rm modeclasses.a
+
index dbc2e925d221008d7658011a1c5188627a7d5f67..e306f31f6fffcc9995b1b8f480e4959ca4659375 100644 (file)
@@ -1 +1,185 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include <string>\r#include <vector>\r#include "inspircd_config.h"\r#include "configreader.h"\r#include "hash_map.h"\r#include "mode.h"\r#include "channels.h"\r#include "users.h"\r#include "modules.h"\r#include "inspstring.h"\r#include "hashcomp.h"\r#include "modes/cmode_b.h"\r\rModeChannelBan::ModeChannelBan(InspIRCd* Instance) : ModeHandler(Instance, 'b', 1, 1, true, MODETYPE_CHANNEL, false)\r{\r}\r\rModeAction ModeChannelBan::OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)\r{\r       int status = channel->GetStatus(source);\r       /* Call the correct method depending on wether we're adding or removing the mode */\r    if (adding)\r    {\r              parameter = this->AddBan(source, parameter, channel, status);\r  }\r      else\r   {\r              parameter = this->DelBan(source, parameter, channel, status);\r  }\r      /* If the method above 'ate' the parameter by reducing it to an empty string, then\r      * it won't matter wether we return ALLOW or DENY here, as an empty string overrides\r    * the return value and is always MODEACTION_DENY if the mode is supposed to have\r       * a parameter.\r         */\r    return MODEACTION_ALLOW;\r}\r\rvoid ModeChannelBan::RemoveMode(chanrec* channel)\r{\r        BanList copy;\r  char moderemove[MAXBUF];\r       userrec* n = new userrec(ServerInstance);\r      n->SetFd(FD_MAGIC_NUMBER);\r\r    for (BanList::iterator i = channel->bans.begin(); i != channel->bans.end(); i++)\r       {\r              copy.push_back(*i);\r    }\r      for (BanList::iterator i = copy.begin(); i != copy.end(); i++)\r {\r              sprintf(moderemove,"-%c",this->GetModeChar());\r         const char* parameters[] = { channel->name, moderemove, i->data };\r             ServerInstance->SendMode(parameters, 3, n);\r    }\r\r     delete n;\r}\r\rvoid ModeChannelBan::RemoveMode(userrec* user)\r{\r}\r\rvoid ModeChannelBan::DisplayList(userrec* user, chanrec* channel)\r{\r   /* Display the channel banlist */\r      for (BanList::reverse_iterator i = channel->bans.rbegin(); i != channel->bans.rend(); ++i)\r     {\r              user->WriteServ("367 %s %s %s %s %d",user->nick, channel->name, i->data, i->set_by, i->set_time);\r      }\r      user->WriteServ("368 %s %s :End of channel ban list",user->nick, channel->name);\r       return;\r}\r\rstd::string& ModeChannelBan::AddBan(userrec *user,std::string &dest,chanrec *chan,int status)\r{\r     if ((!user) || (!chan))\r        {\r              ServerInstance->Log(DEFAULT,"*** BUG *** AddBan was given an invalid parameter");\r              dest = "";\r             return dest;\r   }\r\r     /* Attempt to tidy the mask */\r ModeParser::CleanMask(dest);\r   /* If the mask was invalid, we exit */\r if (dest == "")\r                return dest;\r\r  long maxbans = chan->GetMaxBans();\r     if ((unsigned)chan->bans.size() > (unsigned)maxbans)\r   {\r              user->WriteServ("478 %s %s :Channel ban list for %s is full (maximum entries for this channel is %d)",user->nick, chan->name,chan->name,maxbans);\r              dest = "";\r             return dest;\r   }\r\r     int MOD_RESULT = 0;\r    FOREACH_RESULT(I_OnAddBan,OnAddBan(user,chan,dest));\r   if (MOD_RESULT)\r        {\r              dest = "";\r             return dest;\r   }\r\r     for (BanList::iterator i = chan->bans.begin(); i != chan->bans.end(); i++)\r     {\r              if (!strcasecmp(i->data,dest.c_str()))\r         {\r                      /* dont allow a user to set the same ban twice */\r                      dest = "";\r                     return dest;\r           }\r      }\r\r     b.set_time = ServerInstance->Time();\r   strlcpy(b.data,dest.c_str(),MAXBUF);\r   if (*user->nick)\r       {\r              strlcpy(b.set_by,user->nick,NICKMAX-1);\r        }\r      else\r   {\r              strlcpy(b.set_by,ServerInstance->Config->ServerName,NICKMAX-1);\r        }\r      chan->bans.push_back(b);\r       return dest;\r}\r\rModePair ModeChannelBan::ModeSet(userrec* source, userrec* dest, chanrec* channel, const std::string &parameter)\r{\r     for (BanList::iterator i = channel->bans.begin(); i != channel->bans.end(); i++)\r       {\r              if (!strcasecmp(i->data,parameter.c_str()))\r            {\r                      return std::make_pair(true, i->data);\r          }\r      }\r        return std::make_pair(false, parameter);\r}\r\rstd::string& ModeChannelBan::DelBan(userrec *user,std::string& dest,chanrec *chan,int status)\r{\r  if ((!user) || (!chan))\r        {\r              ServerInstance->Log(DEFAULT,"*** BUG *** TakeBan was given an invalid parameter");\r             dest = "";\r             return dest;\r   }\r\r     /* 'Clean' the mask, e.g. nick -> nick!*@* */\r  ModeParser::CleanMask(dest);\r\r  for (BanList::iterator i = chan->bans.begin(); i != chan->bans.end(); i++)\r     {\r              if (!strcasecmp(i->data,dest.c_str()))\r         {\r                      int MOD_RESULT = 0;\r                    FOREACH_RESULT(I_OnDelBan,OnDelBan(user,chan,dest));\r                   if (MOD_RESULT)\r                        {\r                              dest = "";\r                             return dest;\r                   }\r                      chan->bans.erase(i);\r                   return dest;\r           }\r      }\r      dest = "";\r     return dest;\r}\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include <string>
+#include <vector>
+#include "inspircd_config.h"
+#include "configreader.h"
+#include "hash_map.h"
+#include "mode.h"
+#include "channels.h"
+#include "users.h"
+#include "modules.h"
+#include "inspstring.h"
+#include "hashcomp.h"
+#include "modes/cmode_b.h"
+
+ModeChannelBan::ModeChannelBan(InspIRCd* Instance) : ModeHandler(Instance, 'b', 1, 1, true, MODETYPE_CHANNEL, false)
+{
+}
+
+ModeAction ModeChannelBan::OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)
+{
+       int status = channel->GetStatus(source);
+       /* Call the correct method depending on wether we're adding or removing the mode */
+       if (adding)
+       {
+               parameter = this->AddBan(source, parameter, channel, status);
+       }
+       else
+       {
+               parameter = this->DelBan(source, parameter, channel, status);
+       }
+       /* If the method above 'ate' the parameter by reducing it to an empty string, then
+        * it won't matter wether we return ALLOW or DENY here, as an empty string overrides
+        * the return value and is always MODEACTION_DENY if the mode is supposed to have
+        * a parameter.
+        */
+       return MODEACTION_ALLOW;
+}
+
+void ModeChannelBan::RemoveMode(chanrec* channel)
+{
+       BanList copy;
+       char moderemove[MAXBUF];
+       userrec* n = new userrec(ServerInstance);
+       n->SetFd(FD_MAGIC_NUMBER);
+
+       for (BanList::iterator i = channel->bans.begin(); i != channel->bans.end(); i++)
+       {
+               copy.push_back(*i);
+       }
+       for (BanList::iterator i = copy.begin(); i != copy.end(); i++)
+       {
+               sprintf(moderemove,"-%c",this->GetModeChar());
+               const char* parameters[] = { channel->name, moderemove, i->data };
+               ServerInstance->SendMode(parameters, 3, n);
+       }
+
+       delete n;
+}
+
+void ModeChannelBan::RemoveMode(userrec* user)
+{
+}
+
+void ModeChannelBan::DisplayList(userrec* user, chanrec* channel)
+{
+       /* Display the channel banlist */
+       for (BanList::reverse_iterator i = channel->bans.rbegin(); i != channel->bans.rend(); ++i)
+       {
+               user->WriteServ("367 %s %s %s %s %d",user->nick, channel->name, i->data, i->set_by, i->set_time);
+       }
+       user->WriteServ("368 %s %s :End of channel ban list",user->nick, channel->name);
+       return;
+}
+
+std::string& ModeChannelBan::AddBan(userrec *user,std::string &dest,chanrec *chan,int status)
+{
+       if ((!user) || (!chan))
+       {
+               ServerInstance->Log(DEFAULT,"*** BUG *** AddBan was given an invalid parameter");
+               dest = "";
+               return dest;
+       }
+
+       /* Attempt to tidy the mask */
+       ModeParser::CleanMask(dest);
+       /* If the mask was invalid, we exit */
+       if (dest == "")
+               return dest;
+
+       long maxbans = chan->GetMaxBans();
+       if ((unsigned)chan->bans.size() > (unsigned)maxbans)
+       {
+               user->WriteServ("478 %s %s :Channel ban list for %s is full (maximum entries for this channel is %d)",user->nick, chan->name,chan->name,maxbans);
+               dest = "";
+               return dest;
+       }
+
+       int MOD_RESULT = 0;
+       FOREACH_RESULT(I_OnAddBan,OnAddBan(user,chan,dest));
+       if (MOD_RESULT)
+       {
+               dest = "";
+               return dest;
+       }
+
+       for (BanList::iterator i = chan->bans.begin(); i != chan->bans.end(); i++)
+       {
+               if (!strcasecmp(i->data,dest.c_str()))
+               {
+                       /* dont allow a user to set the same ban twice */
+                       dest = "";
+                       return dest;
+               }
+       }
+
+       b.set_time = ServerInstance->Time();
+       strlcpy(b.data,dest.c_str(),MAXBUF);
+       if (*user->nick)
+       {
+               strlcpy(b.set_by,user->nick,NICKMAX-1);
+       }
+       else
+       {
+               strlcpy(b.set_by,ServerInstance->Config->ServerName,NICKMAX-1);
+       }
+       chan->bans.push_back(b);
+       return dest;
+}
+
+ModePair ModeChannelBan::ModeSet(userrec* source, userrec* dest, chanrec* channel, const std::string &parameter)
+{
+       for (BanList::iterator i = channel->bans.begin(); i != channel->bans.end(); i++)
+       {
+               if (!strcasecmp(i->data,parameter.c_str()))
+               {
+                       return std::make_pair(true, i->data);
+               }
+       }
+        return std::make_pair(false, parameter);
+}
+
+std::string& ModeChannelBan::DelBan(userrec *user,std::string& dest,chanrec *chan,int status)
+{
+       if ((!user) || (!chan))
+       {
+               ServerInstance->Log(DEFAULT,"*** BUG *** TakeBan was given an invalid parameter");
+               dest = "";
+               return dest;
+       }
+
+       /* 'Clean' the mask, e.g. nick -> nick!*@* */
+       ModeParser::CleanMask(dest);
+
+       for (BanList::iterator i = chan->bans.begin(); i != chan->bans.end(); i++)
+       {
+               if (!strcasecmp(i->data,dest.c_str()))
+               {
+                       int MOD_RESULT = 0;
+                       FOREACH_RESULT(I_OnDelBan,OnDelBan(user,chan,dest));
+                       if (MOD_RESULT)
+                       {
+                               dest = "";
+                               return dest;
+                       }
+                       chan->bans.erase(i);
+                       return dest;
+               }
+       }
+       dest = "";
+       return dest;
+}
+
index f2ffff66548425c7dd73aef64efdc9e2001a063b..ecee93388387c0e997e18608583a936af35f1fa1 100644 (file)
@@ -1 +1,162 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "configreader.h"\r#include "mode.h"\r#include "channels.h"\r#include "users.h"\r#include "modules.h"\r#include "modes/cmode_h.h"\r\rModeChannelHalfOp::ModeChannelHalfOp(InspIRCd* Instance) : ModeHandler(Instance, 'h', 1, 1, true, MODETYPE_CHANNEL, false, '%')\r{\r}\r\runsigned int ModeChannelHalfOp::GetPrefixRank()\r{\r        return HALFOP_VALUE;\r}\r\rModePair ModeChannelHalfOp::ModeSet(userrec* source, userrec* dest, chanrec* channel, const std::string &parameter)\r{\r  userrec* x = ServerInstance->FindNick(parameter);\r      if (x)\r {\r              if (channel->GetStatusFlags(x) & UCMODE_HOP)\r           {\r                      return std::make_pair(true, x->nick);\r          }\r              else\r           {\r                      return std::make_pair(false, parameter);\r               }\r      }\r      return std::make_pair(false, parameter);\r}\r\rvoid ModeChannelHalfOp::RemoveMode(chanrec* channel)\r{\r     CUList* list = channel->GetHalfoppedUsers();\r   CUList copy;\r   char moderemove[MAXBUF];\r       userrec* n = new userrec(ServerInstance);\r      n->SetFd(FD_MAGIC_NUMBER);\r\r    for (CUList::iterator i = list->begin(); i != list->end(); i++)\r        {\r              userrec* n = i->first;\r         copy.insert(std::make_pair(n,n->nick));\r        }\r      for (CUList::iterator i = copy.begin(); i != copy.end(); i++)\r  {\r              sprintf(moderemove,"-%c",this->GetModeChar());\r         const char* parameters[] = { channel->name, moderemove, i->first->nick };\r              ServerInstance->SendMode(parameters, 3, n);\r    }\r      delete n;\r}\r\rvoid ModeChannelHalfOp::RemoveMode(userrec* user)\r{\r}\r\rModeAction ModeChannelHalfOp::OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)\r{\r        /* If halfops are not enabled in the conf, we don't execute\r     * anything in this class at all.\r       */\r    if (!ServerInstance->Config->AllowHalfop)\r      {\r              parameter = "";\r                return MODEACTION_DENY;\r        }\r\r     int status = channel->GetStatus(source);\r\r      /* Call the correct method depending on wether we're adding or removing the mode */\r    if (adding)\r    {\r              parameter = this->AddHalfOp(source, parameter.c_str(), channel, status);\r       }\r      else\r   {\r              parameter = this->DelHalfOp(source, parameter.c_str(), channel, status);\r       }\r      /* If the method above 'ate' the parameter by reducing it to an empty string, then\r      * it won't matter wether we return ALLOW or DENY here, as an empty string overrides\r    * the return value and is always MODEACTION_DENY if the mode is supposed to have\r       * a parameter.\r         */\r    if (parameter.length())\r                return MODEACTION_ALLOW;\r       else\r           return MODEACTION_DENY;\r}\r\rstd::string ModeChannelHalfOp::AddHalfOp(userrec *user,const char* dest,chanrec *chan,int status)\r{\r userrec *d = ServerInstance->Modes->SanityChecks(user,dest,chan,status);\r\r      if (d)\r {\r              if (IS_LOCAL(user))\r            {\r                      int MOD_RESULT = 0;\r                    FOREACH_RESULT(I_OnAccessCheck,OnAccessCheck(user,d,chan,AC_HALFOP));\r\r                 if (MOD_RESULT == ACR_DENY)\r                            return "";\r                     if (MOD_RESULT == ACR_DEFAULT)\r                 {\r                              if ((status < STATUS_OP) && (!ServerInstance->ULine(user->server)))\r                            {\r                                      user->WriteServ("482 %s %s :You're not a channel operator",user->nick, chan->name);\r                                    return "";\r                             }\r                      }\r              }\r\r             return ServerInstance->Modes->Grant(d,chan,UCMODE_HOP);\r        }\r      return "";\r}\r\rstd::string ModeChannelHalfOp::DelHalfOp(userrec *user,const char *dest,chanrec *chan,int status)\r{\r      userrec *d = ServerInstance->Modes->SanityChecks(user,dest,chan,status);\r\r      if (d)\r {\r              if (IS_LOCAL(user))\r            {\r                      int MOD_RESULT = 0;\r                    FOREACH_RESULT(I_OnAccessCheck,OnAccessCheck(user,d,chan,AC_DEHALFOP));\r\r                       if (MOD_RESULT == ACR_DENY)\r                            return "";\r                     if (MOD_RESULT == ACR_DEFAULT)\r                 {\r                              if ((user != d) && ((status < STATUS_OP) && (!ServerInstance->ULine(user->server))))\r                           {\r                                      user->WriteServ("482 %s %s :You are not a channel operator",user->nick, chan->name);\r                                   return "";\r                             }\r                      }\r              }\r\r             return ServerInstance->Modes->Revoke(d,chan,UCMODE_HOP);\r       }\r      return "";\r}\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "configreader.h"
+#include "mode.h"
+#include "channels.h"
+#include "users.h"
+#include "modules.h"
+#include "modes/cmode_h.h"
+
+ModeChannelHalfOp::ModeChannelHalfOp(InspIRCd* Instance) : ModeHandler(Instance, 'h', 1, 1, true, MODETYPE_CHANNEL, false, '%')
+{
+}
+
+unsigned int ModeChannelHalfOp::GetPrefixRank()
+{
+       return HALFOP_VALUE;
+}
+
+ModePair ModeChannelHalfOp::ModeSet(userrec* source, userrec* dest, chanrec* channel, const std::string &parameter)
+{
+       userrec* x = ServerInstance->FindNick(parameter);
+       if (x)
+       {
+               if (channel->GetStatusFlags(x) & UCMODE_HOP)
+               {
+                       return std::make_pair(true, x->nick);
+               }
+               else
+               {
+                       return std::make_pair(false, parameter);
+               }
+       }
+       return std::make_pair(false, parameter);
+}
+
+void ModeChannelHalfOp::RemoveMode(chanrec* channel)
+{
+       CUList* list = channel->GetHalfoppedUsers();
+       CUList copy;
+       char moderemove[MAXBUF];
+       userrec* n = new userrec(ServerInstance);
+       n->SetFd(FD_MAGIC_NUMBER);
+
+       for (CUList::iterator i = list->begin(); i != list->end(); i++)
+       {
+               userrec* n = i->first;
+               copy.insert(std::make_pair(n,n->nick));
+       }
+       for (CUList::iterator i = copy.begin(); i != copy.end(); i++)
+       {
+               sprintf(moderemove,"-%c",this->GetModeChar());
+               const char* parameters[] = { channel->name, moderemove, i->first->nick };
+               ServerInstance->SendMode(parameters, 3, n);
+       }
+       delete n;
+}
+
+void ModeChannelHalfOp::RemoveMode(userrec* user)
+{
+}
+
+ModeAction ModeChannelHalfOp::OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)
+{
+       /* If halfops are not enabled in the conf, we don't execute
+        * anything in this class at all.
+        */
+       if (!ServerInstance->Config->AllowHalfop)
+       {
+               parameter = "";
+               return MODEACTION_DENY;
+       }
+
+       int status = channel->GetStatus(source);
+
+       /* Call the correct method depending on wether we're adding or removing the mode */
+       if (adding)
+       {
+               parameter = this->AddHalfOp(source, parameter.c_str(), channel, status);
+       }
+       else
+       {
+               parameter = this->DelHalfOp(source, parameter.c_str(), channel, status);
+       }
+       /* If the method above 'ate' the parameter by reducing it to an empty string, then
+        * it won't matter wether we return ALLOW or DENY here, as an empty string overrides
+        * the return value and is always MODEACTION_DENY if the mode is supposed to have
+        * a parameter.
+        */
+       if (parameter.length())
+               return MODEACTION_ALLOW;
+       else
+               return MODEACTION_DENY;
+}
+
+std::string ModeChannelHalfOp::AddHalfOp(userrec *user,const char* dest,chanrec *chan,int status)
+{
+       userrec *d = ServerInstance->Modes->SanityChecks(user,dest,chan,status);
+
+       if (d)
+       {
+               if (IS_LOCAL(user))
+               {
+                       int MOD_RESULT = 0;
+                       FOREACH_RESULT(I_OnAccessCheck,OnAccessCheck(user,d,chan,AC_HALFOP));
+
+                       if (MOD_RESULT == ACR_DENY)
+                               return "";
+                       if (MOD_RESULT == ACR_DEFAULT)
+                       {
+                               if ((status < STATUS_OP) && (!ServerInstance->ULine(user->server)))
+                               {
+                                       user->WriteServ("482 %s %s :You're not a channel operator",user->nick, chan->name);
+                                       return "";
+                               }
+                       }
+               }
+
+               return ServerInstance->Modes->Grant(d,chan,UCMODE_HOP);
+       }
+       return "";
+}
+
+std::string ModeChannelHalfOp::DelHalfOp(userrec *user,const char *dest,chanrec *chan,int status)
+{
+       userrec *d = ServerInstance->Modes->SanityChecks(user,dest,chan,status);
+
+       if (d)
+       {
+               if (IS_LOCAL(user))
+               {
+                       int MOD_RESULT = 0;
+                       FOREACH_RESULT(I_OnAccessCheck,OnAccessCheck(user,d,chan,AC_DEHALFOP));
+
+                       if (MOD_RESULT == ACR_DENY)
+                               return "";
+                       if (MOD_RESULT == ACR_DEFAULT)
+                       {
+                               if ((user != d) && ((status < STATUS_OP) && (!ServerInstance->ULine(user->server))))
+                               {
+                                       user->WriteServ("482 %s %s :You are not a channel operator",user->nick, chan->name);
+                                       return "";
+                               }
+                       }
+               }
+
+               return ServerInstance->Modes->Revoke(d,chan,UCMODE_HOP);
+       }
+       return "";
+}
+
index 1dd6dc8571e77f64339d91e0bac41d54960c2989..12bdb18b815c7010c8174d649a6f6dfa968c493d 100644 (file)
@@ -1 +1,35 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "mode.h"\r#include "channels.h"\r#include "users.h"\r#include "modes/cmode_i.h"\r\rModeChannelInviteOnly::ModeChannelInviteOnly(InspIRCd* Instance) : ModeHandler(Instance, 'i', 0, 0, false, MODETYPE_CHANNEL, false)\r{\r}\r\rModeAction ModeChannelInviteOnly::OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)\r{\r     if (channel->modes[CM_INVITEONLY] != adding)\r   {\r              channel->modes[CM_INVITEONLY] = adding;\r                return MODEACTION_ALLOW;\r       }\r      else\r   {\r              return MODEACTION_DENY;\r        }\r}\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "mode.h"
+#include "channels.h"
+#include "users.h"
+#include "modes/cmode_i.h"
+
+ModeChannelInviteOnly::ModeChannelInviteOnly(InspIRCd* Instance) : ModeHandler(Instance, 'i', 0, 0, false, MODETYPE_CHANNEL, false)
+{
+}
+
+ModeAction ModeChannelInviteOnly::OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)
+{
+       if (channel->modes[CM_INVITEONLY] != adding)
+       {
+               channel->modes[CM_INVITEONLY] = adding;
+               return MODEACTION_ALLOW;
+       }
+       else
+       {
+               return MODEACTION_DENY;
+       }
+}
index e06c35e83622318f94376874db80925ffe00c014..eb59714f7d818198fca2e6cdcaadf2cb8997e432 100644 (file)
@@ -1 +1,103 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "mode.h"\r#include "channels.h"\r#include "users.h"\r#include "modes/cmode_k.h"\r\rModeChannelKey::ModeChannelKey(InspIRCd* Instance) : ModeHandler(Instance, 'k', 1, 1, false, MODETYPE_CHANNEL, false)\r{\r}\r\rModePair ModeChannelKey::ModeSet(userrec* source, userrec* dest, chanrec* channel, const std::string &parameter)\r{       \r        if (channel->modes[CM_KEY])\r        {\r                return std::make_pair(true, channel->key);\r        }\r        else\r        {\r                return std::make_pair(false, parameter);\r        }\r}\r\rvoid ModeChannelKey::RemoveMode(chanrec* channel)\r{\r     /** +k needs a parameter when being removed,\r    * so we have a special-case RemoveMode here for it\r     */\r    char moderemove[MAXBUF];\r       const char* parameters[] = { channel->name, moderemove, channel->key };\r\r       if (channel->IsModeSet(this->GetModeChar()))\r   {\r              userrec* n = new userrec(ServerInstance);\r\r             sprintf(moderemove,"-%c",this->GetModeChar());\r         n->SetFd(FD_MAGIC_NUMBER);\r\r            ServerInstance->SendMode(parameters, 3, n);\r\r           delete n;\r      }\r}\r\rvoid ModeChannelKey::RemoveMode(userrec* user)\r{\r}\r\rbool ModeChannelKey::CheckTimeStamp(time_t theirs, time_t ours, const std::string &their_param, const std::string &our_param, chanrec* channel)\r{\r     /* When TS is equal, the alphabetically later channel key wins */\r      return (their_param < our_param);\r}\r\rModeAction ModeChannelKey::OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)\r{\r  if ((channel->modes[CM_KEY] != adding) || (!IS_LOCAL(source)))\r {\r              if (((channel->modes[CM_KEY]) && (strcasecmp(parameter.c_str(),channel->key))) && (IS_LOCAL(source)))\r          {\r                      /* Key is currently set and the correct key wasnt given */\r                     return MODEACTION_DENY;\r                }\r              else if ((!channel->modes[CM_KEY]) || ((adding) && (!IS_LOCAL(source))))\r               {\r                      /* Key isnt currently set */\r                   if ((parameter.length()) && (parameter.rfind(' ') == std::string::npos))\r                       {\r                              strlcpy(channel->key,parameter.c_str(),32);\r                            channel->modes[CM_KEY] = adding;\r                               parameter = channel->key;\r                              return MODEACTION_ALLOW;\r                       }\r                      else\r                           return MODEACTION_DENY;\r                }\r              else if (((channel->modes[CM_KEY]) && (!strcasecmp(parameter.c_str(),channel->key))) || ((!adding) && (!IS_LOCAL(source))))\r            {\r                      /* Key is currently set, and correct key was given */\r                  *channel->key = 0;\r                     channel->modes[CM_KEY] = adding;\r                       return MODEACTION_ALLOW;\r               }\r              return MODEACTION_DENY;\r        }\r      else\r   {\r              return MODEACTION_DENY;\r        }\r}\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "mode.h"
+#include "channels.h"
+#include "users.h"
+#include "modes/cmode_k.h"
+
+ModeChannelKey::ModeChannelKey(InspIRCd* Instance) : ModeHandler(Instance, 'k', 1, 1, false, MODETYPE_CHANNEL, false)
+{
+}
+
+ModePair ModeChannelKey::ModeSet(userrec* source, userrec* dest, chanrec* channel, const std::string &parameter)
+{       
+        if (channel->modes[CM_KEY])
+        {
+                return std::make_pair(true, channel->key);
+        }
+        else
+        {
+                return std::make_pair(false, parameter);
+        }
+}
+
+void ModeChannelKey::RemoveMode(chanrec* channel)
+{
+       /** +k needs a parameter when being removed,
+        * so we have a special-case RemoveMode here for it
+        */
+       char moderemove[MAXBUF];
+       const char* parameters[] = { channel->name, moderemove, channel->key };
+
+       if (channel->IsModeSet(this->GetModeChar()))
+       {
+               userrec* n = new userrec(ServerInstance);
+
+               sprintf(moderemove,"-%c",this->GetModeChar());
+               n->SetFd(FD_MAGIC_NUMBER);
+
+               ServerInstance->SendMode(parameters, 3, n);
+
+               delete n;
+       }
+}
+
+void ModeChannelKey::RemoveMode(userrec* user)
+{
+}
+
+bool ModeChannelKey::CheckTimeStamp(time_t theirs, time_t ours, const std::string &their_param, const std::string &our_param, chanrec* channel)
+{
+       /* When TS is equal, the alphabetically later channel key wins */
+       return (their_param < our_param);
+}
+
+ModeAction ModeChannelKey::OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)
+{
+       if ((channel->modes[CM_KEY] != adding) || (!IS_LOCAL(source)))
+       {
+               if (((channel->modes[CM_KEY]) && (strcasecmp(parameter.c_str(),channel->key))) && (IS_LOCAL(source)))
+               {
+                       /* Key is currently set and the correct key wasnt given */
+                       return MODEACTION_DENY;
+               }
+               else if ((!channel->modes[CM_KEY]) || ((adding) && (!IS_LOCAL(source))))
+               {
+                       /* Key isnt currently set */
+                       if ((parameter.length()) && (parameter.rfind(' ') == std::string::npos))
+                       {
+                               strlcpy(channel->key,parameter.c_str(),32);
+                               channel->modes[CM_KEY] = adding;
+                               parameter = channel->key;
+                               return MODEACTION_ALLOW;
+                       }
+                       else
+                               return MODEACTION_DENY;
+               }
+               else if (((channel->modes[CM_KEY]) && (!strcasecmp(parameter.c_str(),channel->key))) || ((!adding) && (!IS_LOCAL(source))))
+               {
+                       /* Key is currently set, and correct key was given */
+                       *channel->key = 0;
+                       channel->modes[CM_KEY] = adding;
+                       return MODEACTION_ALLOW;
+               }
+               return MODEACTION_DENY;
+       }
+       else
+       {
+               return MODEACTION_DENY;
+       }
+}
+
index 5e1a8c26cd250bcb260fd8a86c535f62030d7c01..1a57a440d30cb0cd3ba97cc097cd72a80a94f115 100644 (file)
@@ -1 +1,97 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "mode.h"\r#include "channels.h"\r#include "users.h"\r#include "modes/cmode_l.h"\r\rModeChannelLimit::ModeChannelLimit(InspIRCd* Instance) : ModeHandler(Instance, 'l', 1, 0, false, MODETYPE_CHANNEL, false)\r{\r}\r\rModePair ModeChannelLimit::ModeSet(userrec* source, userrec* dest, chanrec* channel, const std::string &parameter)\r{\r  if (channel->limit)\r    {\r              return std::make_pair(true, ConvToStr(channel->limit));\r        }\r      else\r   {\r              return std::make_pair(false, parameter);\r       }\r}\r\rbool ModeChannelLimit::CheckTimeStamp(time_t theirs, time_t ours, const std::string &their_param, const std::string &our_param, chanrec* channel)\r{\r       /* When TS is equal, the higher channel limit wins */\r  return (atoi(their_param.c_str()) < atoi(our_param.c_str()));\r}\r\rModeAction ModeChannelLimit::OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)\r{\r    if (adding)\r    {\r              /* Setting a new limit, sanity check */\r                long limit = atoi(parameter.c_str());\r\r         /* Wrap low values at 32768 */\r         if (limit < 0)\r                 limit = 0x7FFF;\r\r               /* If the new limit is the same as the old limit,\r               * and the old limit isnt 0, disallow */\r               if ((limit == channel->limit) && (channel->limit > 0))\r         {\r                      parameter = "";\r                        return MODEACTION_DENY;\r                }\r\r             /* They must have specified an invalid number.\r          * Dont allow +l 0.\r             */\r            if (!limit)\r            {\r                      parameter = "";\r                        return MODEACTION_DENY;\r                }\r\r             parameter = ConvToStr(limit);\r\r         /* Set new limit */\r            channel->limit = limit;\r                channel->modes[CM_LIMIT] = 1;\r\r         return MODEACTION_ALLOW;\r       }\r      else\r   {\r              /* Check if theres a limit here to remove.\r              * If there isnt, dont allow the -l\r             */\r            if (!channel->limit)\r           {\r                      parameter = "";\r                        return MODEACTION_DENY;\r                }\r\r             /* Removing old limit, no checks here */\r               channel->limit = 0;\r            channel->modes[CM_LIMIT] = 0;\r\r         return MODEACTION_ALLOW;\r       }\r\r     return MODEACTION_DENY;\r}\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "mode.h"
+#include "channels.h"
+#include "users.h"
+#include "modes/cmode_l.h"
+
+ModeChannelLimit::ModeChannelLimit(InspIRCd* Instance) : ModeHandler(Instance, 'l', 1, 0, false, MODETYPE_CHANNEL, false)
+{
+}
+
+ModePair ModeChannelLimit::ModeSet(userrec* source, userrec* dest, chanrec* channel, const std::string &parameter)
+{
+       if (channel->limit)
+       {
+               return std::make_pair(true, ConvToStr(channel->limit));
+       }
+       else
+       {
+               return std::make_pair(false, parameter);
+       }
+}
+
+bool ModeChannelLimit::CheckTimeStamp(time_t theirs, time_t ours, const std::string &their_param, const std::string &our_param, chanrec* channel)
+{
+       /* When TS is equal, the higher channel limit wins */
+       return (atoi(their_param.c_str()) < atoi(our_param.c_str()));
+}
+
+ModeAction ModeChannelLimit::OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)
+{
+       if (adding)
+       {
+               /* Setting a new limit, sanity check */
+               long limit = atoi(parameter.c_str());
+
+               /* Wrap low values at 32768 */
+               if (limit < 0)
+                       limit = 0x7FFF;
+
+               /* If the new limit is the same as the old limit,
+                * and the old limit isnt 0, disallow */
+               if ((limit == channel->limit) && (channel->limit > 0))
+               {
+                       parameter = "";
+                       return MODEACTION_DENY;
+               }
+
+               /* They must have specified an invalid number.
+                * Dont allow +l 0.
+                */
+               if (!limit)
+               {
+                       parameter = "";
+                       return MODEACTION_DENY;
+               }
+
+               parameter = ConvToStr(limit);
+
+               /* Set new limit */
+               channel->limit = limit;
+               channel->modes[CM_LIMIT] = 1;
+
+               return MODEACTION_ALLOW;
+       }
+       else
+       {
+               /* Check if theres a limit here to remove.
+                * If there isnt, dont allow the -l
+                */
+               if (!channel->limit)
+               {
+                       parameter = "";
+                       return MODEACTION_DENY;
+               }
+
+               /* Removing old limit, no checks here */
+               channel->limit = 0;
+               channel->modes[CM_LIMIT] = 0;
+
+               return MODEACTION_ALLOW;
+       }
+
+       return MODEACTION_DENY;
+}
index da882333b1db565c241f57d979c7b1e592a41693..520248fdab7e93e074378216b7099b1a8c1428a8 100644 (file)
@@ -1 +1,36 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "mode.h"\r#include "channels.h"\r#include "users.h"\r#include "modes/cmode_m.h"\r\rModeChannelModerated::ModeChannelModerated(InspIRCd* Instance) : ModeHandler(Instance, 'm', 0, 0, false, MODETYPE_CHANNEL, false)\r{\r}\r\rModeAction ModeChannelModerated::OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)\r{\r        if (channel->modes[CM_MODERATED] != adding)\r    {\r              channel->modes[CM_MODERATED] = adding;\r         return MODEACTION_ALLOW;\r       }\r      else\r   {\r              return MODEACTION_DENY;\r        }\r}\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "mode.h"
+#include "channels.h"
+#include "users.h"
+#include "modes/cmode_m.h"
+
+ModeChannelModerated::ModeChannelModerated(InspIRCd* Instance) : ModeHandler(Instance, 'm', 0, 0, false, MODETYPE_CHANNEL, false)
+{
+}
+
+ModeAction ModeChannelModerated::OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)
+{
+       if (channel->modes[CM_MODERATED] != adding)
+       {
+               channel->modes[CM_MODERATED] = adding;
+               return MODEACTION_ALLOW;
+       }
+       else
+       {
+               return MODEACTION_DENY;
+       }
+}
+
index 3ae7d538c9c5a1008ed3ad49f411bcf0810b6dc9..ddc2e1bbd219a7557bb4c992b1b7112ad3b11289 100644 (file)
@@ -1 +1,36 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "mode.h"\r#include "channels.h"\r#include "users.h"\r#include "modes/cmode_n.h"\r\rModeChannelNoExternal::ModeChannelNoExternal(InspIRCd* Instance) : ModeHandler(Instance, 'n', 0, 0, false, MODETYPE_CHANNEL, false)\r{\r}\r\rModeAction ModeChannelNoExternal::OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)\r{\r     if (channel->modes[CM_NOEXTERNAL] != adding)\r   {\r              channel->modes[CM_NOEXTERNAL] = adding;\r                return MODEACTION_ALLOW;\r       }\r      else\r   {\r              return MODEACTION_DENY;\r        }\r}\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "mode.h"
+#include "channels.h"
+#include "users.h"
+#include "modes/cmode_n.h"
+
+ModeChannelNoExternal::ModeChannelNoExternal(InspIRCd* Instance) : ModeHandler(Instance, 'n', 0, 0, false, MODETYPE_CHANNEL, false)
+{
+}
+
+ModeAction ModeChannelNoExternal::OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)
+{
+       if (channel->modes[CM_NOEXTERNAL] != adding)
+       {
+               channel->modes[CM_NOEXTERNAL] = adding;
+               return MODEACTION_ALLOW;
+       }
+       else
+       {
+               return MODEACTION_DENY;
+       }
+}
+
index 9ae18109e6a788bb0a6791e4190590aabb5d4156..47d191ff8f7198a3094d98f27ed78b83068df4ff 100644 (file)
@@ -1 +1,153 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "configreader.h"\r#include "mode.h"\r#include "channels.h"\r#include "users.h"\r#include "modules.h"\r#include "modes/cmode_o.h"\r\rModeChannelOp::ModeChannelOp(InspIRCd* Instance) : ModeHandler(Instance, 'o', 1, 1, true, MODETYPE_CHANNEL, false, '@')\r{\r}\r\runsigned int ModeChannelOp::GetPrefixRank()\r{\r    return OP_VALUE;\r}\r\rModePair ModeChannelOp::ModeSet(userrec* source, userrec* dest, chanrec* channel, const std::string &parameter)\r{\r  userrec* x = ServerInstance->FindNick(parameter);\r      if (x)\r {\r              if (channel->GetStatusFlags(x) & UCMODE_OP)\r            {\r                      return std::make_pair(true, x->nick);\r          }\r              else\r           {\r                      return std::make_pair(false, parameter);\r               }\r      }\r      return std::make_pair(false, parameter);\r}\r\r\rvoid ModeChannelOp::RemoveMode(chanrec* channel)\r{\r        CUList* list = channel->GetOppedUsers();\r       CUList copy;\r   char moderemove[MAXBUF];\r       userrec* n = new userrec(ServerInstance);\r      n->SetFd(FD_MAGIC_NUMBER);\r\r    for (CUList::iterator i = list->begin(); i != list->end(); i++)\r        {\r              userrec* n = i->first;\r         copy.insert(std::make_pair(n,n->nick));\r        }\r      for (CUList::iterator i = copy.begin(); i != copy.end(); i++)\r  {\r              sprintf(moderemove,"-%c",this->GetModeChar());\r         const char* parameters[] = { channel->name, moderemove, i->first->nick };\r              ServerInstance->SendMode(parameters, 3, n);\r    }\r      delete n;\r}\r\rvoid ModeChannelOp::RemoveMode(userrec* user)\r{\r}\r\rModeAction ModeChannelOp::OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)\r{\r        int status = channel->GetStatus(source);\r\r      /* Call the correct method depending on wether we're adding or removing the mode */\r    if (adding)\r    {\r              parameter = this->AddOp(source, parameter.c_str(), channel, status);\r   }\r      else\r   {\r              parameter = this->DelOp(source, parameter.c_str(), channel, status);\r   }\r      /* If the method above 'ate' the parameter by reducing it to an empty string, then\r      * it won't matter wether we return ALLOW or DENY here, as an empty string overrides\r    * the return value and is always MODEACTION_DENY if the mode is supposed to have\r       * a parameter.\r         */\r    if (parameter.length())\r                return MODEACTION_ALLOW;\r       else\r           return MODEACTION_DENY;\r}\r\rstd::string ModeChannelOp::AddOp(userrec *user,const char* dest,chanrec *chan,int status)\r{\r userrec *d = ServerInstance->Modes->SanityChecks(user,dest,chan,status);\r\r      if (d)\r {\r              if (IS_LOCAL(user))\r            {\r                      int MOD_RESULT = 0;\r                    FOREACH_RESULT(I_OnAccessCheck,OnAccessCheck(user,d,chan,AC_OP));\r\r                     if (MOD_RESULT == ACR_DENY)\r                            return "";\r                     if (MOD_RESULT == ACR_DEFAULT)\r                 {\r                              if ((status < STATUS_OP) && (!ServerInstance->ULine(user->server)))\r                            {\r                                      user->WriteServ("482 %s %s :You're not a channel operator",user->nick, chan->name);\r                                    return "";\r                             }\r                      }\r              }\r\r             return ServerInstance->Modes->Grant(d,chan,UCMODE_OP);\r }\r      return "";\r}\r\rstd::string ModeChannelOp::DelOp(userrec *user,const char *dest,chanrec *chan,int status)\r{\r      userrec *d = ServerInstance->Modes->SanityChecks(user,dest,chan,status);\r\r      if (d)\r {\r              if (IS_LOCAL(user))\r            {\r                      int MOD_RESULT = 0;\r                    FOREACH_RESULT(I_OnAccessCheck,OnAccessCheck(user,d,chan,AC_DEOP));\r\r                   if (MOD_RESULT == ACR_DENY)\r                            return "";\r                     if (MOD_RESULT == ACR_DEFAULT)\r                 {\r                              if ((status < STATUS_OP) && (!ServerInstance->ULine(user->server)) && (IS_LOCAL(user)))\r                                {\r                                      user->WriteServ("482 %s %s :You are not a channel operator",user->nick, chan->name);\r                                   return "";\r                             }\r                      }\r              }\r\r             return ServerInstance->Modes->Revoke(d,chan,UCMODE_OP);\r        }\r      return "";\r}\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "configreader.h"
+#include "mode.h"
+#include "channels.h"
+#include "users.h"
+#include "modules.h"
+#include "modes/cmode_o.h"
+
+ModeChannelOp::ModeChannelOp(InspIRCd* Instance) : ModeHandler(Instance, 'o', 1, 1, true, MODETYPE_CHANNEL, false, '@')
+{
+}
+
+unsigned int ModeChannelOp::GetPrefixRank()
+{
+       return OP_VALUE;
+}
+
+ModePair ModeChannelOp::ModeSet(userrec* source, userrec* dest, chanrec* channel, const std::string &parameter)
+{
+       userrec* x = ServerInstance->FindNick(parameter);
+       if (x)
+       {
+               if (channel->GetStatusFlags(x) & UCMODE_OP)
+               {
+                       return std::make_pair(true, x->nick);
+               }
+               else
+               {
+                       return std::make_pair(false, parameter);
+               }
+       }
+       return std::make_pair(false, parameter);
+}
+
+
+void ModeChannelOp::RemoveMode(chanrec* channel)
+{
+       CUList* list = channel->GetOppedUsers();
+       CUList copy;
+       char moderemove[MAXBUF];
+       userrec* n = new userrec(ServerInstance);
+       n->SetFd(FD_MAGIC_NUMBER);
+
+       for (CUList::iterator i = list->begin(); i != list->end(); i++)
+       {
+               userrec* n = i->first;
+               copy.insert(std::make_pair(n,n->nick));
+       }
+       for (CUList::iterator i = copy.begin(); i != copy.end(); i++)
+       {
+               sprintf(moderemove,"-%c",this->GetModeChar());
+               const char* parameters[] = { channel->name, moderemove, i->first->nick };
+               ServerInstance->SendMode(parameters, 3, n);
+       }
+       delete n;
+}
+
+void ModeChannelOp::RemoveMode(userrec* user)
+{
+}
+
+ModeAction ModeChannelOp::OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)
+{
+       int status = channel->GetStatus(source);
+
+       /* Call the correct method depending on wether we're adding or removing the mode */
+       if (adding)
+       {
+               parameter = this->AddOp(source, parameter.c_str(), channel, status);
+       }
+       else
+       {
+               parameter = this->DelOp(source, parameter.c_str(), channel, status);
+       }
+       /* If the method above 'ate' the parameter by reducing it to an empty string, then
+        * it won't matter wether we return ALLOW or DENY here, as an empty string overrides
+        * the return value and is always MODEACTION_DENY if the mode is supposed to have
+        * a parameter.
+        */
+       if (parameter.length())
+               return MODEACTION_ALLOW;
+       else
+               return MODEACTION_DENY;
+}
+
+std::string ModeChannelOp::AddOp(userrec *user,const char* dest,chanrec *chan,int status)
+{
+       userrec *d = ServerInstance->Modes->SanityChecks(user,dest,chan,status);
+
+       if (d)
+       {
+               if (IS_LOCAL(user))
+               {
+                       int MOD_RESULT = 0;
+                       FOREACH_RESULT(I_OnAccessCheck,OnAccessCheck(user,d,chan,AC_OP));
+
+                       if (MOD_RESULT == ACR_DENY)
+                               return "";
+                       if (MOD_RESULT == ACR_DEFAULT)
+                       {
+                               if ((status < STATUS_OP) && (!ServerInstance->ULine(user->server)))
+                               {
+                                       user->WriteServ("482 %s %s :You're not a channel operator",user->nick, chan->name);
+                                       return "";
+                               }
+                       }
+               }
+
+               return ServerInstance->Modes->Grant(d,chan,UCMODE_OP);
+       }
+       return "";
+}
+
+std::string ModeChannelOp::DelOp(userrec *user,const char *dest,chanrec *chan,int status)
+{
+       userrec *d = ServerInstance->Modes->SanityChecks(user,dest,chan,status);
+
+       if (d)
+       {
+               if (IS_LOCAL(user))
+               {
+                       int MOD_RESULT = 0;
+                       FOREACH_RESULT(I_OnAccessCheck,OnAccessCheck(user,d,chan,AC_DEOP));
+
+                       if (MOD_RESULT == ACR_DENY)
+                               return "";
+                       if (MOD_RESULT == ACR_DEFAULT)
+                       {
+                               if ((status < STATUS_OP) && (!ServerInstance->ULine(user->server)) && (IS_LOCAL(user)))
+                               {
+                                       user->WriteServ("482 %s %s :You are not a channel operator",user->nick, chan->name);
+                                       return "";
+                               }
+                       }
+               }
+
+               return ServerInstance->Modes->Revoke(d,chan,UCMODE_OP);
+       }
+       return "";
+}
index c762b78271a95241ffa4f21c54f4c094402f9111..15c33222e155a653ba1b13277b3e309cfa922fe6 100644 (file)
@@ -1 +1,35 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "mode.h"\r#include "channels.h"\r#include "users.h"\r#include "modes/cmode_p.h"\r\rModeChannelPrivate::ModeChannelPrivate(InspIRCd* Instance) : ModeHandler(Instance, 'p', 0, 0, false, MODETYPE_CHANNEL, false)\r{\r}\r\rModeAction ModeChannelPrivate::OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)\r{\r      if (channel->modes[CM_PRIVATE] != adding)\r      {\r              channel->modes[CM_PRIVATE] = adding;\r           return MODEACTION_ALLOW;\r       }\r      else\r   {\r              return MODEACTION_DENY;\r        }\r}\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "mode.h"
+#include "channels.h"
+#include "users.h"
+#include "modes/cmode_p.h"
+
+ModeChannelPrivate::ModeChannelPrivate(InspIRCd* Instance) : ModeHandler(Instance, 'p', 0, 0, false, MODETYPE_CHANNEL, false)
+{
+}
+
+ModeAction ModeChannelPrivate::OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)
+{
+       if (channel->modes[CM_PRIVATE] != adding)
+       {
+               channel->modes[CM_PRIVATE] = adding;
+               return MODEACTION_ALLOW;
+       }
+       else
+       {
+               return MODEACTION_DENY;
+       }
+}
index 069591e6b574fb74785f74703af33c54ce193bbc..135291592c7bc2cce4dccfbec2b44ec26343aafa 100644 (file)
@@ -1 +1,35 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "mode.h"\r#include "channels.h"\r#include "users.h"\r#include "modes/cmode_s.h"\r\rModeChannelSecret::ModeChannelSecret(InspIRCd* Instance) : ModeHandler(Instance, 's', 0, 0, false, MODETYPE_CHANNEL, false)\r{\r}\r\rModeAction ModeChannelSecret::OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)\r{\r if (channel->modes[CM_SECRET] != adding)\r       {\r              channel->modes[CM_SECRET] = adding;\r            return MODEACTION_ALLOW;\r       }\r      else\r   {\r              return MODEACTION_DENY;\r        }\r}\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "mode.h"
+#include "channels.h"
+#include "users.h"
+#include "modes/cmode_s.h"
+
+ModeChannelSecret::ModeChannelSecret(InspIRCd* Instance) : ModeHandler(Instance, 's', 0, 0, false, MODETYPE_CHANNEL, false)
+{
+}
+
+ModeAction ModeChannelSecret::OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)
+{
+       if (channel->modes[CM_SECRET] != adding)
+       {
+               channel->modes[CM_SECRET] = adding;
+               return MODEACTION_ALLOW;
+       }
+       else
+       {
+               return MODEACTION_DENY;
+       }
+}
index def48a7811c6804d0401a030b5293bc980b45c36..2a6c06b42ec2091171062c95416bf1097bec035d 100644 (file)
@@ -1 +1,36 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "mode.h"\r#include "channels.h"\r#include "users.h"\r#include "modes/cmode_t.h"\r\rModeChannelTopicOps::ModeChannelTopicOps(InspIRCd* Instance) : ModeHandler(Instance, 't', 0, 0, false, MODETYPE_CHANNEL, false)\r{\r}\r\rModeAction ModeChannelTopicOps::OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)\r{\r   if (channel->modes[CM_TOPICLOCK] != adding)\r    {\r              channel->modes[CM_TOPICLOCK] = adding;\r         return MODEACTION_ALLOW;\r       }\r      else\r   {\r              return MODEACTION_DENY;\r        }\r}\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "mode.h"
+#include "channels.h"
+#include "users.h"
+#include "modes/cmode_t.h"
+
+ModeChannelTopicOps::ModeChannelTopicOps(InspIRCd* Instance) : ModeHandler(Instance, 't', 0, 0, false, MODETYPE_CHANNEL, false)
+{
+}
+
+ModeAction ModeChannelTopicOps::OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)
+{
+       if (channel->modes[CM_TOPICLOCK] != adding)
+       {
+               channel->modes[CM_TOPICLOCK] = adding;
+               return MODEACTION_ALLOW;
+       }
+       else
+       {
+               return MODEACTION_DENY;
+       }
+}
+
index c055cca7fe25149a10f4d0ed61b2f6bfb3c22075..1e244c606eaf74d8b26b142543d1ad8c8d7ce8ae 100644 (file)
@@ -1 +1,152 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "configreader.h"\r#include "mode.h"\r#include "channels.h"\r#include "users.h"\r#include "modules.h"\r#include "modes/cmode_v.h"\r\rModeChannelVoice::ModeChannelVoice(InspIRCd* Instance) : ModeHandler(Instance, 'v', 1, 1, true, MODETYPE_CHANNEL, false, '+')\r{\r}\r\runsigned int ModeChannelVoice::GetPrefixRank()\r{\r   return VOICE_VALUE;\r}\r\rModePair ModeChannelVoice::ModeSet(userrec* source, userrec* dest, chanrec* channel, const std::string &parameter)\r{\r    userrec* x = ServerInstance->FindNick(parameter);\r      if (x)\r {\r              if (channel->GetStatusFlags(x) & UCMODE_VOICE)\r         {\r                      return std::make_pair(true, x->nick);\r          }\r              else\r           {\r                      return std::make_pair(false, parameter);\r               }\r      }\r      return std::make_pair(false, parameter);\r}\r\rvoid ModeChannelVoice::RemoveMode(chanrec* channel)\r{\r      CUList* list = channel->GetVoicedUsers();\r      CUList copy;\r   char moderemove[MAXBUF];\r       userrec* n = new userrec(ServerInstance);\r      n->SetFd(FD_MAGIC_NUMBER);\r\r    for (CUList::iterator i = list->begin(); i != list->end(); i++)\r        {\r              userrec* n = i->first;\r         copy.insert(std::make_pair(n,n->nick));\r        }\r      for (CUList::iterator i = copy.begin(); i != copy.end(); i++)\r  {\r              sprintf(moderemove,"-%c",this->GetModeChar());\r         const char* parameters[] = { channel->name, moderemove, i->first->nick };\r              ServerInstance->SendMode(parameters, 3, n);\r    }\r      delete n;\r}\r\rvoid ModeChannelVoice::RemoveMode(userrec* user)\r{\r}\r\rModeAction ModeChannelVoice::OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)\r{\r  int status = channel->GetStatus(source);\r\r      /* Call the correct method depending on wether we're adding or removing the mode */\r    if (adding)\r    {\r              parameter = this->AddVoice(source, parameter.c_str(), channel, status);\r        }\r      else\r   {\r              parameter = this->DelVoice(source, parameter.c_str(), channel, status);\r        }\r      /* If the method above 'ate' the parameter by reducing it to an empty string, then\r      * it won't matter wether we return ALLOW or DENY here, as an empty string overrides\r    * the return value and is always MODEACTION_DENY if the mode is supposed to have\r       * a parameter.\r         */\r    if (parameter.length())\r                return MODEACTION_ALLOW;\r       else\r           return MODEACTION_DENY;\r}\r\rstd::string ModeChannelVoice::AddVoice(userrec *user,const char* dest,chanrec *chan,int status)\r{\r   userrec *d = ServerInstance->Modes->SanityChecks(user,dest,chan,status);\r\r      if (d)\r {\r              if (IS_LOCAL(user))\r            {\r                      int MOD_RESULT = 0;\r                    FOREACH_RESULT(I_OnAccessCheck,OnAccessCheck(user,d,chan,AC_VOICE));\r\r                  if (MOD_RESULT == ACR_DENY)\r                            return "";\r                     if (MOD_RESULT == ACR_DEFAULT)\r                 {\r                              if ((status < STATUS_HOP) && (!ServerInstance->ULine(user->server)))\r                           {\r                                      user->WriteServ("482 %s %s :You're not a channel (half)operator",user->nick, chan->name);\r                                      return "";\r                             }\r                      }\r              }\r\r             return ServerInstance->Modes->Grant(d,chan,UCMODE_VOICE);\r      }\r      return "";\r}\r\rstd::string ModeChannelVoice::DelVoice(userrec *user,const char *dest,chanrec *chan,int status)\r{\r        userrec *d = ServerInstance->Modes->SanityChecks(user,dest,chan,status);\r\r      if (d)\r {\r              if (IS_LOCAL(user))\r            {\r                      int MOD_RESULT = 0;\r                    FOREACH_RESULT(I_OnAccessCheck,OnAccessCheck(user,d,chan,AC_DEVOICE));\r\r                        if (MOD_RESULT == ACR_DENY)\r                            return "";\r                     if (MOD_RESULT == ACR_DEFAULT)\r                 {\r                              if ((status < STATUS_HOP) && (!ServerInstance->ULine(user->server)))\r                           {\r                                      user->WriteServ("482 %s %s :You are not a channel (half)operator",user->nick, chan->name);\r                                     return "";\r                             }\r                      }\r              }\r\r             return ServerInstance->Modes->Revoke(d,chan,UCMODE_VOICE);\r     }\r      return "";\r}\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "configreader.h"
+#include "mode.h"
+#include "channels.h"
+#include "users.h"
+#include "modules.h"
+#include "modes/cmode_v.h"
+
+ModeChannelVoice::ModeChannelVoice(InspIRCd* Instance) : ModeHandler(Instance, 'v', 1, 1, true, MODETYPE_CHANNEL, false, '+')
+{
+}
+
+unsigned int ModeChannelVoice::GetPrefixRank()
+{
+       return VOICE_VALUE;
+}
+
+ModePair ModeChannelVoice::ModeSet(userrec* source, userrec* dest, chanrec* channel, const std::string &parameter)
+{
+       userrec* x = ServerInstance->FindNick(parameter);
+       if (x)
+       {
+               if (channel->GetStatusFlags(x) & UCMODE_VOICE)
+               {
+                       return std::make_pair(true, x->nick);
+               }
+               else
+               {
+                       return std::make_pair(false, parameter);
+               }
+       }
+       return std::make_pair(false, parameter);
+}
+
+void ModeChannelVoice::RemoveMode(chanrec* channel)
+{
+       CUList* list = channel->GetVoicedUsers();
+       CUList copy;
+       char moderemove[MAXBUF];
+       userrec* n = new userrec(ServerInstance);
+       n->SetFd(FD_MAGIC_NUMBER);
+
+       for (CUList::iterator i = list->begin(); i != list->end(); i++)
+       {
+               userrec* n = i->first;
+               copy.insert(std::make_pair(n,n->nick));
+       }
+       for (CUList::iterator i = copy.begin(); i != copy.end(); i++)
+       {
+               sprintf(moderemove,"-%c",this->GetModeChar());
+               const char* parameters[] = { channel->name, moderemove, i->first->nick };
+               ServerInstance->SendMode(parameters, 3, n);
+       }
+       delete n;
+}
+
+void ModeChannelVoice::RemoveMode(userrec* user)
+{
+}
+
+ModeAction ModeChannelVoice::OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)
+{
+       int status = channel->GetStatus(source);
+
+       /* Call the correct method depending on wether we're adding or removing the mode */
+       if (adding)
+       {
+               parameter = this->AddVoice(source, parameter.c_str(), channel, status);
+       }
+       else
+       {
+               parameter = this->DelVoice(source, parameter.c_str(), channel, status);
+       }
+       /* If the method above 'ate' the parameter by reducing it to an empty string, then
+        * it won't matter wether we return ALLOW or DENY here, as an empty string overrides
+        * the return value and is always MODEACTION_DENY if the mode is supposed to have
+        * a parameter.
+        */
+       if (parameter.length())
+               return MODEACTION_ALLOW;
+       else
+               return MODEACTION_DENY;
+}
+
+std::string ModeChannelVoice::AddVoice(userrec *user,const char* dest,chanrec *chan,int status)
+{
+       userrec *d = ServerInstance->Modes->SanityChecks(user,dest,chan,status);
+
+       if (d)
+       {
+               if (IS_LOCAL(user))
+               {
+                       int MOD_RESULT = 0;
+                       FOREACH_RESULT(I_OnAccessCheck,OnAccessCheck(user,d,chan,AC_VOICE));
+
+                       if (MOD_RESULT == ACR_DENY)
+                               return "";
+                       if (MOD_RESULT == ACR_DEFAULT)
+                       {
+                               if ((status < STATUS_HOP) && (!ServerInstance->ULine(user->server)))
+                               {
+                                       user->WriteServ("482 %s %s :You're not a channel (half)operator",user->nick, chan->name);
+                                       return "";
+                               }
+                       }
+               }
+
+               return ServerInstance->Modes->Grant(d,chan,UCMODE_VOICE);
+       }
+       return "";
+}
+
+std::string ModeChannelVoice::DelVoice(userrec *user,const char *dest,chanrec *chan,int status)
+{
+       userrec *d = ServerInstance->Modes->SanityChecks(user,dest,chan,status);
+
+       if (d)
+       {
+               if (IS_LOCAL(user))
+               {
+                       int MOD_RESULT = 0;
+                       FOREACH_RESULT(I_OnAccessCheck,OnAccessCheck(user,d,chan,AC_DEVOICE));
+
+                       if (MOD_RESULT == ACR_DENY)
+                               return "";
+                       if (MOD_RESULT == ACR_DEFAULT)
+                       {
+                               if ((status < STATUS_HOP) && (!ServerInstance->ULine(user->server)))
+                               {
+                                       user->WriteServ("482 %s %s :You are not a channel (half)operator",user->nick, chan->name);
+                                       return "";
+                               }
+                       }
+               }
+
+               return ServerInstance->Modes->Revoke(d,chan,UCMODE_VOICE);
+       }
+       return "";
+}
index 6bd769a9ac4d2a3870001f79e1703998cce78cde..5a93273757e0a7e7f8323f5e31e9c1404149ab92 100644 (file)
@@ -1 +1,45 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "mode.h"\r#include "channels.h"\r#include "users.h"\r#include "modes/umode_i.h"\r\rModeUserInvisible::ModeUserInvisible(InspIRCd* Instance) : ModeHandler(Instance, 'i', 0, 0, false, MODETYPE_USER, false)\r{\r}\r\rModeAction ModeUserInvisible::OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)\r{\r    /* Only opers can change other users modes */\r  if ((source != dest) && (!*source->oper))\r              return MODEACTION_DENY;\r\r       /* Set the bitfields */\r        if (dest->modes[UM_INVISIBLE] != adding)\r       {\r              dest->modes[UM_INVISIBLE] = adding;\r            this->count += (adding ? 1: -1);\r               return MODEACTION_ALLOW;\r       }\r\r     /* Allow the change */\r return MODEACTION_DENY;\r}\r\runsigned int ModeUserInvisible::GetCount()\r{\r        return count;\r}\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "mode.h"
+#include "channels.h"
+#include "users.h"
+#include "modes/umode_i.h"
+
+ModeUserInvisible::ModeUserInvisible(InspIRCd* Instance) : ModeHandler(Instance, 'i', 0, 0, false, MODETYPE_USER, false)
+{
+}
+
+ModeAction ModeUserInvisible::OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)
+{
+       /* Only opers can change other users modes */
+       if ((source != dest) && (!*source->oper))
+               return MODEACTION_DENY;
+
+       /* Set the bitfields */
+       if (dest->modes[UM_INVISIBLE] != adding)
+       {
+               dest->modes[UM_INVISIBLE] = adding;
+               this->count += (adding ? 1: -1);
+               return MODEACTION_ALLOW;
+       }
+
+       /* Allow the change */
+       return MODEACTION_DENY;
+}
+
+unsigned int ModeUserInvisible::GetCount()
+{
+       return count;
+}
index c5d2599d87108e5ee0976e3467547af8eb72dda5..c9c9e312ef309f0b52beb62cab292df33db3354e 100644 (file)
@@ -1 +1,58 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "mode.h"\r#include "channels.h"\r#include "users.h"\r#include "modes/umode_n.h"\r\rModeUserServerNoticeMask::ModeUserServerNoticeMask(InspIRCd* Instance) : ModeHandler(Instance, 'n', 1, 0, false, MODETYPE_USER, true)\r{\r}\r\rModeAction ModeUserServerNoticeMask::OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)\r{\r        /* Only opers can change other users modes */\r  if ((source != dest) && (!*source->oper))\r              return MODEACTION_DENY;\r\r       /* Set the bitfields */\r        if (adding)\r    {\r              /* Fix for bug #310 reported by Smartys */\r             if (!dest->modes[UM_SNOMASK])\r                  memset(dest->snomasks, 0, sizeof(dest->snomasks));\r\r            parameter = dest->ProcessNoticeMasks(parameter.c_str());\r               dest->modes[UM_SNOMASK] = true;\r                if (!dest->modes[UM_SERVERNOTICE])\r             {\r                      const char* newmodes[] = { dest->nick, "+s" };\r                 ServerInstance->Modes->Process(newmodes, 2, source, true);\r             }\r              return MODEACTION_ALLOW;\r       }\r      else\r   {\r              if (dest->modes[UM_SNOMASK] != false)\r          {\r                      dest->modes[UM_SNOMASK] = false;\r                       return MODEACTION_ALLOW;\r               }\r      }\r\r     /* Allow the change */\r return MODEACTION_DENY;\r}\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "mode.h"
+#include "channels.h"
+#include "users.h"
+#include "modes/umode_n.h"
+
+ModeUserServerNoticeMask::ModeUserServerNoticeMask(InspIRCd* Instance) : ModeHandler(Instance, 'n', 1, 0, false, MODETYPE_USER, true)
+{
+}
+
+ModeAction ModeUserServerNoticeMask::OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)
+{
+       /* Only opers can change other users modes */
+       if ((source != dest) && (!*source->oper))
+               return MODEACTION_DENY;
+
+       /* Set the bitfields */
+       if (adding)
+       {
+               /* Fix for bug #310 reported by Smartys */
+               if (!dest->modes[UM_SNOMASK])
+                       memset(dest->snomasks, 0, sizeof(dest->snomasks));
+
+               parameter = dest->ProcessNoticeMasks(parameter.c_str());
+               dest->modes[UM_SNOMASK] = true;
+               if (!dest->modes[UM_SERVERNOTICE])
+               {
+                       const char* newmodes[] = { dest->nick, "+s" };
+                       ServerInstance->Modes->Process(newmodes, 2, source, true);
+               }
+               return MODEACTION_ALLOW;
+       }
+       else
+       {
+               if (dest->modes[UM_SNOMASK] != false)
+               {
+                       dest->modes[UM_SNOMASK] = false;
+                       return MODEACTION_ALLOW;
+               }
+       }
+
+       /* Allow the change */
+       return MODEACTION_DENY;
+}
+
index 1b47fe8b24d1c38104d88f067b0cb972846cf03c..30ed089f6e0cf38c0ae566cf1217c9776a891058 100644 (file)
@@ -1 +1,49 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "mode.h"\r#include "channels.h"\r#include "users.h"\r#include "modes/umode_o.h"\r\rModeUserOperator::ModeUserOperator(InspIRCd* Instance) : ModeHandler(Instance, 'o', 0, 0, false, MODETYPE_USER, true)\r{\r}\r\rModeAction ModeUserOperator::OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)\r{\r        /* Only opers can execute this class at all */\r if (!*source->oper)\r            return MODEACTION_DENY;\r\r       /* Not even opers can GIVE the +o mode, only take it away */\r   if (adding)\r            return MODEACTION_DENY;\r\r       /* Set the bitfields.\r   * Note that oper status is only given in cmd_oper.cpp\r  * NOT here. It is impossible to directly set +o without\r        * verifying as an oper and getting an opertype assigned\r        * to your userrec!\r     */\r    ServerInstance->SNO->WriteToSnoMask('o', "User %s de-opered (by %s)", dest->nick, source->nick);\r       dest->UnOper();\r\r       return MODEACTION_ALLOW;\r}\r\runsigned int ModeUserOperator::GetCount()\r{\r        return ServerInstance->all_opers.size();\r}\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "mode.h"
+#include "channels.h"
+#include "users.h"
+#include "modes/umode_o.h"
+
+ModeUserOperator::ModeUserOperator(InspIRCd* Instance) : ModeHandler(Instance, 'o', 0, 0, false, MODETYPE_USER, true)
+{
+}
+
+ModeAction ModeUserOperator::OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)
+{
+       /* Only opers can execute this class at all */
+       if (!*source->oper)
+               return MODEACTION_DENY;
+
+       /* Not even opers can GIVE the +o mode, only take it away */
+       if (adding)
+               return MODEACTION_DENY;
+
+       /* Set the bitfields.
+        * Note that oper status is only given in cmd_oper.cpp
+        * NOT here. It is impossible to directly set +o without
+        * verifying as an oper and getting an opertype assigned
+        * to your userrec!
+        */
+       ServerInstance->SNO->WriteToSnoMask('o', "User %s de-opered (by %s)", dest->nick, source->nick);
+       dest->UnOper();
+
+       return MODEACTION_ALLOW;
+}
+
+unsigned int ModeUserOperator::GetCount()
+{
+       return ServerInstance->all_opers.size();
+}
index f0441b85f7efe4035286ec6de6681b9a92acfeeb..4b3179001af415419eb14950628f1ba05720bdd8 100644 (file)
@@ -1 +1,45 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "mode.h"\r#include "channels.h"\r#include "users.h"\r#include "modes/umode_s.h"\r\rModeUserServerNotice::ModeUserServerNotice(InspIRCd* Instance) : ModeHandler(Instance, 's', 0, 0, false, MODETYPE_USER, false)\r{\r}\r\rModeAction ModeUserServerNotice::OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)\r{\r   /* Only opers can change other users modes */\r  if ((source != dest) && (!*source->oper))\r              return MODEACTION_DENY;\r\r       /* Set the bitfields */\r        if (dest->modes[UM_SERVERNOTICE] != adding)\r    {\r              dest->modes[UM_SERVERNOTICE] = adding;\r         this->count += (adding ? 1: -1);\r               return MODEACTION_ALLOW;\r       }\r\r     /* Allow the change */\r return MODEACTION_DENY;\r}\r\runsigned int ModeUserServerNotice::GetCount()\r{\r     return count;\r}\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "mode.h"
+#include "channels.h"
+#include "users.h"
+#include "modes/umode_s.h"
+
+ModeUserServerNotice::ModeUserServerNotice(InspIRCd* Instance) : ModeHandler(Instance, 's', 0, 0, false, MODETYPE_USER, false)
+{
+}
+
+ModeAction ModeUserServerNotice::OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)
+{
+       /* Only opers can change other users modes */
+       if ((source != dest) && (!*source->oper))
+               return MODEACTION_DENY;
+
+       /* Set the bitfields */
+       if (dest->modes[UM_SERVERNOTICE] != adding)
+       {
+               dest->modes[UM_SERVERNOTICE] = adding;
+               this->count += (adding ? 1: -1);
+               return MODEACTION_ALLOW;
+       }
+
+       /* Allow the change */
+       return MODEACTION_DENY;
+}
+
+unsigned int ModeUserServerNotice::GetCount()
+{
+       return count;
+}
index 21c0076558dda12c01d8c94cf2cc54d2cd707184..383c91f6ef1f5e6a179d568a42141e41bd6e6e23 100644 (file)
@@ -1 +1,46 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "mode.h"\r#include "channels.h"\r#include "users.h"\r#include "modes/umode_w.h"\r\rModeUserWallops::ModeUserWallops(InspIRCd* Instance) : ModeHandler(Instance, 'w', 0, 0, false, MODETYPE_USER, false)\r{\r}\r\rModeAction ModeUserWallops::OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)\r{\r  /* Only opers can change other users modes */\r  if ((source != dest) && (!*source->oper))\r              return MODEACTION_DENY;\r\r       /* Set the bitfields */\r        if (dest->modes[UM_WALLOPS] != adding)\r {\r              dest->modes[UM_WALLOPS] = adding;\r              this->count += (adding ? 1: -1);\r               return MODEACTION_ALLOW;\r       }\r\r     /* Allow the change */\r return MODEACTION_DENY;\r}\r\runsigned int ModeUserWallops::GetCount()\r{\r  return count;\r}\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "mode.h"
+#include "channels.h"
+#include "users.h"
+#include "modes/umode_w.h"
+
+ModeUserWallops::ModeUserWallops(InspIRCd* Instance) : ModeHandler(Instance, 'w', 0, 0, false, MODETYPE_USER, false)
+{
+}
+
+ModeAction ModeUserWallops::OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)
+{
+       /* Only opers can change other users modes */
+       if ((source != dest) && (!*source->oper))
+               return MODEACTION_DENY;
+
+       /* Set the bitfields */
+       if (dest->modes[UM_WALLOPS] != adding)
+       {
+               dest->modes[UM_WALLOPS] = adding;
+               this->count += (adding ? 1: -1);
+               return MODEACTION_ALLOW;
+       }
+
+       /* Allow the change */
+       return MODEACTION_DENY;
+}
+
+unsigned int ModeUserWallops::GetCount()
+{
+       return count;
+}
+
index 2c34a034c9323edcc71a07bfa83cb9a9f936d3a7..9deaa79545c8e5113e1e4337f31208e11a91a2bb 100644 (file)
@@ -1 +1,732 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "configreader.h"\r#include "users.h"\r#include "modules.h"\r#include "wildcard.h"\r#include "mode.h"\r#include "xline.h"\r#include "socket.h"\r#include "socketengine.h"\r#include "command_parse.h"\r#include "dns.h"\r\r// version is a simple class for holding a modules version number\rVersion::Version(int major, int minor, int revision, int build, int flags, int api_ver)\r: Major(major), Minor(minor), Revision(revision), Build(build), Flags(flags), API(api_ver)\r{\r}\r\rRequest::Request(char* anydata, Module* src, Module* dst)\r: data(anydata), source(src), dest(dst)\r{\r       /* Ensure that because this module doesnt support ID strings, it doesnt break modules that do\r   * by passing them uninitialized pointers (could happen)\r        */\r    id = '\0';\r}\r\rRequest::Request(Module* src, Module* dst, const char* idstr)\r: id(idstr), source(src), dest(dst)\r{\r}\r\rchar* Request::GetData()\r{\r        return this->data;\r}\r\rconst char* Request::GetId()\r{\r   return this->id;\r}\r\rModule* Request::GetSource()\r{\r     return this->source;\r}\r\rModule* Request::GetDest()\r{\r   return this->dest;\r}\r\rchar* Request::Send()\r{\r  if (this->dest)\r        {\r              return dest->OnRequest(this);\r  }\r      else\r   {\r              return NULL;\r   }\r}\r\rEvent::Event(char* anydata, Module* src, const std::string &eventid) : data(anydata), source(src), id(eventid) { }\r\rchar* Event::GetData()\r{\r      return (char*)this->data;\r}\r\rModule* Event::GetSource()\r{\r      return this->source;\r}\r\rchar* Event::Send(InspIRCd* ServerInstance)\r{\r  FOREACH_MOD(I_OnEvent,OnEvent(this));\r  return NULL;\r}\r\rstd::string Event::GetEventID()\r{\r      return this->id;\r}\r\r\r// These declarations define the behavours of the base class Module (which does nothing at all)\r\r          Module::Module(InspIRCd* Me) : ServerInstance(Me) { }\r          Module::~Module() { }\rvoid              Module::OnUserConnect(userrec* user) { }\rvoid           Module::OnUserQuit(userrec* user, const std::string& message, const std::string &oper_message) { }\rvoid         Module::OnUserDisconnect(userrec* user) { }\rvoid                Module::OnUserJoin(userrec* user, chanrec* channel, bool &silent) { }\rvoid              Module::OnPostJoin(userrec* user, chanrec* channel) { }\rvoid            Module::OnUserPart(userrec* user, chanrec* channel, const std::string &partmessage, bool &silent) { }\rvoid              Module::OnRehash(userrec* user, const std::string &parameter) { }\rvoid          Module::OnServerRaw(std::string &raw, bool inbound, userrec* user) { }\rint              Module::OnUserPreJoin(userrec* user, chanrec* chan, const char* cname, std::string &privs) { return 0; }\rvoid           Module::OnMode(userrec* user, void* dest, int target_type, const std::string &text) { }\rVersion         Module::GetVersion() { return Version(1,0,0,0,VF_VENDOR,-1); }\rvoid             Module::OnOper(userrec* user, const std::string &opertype) { }\rvoid             Module::OnPostOper(userrec* user, const std::string &opertype) { }\rvoid         Module::OnInfo(userrec* user) { }\rvoid          Module::OnWhois(userrec* source, userrec* dest) { }\rint         Module::OnUserPreInvite(userrec* source,userrec* dest,chanrec* channel) { return 0; }\rint               Module::OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text,char status, CUList &exempt_list) { return 0; }\rint                Module::OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text,char status, CUList &exempt_list) { return 0; }\rint         Module::OnUserPreNick(userrec* user, const std::string &newnick) { return 0; }\rvoid             Module::OnUserPostNick(userrec* user, const std::string &oldnick) { }\rint               Module::OnAccessCheck(userrec* source,userrec* dest,chanrec* channel,int access_type) { return ACR_DEFAULT; }\rvoid              Module::On005Numeric(std::string &output) { }\rint               Module::OnKill(userrec* source, userrec* dest, const std::string &reason) { return 0; }\rvoid            Module::OnLoadModule(Module* mod,const std::string &name) { }\rvoid              Module::OnUnloadModule(Module* mod,const std::string &name) { }\rvoid            Module::OnBackgroundTimer(time_t curtime) { }\rint               Module::OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line) { return 0; }\rvoid         Module::OnPostCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, CmdResult result, const std::string &original_line) { }\rbool                Module::OnCheckReady(userrec* user) { return true; }\rint                Module::OnUserRegister(userrec* user) { return 0; }\rint         Module::OnUserPreKick(userrec* source, userrec* user, chanrec* chan, const std::string &reason) { return 0; }\rvoid              Module::OnUserKick(userrec* source, userrec* user, chanrec* chan, const std::string &reason, bool &silent) { }\rint              Module::OnCheckInvite(userrec* user, chanrec* chan) { return 0; }\rint           Module::OnCheckKey(userrec* user, chanrec* chan, const std::string &keygiven) { return 0; }\rint         Module::OnCheckLimit(userrec* user, chanrec* chan) { return 0; }\rint            Module::OnCheckBan(userrec* user, chanrec* chan) { return 0; }\rint              Module::OnStats(char symbol, userrec* user, string_list &results) { return 0; }\rint             Module::OnChangeLocalUserHost(userrec* user, const std::string &newhost) { return 0; }\rint              Module::OnChangeLocalUserGECOS(userrec* user, const std::string &newhost) { return 0; }\rint             Module::OnLocalTopicChange(userrec* user, chanrec* chan, const std::string &topic) { return 0; }\rvoid           Module::OnEvent(Event* event) { return; }\rchar*         Module::OnRequest(Request* request) { return NULL; }\rint                Module::OnOperCompare(const std::string &password, const std::string &input, int tagnumber) { return 0; }\rvoid          Module::OnGlobalOper(userrec* user) { }\rvoid            Module::OnPostConnect(userrec* user) { }\rint            Module::OnAddBan(userrec* source, chanrec* channel,const std::string &banmask) { return 0; }\rint                Module::OnDelBan(userrec* source, chanrec* channel,const std::string &banmask) { return 0; }\rvoid               Module::OnRawSocketAccept(int fd, const std::string &ip, int localport) { }\rint         Module::OnRawSocketWrite(int fd, const char* buffer, int count) { return 0; }\rvoid              Module::OnRawSocketClose(int fd) { }\rvoid               Module::OnRawSocketConnect(int fd) { }\rint              Module::OnRawSocketRead(int fd, char* buffer, unsigned int count, int &readresult) { return 0; }\rvoid           Module::OnUserMessage(userrec* user, void* dest, int target_type, const std::string &text, char status, const CUList &exempt_list) { }\rvoid             Module::OnUserNotice(userrec* user, void* dest, int target_type, const std::string &text, char status, const CUList &exempt_list) { }\rvoid              Module::OnRemoteKill(userrec* source, userrec* dest, const std::string &reason, const std::string &operreason) { }\rvoid         Module::OnUserInvite(userrec* source,userrec* dest,chanrec* channel) { }\rvoid           Module::OnPostLocalTopicChange(userrec* user, chanrec* chan, const std::string &topic) { }\rvoid         Module::OnGetServerDescription(const std::string &servername,std::string &description) { }\rvoid         Module::OnSyncUser(userrec* user, Module* proto, void* opaque) { }\rvoid         Module::OnSyncChannel(chanrec* chan, Module* proto, void* opaque) { }\rvoid              Module::ProtoSendMode(void* opaque, int target_type, void* target, const std::string &modeline) { }\rvoid                Module::OnSyncChannelMetaData(chanrec* chan, Module* proto,void* opaque, const std::string &extname, bool displayable) { }\rvoid         Module::OnSyncUserMetaData(userrec* user, Module* proto,void* opaque, const std::string &extname, bool displayable) { }\rvoid            Module::OnSyncOtherMetaData(Module* proto, void* opaque, bool displayable) { }\rvoid             Module::OnDecodeMetaData(int target_type, void* target, const std::string &extname, const std::string &extdata) { }\rvoid                Module::ProtoSendMetaData(void* opaque, int target_type, void* target, const std::string &extname, const std::string &extdata) { }\rvoid         Module::OnWallops(userrec* user, const std::string &text) { }\rvoid              Module::OnChangeHost(userrec* user, const std::string &newhost) { }\rvoid                Module::OnChangeName(userrec* user, const std::string &gecos) { }\rvoid          Module::OnAddGLine(long duration, userrec* source, const std::string &reason, const std::string &hostmask) { }\rvoid             Module::OnAddZLine(long duration, userrec* source, const std::string &reason, const std::string &ipmask) { }\rvoid               Module::OnAddKLine(long duration, userrec* source, const std::string &reason, const std::string &hostmask) { }\rvoid             Module::OnAddQLine(long duration, userrec* source, const std::string &reason, const std::string &nickmask) { }\rvoid             Module::OnAddELine(long duration, userrec* source, const std::string &reason, const std::string &hostmask) { }\rvoid             Module::OnDelGLine(userrec* source, const std::string &hostmask) { }\rvoid               Module::OnDelZLine(userrec* source, const std::string &ipmask) { }\rvoid         Module::OnDelKLine(userrec* source, const std::string &hostmask) { }\rvoid               Module::OnDelQLine(userrec* source, const std::string &nickmask) { }\rvoid               Module::OnDelELine(userrec* source, const std::string &hostmask) { }\rvoid               Module::OnCleanup(int target_type, void* item) { }\rvoid         Module::Implements(char* Implements) { for (int j = 0; j < 255; j++) Implements[j] = 0; }\rvoid          Module::OnChannelDelete(chanrec* chan) { }\rPriority     Module::Prioritize() { return PRIORITY_DONTCARE; }\rvoid         Module::OnSetAway(userrec* user) { }\rvoid               Module::OnCancelAway(userrec* user) { }\rint             Module::OnUserList(userrec* user, chanrec* Ptr, CUList* &userlist) { return 0; }\rint            Module::OnWhoisLine(userrec* user, userrec* dest, int &numeric, std::string &text) { return 0; }\rvoid           Module::OnBuildExemptList(MessageType message_type, chanrec* chan, userrec* sender, char status, CUList &exempt_list) { }\rvoid          Module::OnGarbageCollect() { }\rvoid             Module::OnBufferFlushed(userrec* user) { }\r\rlong InspIRCd::PriorityAfter(const std::string &modulename)\r{\r      for (unsigned int j = 0; j < this->Config->module_names.size(); j++)\r   {\r              if (this->Config->module_names[j] == modulename)\r               {\r                      return ((j << 8) | PRIORITY_AFTER);\r            }\r      }\r      return PRIORITY_DONTCARE;\r}\r\rlong InspIRCd::PriorityBefore(const std::string &modulename)\r{\r    for (unsigned int j = 0; j < this->Config->module_names.size(); j++)\r   {\r              if (this->Config->module_names[j] == modulename)\r               {\r                      return ((j << 8) | PRIORITY_BEFORE);\r           }\r      }\r      return PRIORITY_DONTCARE;\r}\r\rbool InspIRCd::PublishFeature(const std::string &FeatureName, Module* Mod)\r{\r      if (Features.find(FeatureName) == Features.end())\r      {\r              Features[FeatureName] = Mod;\r           return true;\r   }\r      return false;\r}\r\rbool InspIRCd::UnpublishFeature(const std::string &FeatureName)\r{\r     featurelist::iterator iter = Features.find(FeatureName);\r       \r       if (iter == Features.end())\r            return false;\r\r Features.erase(iter);\r  return true;\r}\r\rModule* InspIRCd::FindFeature(const std::string &FeatureName)\r{\r        featurelist::iterator iter = Features.find(FeatureName);\r\r      if (iter == Features.end())\r            return NULL;\r\r  return iter->second;\r}\r\rbool InspIRCd::PublishInterface(const std::string &InterfaceName, Module* Mod)\r{\r       interfacelist::iterator iter = Interfaces.find(InterfaceName);\r\r        if (iter == Interfaces.end())\r  {\r              modulelist ml;\r         ml.push_back(Mod);\r             Interfaces[InterfaceName] = std::make_pair(0, ml);\r             return true;\r   }\r      else\r   {\r              iter->second.second.push_back(Mod);\r            return true;\r   }\r      return false;\r}\r\rbool InspIRCd::UnpublishInterface(const std::string &InterfaceName, Module* Mod)\r{\r    interfacelist::iterator iter = Interfaces.find(InterfaceName);\r\r        if (iter == Interfaces.end())\r          return false;\r\r for (modulelist::iterator x = iter->second.second.begin(); x != iter->second.second.end(); x++)\r        {\r              if (*x == Mod)\r         {\r                      iter->second.second.erase(x);\r                  if (iter->second.second.empty())\r                               Interfaces.erase(InterfaceName);\r                       return true;\r           }\r      }\r      return false;\r}\r\rmodulelist* InspIRCd::FindInterface(const std::string &InterfaceName)\r{\r       interfacelist::iterator iter = Interfaces.find(InterfaceName);\r if (iter == Interfaces.end())\r          return NULL;\r   else\r           return &(iter->second.second);\r}\r\rvoid InspIRCd::UseInterface(const std::string &InterfaceName)\r{\r      interfacelist::iterator iter = Interfaces.find(InterfaceName);\r if (iter != Interfaces.end())\r          iter->second.first++;\r\r}\r\rvoid InspIRCd::DoneWithInterface(const std::string &InterfaceName)\r{\r interfacelist::iterator iter = Interfaces.find(InterfaceName);\r if (iter != Interfaces.end())\r          iter->second.first--;\r}\r\rstd::pair<int,std::string> InspIRCd::GetInterfaceInstanceCount(Module* m)\r{\r   for (interfacelist::iterator iter = Interfaces.begin(); iter != Interfaces.end(); iter++)\r      {\r              for (modulelist::iterator x = iter->second.second.begin(); x != iter->second.second.end(); x++)\r                {\r                      if (*x == m)\r                   {\r                              return std::make_pair(iter->second.first, iter->first);\r                        }\r              }\r      }\r      return std::make_pair(0, "");\r}\r\rconst std::string& InspIRCd::GetModuleName(Module* m)\r{\r       static std::string nothing; /* Prevent compiler warning */\r\r    if (!this->GetModuleCount())\r           return nothing;\r\r       for (int i = 0; i <= this->GetModuleCount(); i++)\r      {\r              if (this->modules[i] == m)\r             {\r                      return this->Config->module_names[i];\r          }\r      }\r      return nothing; /* As above */\r}\r\rvoid InspIRCd::RehashServer()\r{\r      this->WriteOpers("*** Rehashing config file");\r this->RehashUsersAndChans();\r   this->Config->Read(false,NULL);\r        this->ResetMaxBans();\r  this->Res->Rehash();\r}\r\r/* This is ugly, yes, but hash_map's arent designed to be\r * addressed in this manner, and this is a bit of a kludge.\r * Luckily its a specialist function and rarely used by\r * many modules (in fact, it was specially created to make\r * m_safelist possible, initially).\r */\r\rchanrec* InspIRCd::GetChannelIndex(long index)\r{\r     int target = 0;\r        for (chan_hash::iterator n = this->chanlist->begin(); n != this->chanlist->end(); n++, target++)\r       {\r              if (index == target)\r                   return n->second;\r      }\r      return NULL;\r}\r\rbool InspIRCd::MatchText(const std::string &sliteral, const std::string &spattern)\r{\r   return match(sliteral.c_str(),spattern.c_str());\r}\r\rCmdResult InspIRCd::CallCommandHandler(const std::string &commandname, const char** parameters, int pcnt, userrec* user)\r{\r return this->Parser->CallHandler(commandname,parameters,pcnt,user);\r}\r\rbool InspIRCd::IsValidModuleCommand(const std::string &commandname, int pcnt, userrec* user)\r{\r  return this->Parser->IsValidCommand(commandname, pcnt, user);\r}\r\rvoid InspIRCd::AddCommand(command_t *f)\r{\r     if (!this->Parser->CreateCommand(f))\r   {\r              ModuleException err("Command "+std::string(f->command)+" already exists.");\r            throw (err);\r   }\r}\r\rvoid InspIRCd::SendMode(const char** parameters, int pcnt, userrec *user)\r{\r       this->Modes->Process(parameters,pcnt,user,true);\r}\r\rvoid InspIRCd::DumpText(userrec* User, const std::string &LinePrefix, stringstream &TextStream)\r{\r  std::string CompleteLine = LinePrefix;\r std::string Word;\r      while (TextStream >> Word)\r     {\r              if (CompleteLine.length() + Word.length() + 3 > 500)\r           {\r                      User->WriteServ(CompleteLine);\r                 CompleteLine = LinePrefix;\r             }\r              CompleteLine = CompleteLine + Word + " ";\r      }\r      User->WriteServ(CompleteLine);\r}\r\ruserrec* InspIRCd::FindDescriptor(int socket)\r{\r      return reinterpret_cast<userrec*>(this->SE->GetRef(socket));\r}\r\rbool InspIRCd::AddMode(ModeHandler* mh, const unsigned char mode)\r{\r    return this->Modes->AddMode(mh,mode);\r}\r\rbool InspIRCd::AddModeWatcher(ModeWatcher* mw)\r{\r      return this->Modes->AddModeWatcher(mw);\r}\r\rbool InspIRCd::DelModeWatcher(ModeWatcher* mw)\r{\r    return this->Modes->DelModeWatcher(mw);\r}\r\rbool InspIRCd::AddResolver(Resolver* r, bool cached)\r{\r      if (!cached)\r           return this->Res->AddResolverClass(r);\r else\r   {\r              r->TriggerCachedResult();\r              delete r;\r              return true;\r   }\r}\r\rvoid InspIRCd::AddGLine(long duration, const std::string &source, const std::string &reason, const std::string &hostmask)\r{\r       XLines->add_gline(duration, source.c_str(), reason.c_str(), hostmask.c_str());\r XLines->apply_lines(APPLY_GLINES);\r}\r\rvoid InspIRCd::AddQLine(long duration, const std::string &source, const std::string &reason, const std::string &nickname)\r{\r      XLines->add_qline(duration, source.c_str(), reason.c_str(), nickname.c_str());\r XLines->apply_lines(APPLY_QLINES);\r}\r\rvoid InspIRCd::AddZLine(long duration, const std::string &source, const std::string &reason, const std::string &ipaddr)\r{\r        XLines->add_zline(duration, source.c_str(), reason.c_str(), ipaddr.c_str());\r   XLines->apply_lines(APPLY_ZLINES);\r}\r\rvoid InspIRCd::AddKLine(long duration, const std::string &source, const std::string &reason, const std::string &hostmask)\r{\r      XLines->add_kline(duration, source.c_str(), reason.c_str(), hostmask.c_str());\r XLines->apply_lines(APPLY_KLINES);\r}\r\rvoid InspIRCd::AddELine(long duration, const std::string &source, const std::string &reason, const std::string &hostmask)\r{\r      XLines->add_eline(duration, source.c_str(), reason.c_str(), hostmask.c_str());\r}\r\rbool InspIRCd::DelGLine(const std::string &hostmask)\r{\r       return XLines->del_gline(hostmask.c_str());\r}\r\rbool InspIRCd::DelQLine(const std::string &nickname)\r{\r  return XLines->del_qline(nickname.c_str());\r}\r\rbool InspIRCd::DelZLine(const std::string &ipaddr)\r{\r    return XLines->del_zline(ipaddr.c_str());\r}\r\rbool InspIRCd::DelKLine(const std::string &hostmask)\r{\r    return XLines->del_kline(hostmask.c_str());\r}\r\rbool InspIRCd::DelELine(const std::string &hostmask)\r{\r  return XLines->del_eline(hostmask.c_str());\r}\r\r/*\r * XXX why on *earth* is this in modules.cpp...? I think\r * perhaps we need a server.cpp for InspIRCd:: stuff where possible. -- w00t\r */\rbool InspIRCd::IsValidMask(const std::string &mask)\r{\r      char* dest = (char*)mask.c_str();\r      if (strchr(dest,'!')==0)\r               return false;\r  if (strchr(dest,'@')==0)\r               return false;\r  for (char* i = dest; *i; i++)\r          if (*i < 32)\r                   return false;\r  for (char* i = dest; *i; i++)\r          if (*i > 126)\r                  return false;\r  unsigned int c = 0;\r    for (char* i = dest; *i; i++)\r          if (*i == '!')\r                 c++;\r   if (c>1)\r               return false;\r  c = 0;\r for (char* i = dest; *i; i++)\r          if (*i == '@')\r                 c++;\r   if (c>1)\r               return false;\r\r return true;\r}\r\rModule* InspIRCd::FindModule(const std::string &name)\r{\r        for (int i = 0; i <= this->GetModuleCount(); i++)\r      {\r              if (this->Config->module_names[i] == name)\r             {\r                      return this->modules[i];\r               }\r      }\r      return NULL;\r}\r\rConfigReader::ConfigReader(InspIRCd* Instance) : ServerInstance(Instance)\r{\r    /* Is there any reason to load the entire config file again here?\r       * it's needed if they specify another config file, but using the\r       * default one we can just use the global config data - pre-parsed!\r     */\r    this->errorlog = new std::ostringstream(std::stringstream::in | std::stringstream::out);\r       \r       this->data = &ServerInstance->Config->config_data;\r     this->privatehash = false;\r}\r\r\rConfigReader::~ConfigReader()\r{\r if (this->errorlog)\r            DELETE(this->errorlog);\r        if(this->privatehash)\r          DELETE(this->data);\r}\r\r\rConfigReader::ConfigReader(InspIRCd* Instance, const std::string &filename) : ServerInstance(Instance)\r{\r       ServerInstance->Config->ClearStack();\r\r this->data = new ConfigDataHash;\r       this->privatehash = true;\r      this->errorlog = new std::ostringstream(std::stringstream::in | std::stringstream::out);\r       this->readerror = ServerInstance->Config->LoadConf(*this->data, filename, *this->errorlog);\r    if (!this->readerror)\r          this->error = CONF_FILE_NOT_FOUND;\r}\r\r\rstd::string ConfigReader::ReadValue(const std::string &tag, const std::string &name, const std::string &default_value, int index, bool allow_linefeeds)\r{\r       /* Don't need to strlcpy() tag and name anymore, ReadConf() takes const char* */ \r      std::string result;\r    \r       if (!ServerInstance->Config->ConfValue(*this->data, tag, name, default_value, index, result, allow_linefeeds))\r {\r              this->error = CONF_VALUE_NOT_FOUND;\r    }\r      return result;\r}\r\rstd::string ConfigReader::ReadValue(const std::string &tag, const std::string &name, int index, bool allow_linefeeds)\r{\r      return ReadValue(tag, name, "", index, allow_linefeeds);\r}\r\rbool ConfigReader::ReadFlag(const std::string &tag, const std::string &name, const std::string &default_value, int index)\r{\r        return ServerInstance->Config->ConfValueBool(*this->data, tag, name, default_value, index);\r}\r\rbool ConfigReader::ReadFlag(const std::string &tag, const std::string &name, int index)\r{\r       return ReadFlag(tag, name, "", index);\r}\r\r\rlong ConfigReader::ReadInteger(const std::string &tag, const std::string &name, const std::string &default_value, int index, bool needs_unsigned)\r{\r int result;\r    \r       if(!ServerInstance->Config->ConfValueInteger(*this->data, tag, name, default_value, index, result))\r    {\r              this->error = CONF_VALUE_NOT_FOUND;\r            return 0;\r      }\r      \r       if ((needs_unsigned) && (result < 0))\r  {\r              this->error = CONF_NOT_UNSIGNED;\r               return 0;\r      }\r      \r       return result;\r}\r\rlong ConfigReader::ReadInteger(const std::string &tag, const std::string &name, int index, bool needs_unsigned)\r{\r    return ReadInteger(tag, name, "", index, needs_unsigned);\r}\r\rlong ConfigReader::GetError()\r{\r   long olderr = this->error;\r     this->error = 0;\r       return olderr;\r}\r\rvoid ConfigReader::DumpErrors(bool bail, userrec* user)\r{\r    ServerInstance->Config->ReportConfigError(this->errorlog->str(), bail, user);\r}\r\r\rint ConfigReader::Enumerate(const std::string &tag)\r{\r        return ServerInstance->Config->ConfValueEnum(*this->data, tag);\r}\r\rint ConfigReader::EnumerateValues(const std::string &tag, int index)\r{\r      return ServerInstance->Config->ConfVarEnum(*this->data, tag, index);\r}\r\rbool ConfigReader::Verify()\r{\r  return this->readerror;\r}\r\r\rFileReader::FileReader(InspIRCd* Instance, const std::string &filename) : ServerInstance(Instance)\r{\r       LoadFile(filename);\r}\r\rFileReader::FileReader(InspIRCd* Instance) : ServerInstance(Instance)\r{\r}\r\rstd::string FileReader::Contents()\r{\r std::string x;\r for (file_cache::iterator a = this->fc.begin(); a != this->fc.end(); a++)\r      {\r              x.append(*a);\r          x.append("\r\n");\r      }\r      return x;\r}\r\runsigned long FileReader::ContentSize()\r{\r return this->contentsize;\r}\r\rvoid FileReader::CalcSize()\r{\r     unsigned long n = 0;\r   for (file_cache::iterator a = this->fc.begin(); a != this->fc.end(); a++)\r              n += (a->length() + 2);\r        this->contentsize = n;\r}\r\rvoid FileReader::LoadFile(const std::string &filename)\r{\r     file_cache c;\r  c.clear();\r     if (ServerInstance->Config->ReadFile(c,filename.c_str()))\r      {\r              this->fc = c;\r          this->CalcSize();\r      }\r}\r\r\rFileReader::~FileReader()\r{\r}\r\rbool FileReader::Exists()\r{\r       return (!(fc.size() == 0));\r}\r\rstd::string FileReader::GetLine(int x)\r{\r        if ((x<0) || ((unsigned)x>fc.size()))\r          return "";\r     return fc[x];\r}\r\rint FileReader::FileSize()\r{\r  return fc.size();\r}\r\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "configreader.h"
+#include "users.h"
+#include "modules.h"
+#include "wildcard.h"
+#include "mode.h"
+#include "xline.h"
+#include "socket.h"
+#include "socketengine.h"
+#include "command_parse.h"
+#include "dns.h"
+
+// version is a simple class for holding a modules version number
+Version::Version(int major, int minor, int revision, int build, int flags, int api_ver)
+: Major(major), Minor(minor), Revision(revision), Build(build), Flags(flags), API(api_ver)
+{
+}
+
+Request::Request(char* anydata, Module* src, Module* dst)
+: data(anydata), source(src), dest(dst)
+{
+       /* Ensure that because this module doesnt support ID strings, it doesnt break modules that do
+        * by passing them uninitialized pointers (could happen)
+        */
+       id = '\0';
+}
+
+Request::Request(Module* src, Module* dst, const char* idstr)
+: id(idstr), source(src), dest(dst)
+{
+}
+
+char* Request::GetData()
+{
+       return this->data;
+}
+
+const char* Request::GetId()
+{
+       return this->id;
+}
+
+Module* Request::GetSource()
+{
+       return this->source;
+}
+
+Module* Request::GetDest()
+{
+       return this->dest;
+}
+
+char* Request::Send()
+{
+       if (this->dest)
+       {
+               return dest->OnRequest(this);
+       }
+       else
+       {
+               return NULL;
+       }
+}
+
+Event::Event(char* anydata, Module* src, const std::string &eventid) : data(anydata), source(src), id(eventid) { }
+
+char* Event::GetData()
+{
+       return (char*)this->data;
+}
+
+Module* Event::GetSource()
+{
+       return this->source;
+}
+
+char* Event::Send(InspIRCd* ServerInstance)
+{
+       FOREACH_MOD(I_OnEvent,OnEvent(this));
+       return NULL;
+}
+
+std::string Event::GetEventID()
+{
+       return this->id;
+}
+
+
+// These declarations define the behavours of the base class Module (which does nothing at all)
+
+               Module::Module(InspIRCd* Me) : ServerInstance(Me) { }
+               Module::~Module() { }
+void           Module::OnUserConnect(userrec* user) { }
+void           Module::OnUserQuit(userrec* user, const std::string& message, const std::string &oper_message) { }
+void           Module::OnUserDisconnect(userrec* user) { }
+void           Module::OnUserJoin(userrec* user, chanrec* channel, bool &silent) { }
+void           Module::OnPostJoin(userrec* user, chanrec* channel) { }
+void           Module::OnUserPart(userrec* user, chanrec* channel, const std::string &partmessage, bool &silent) { }
+void           Module::OnRehash(userrec* user, const std::string &parameter) { }
+void           Module::OnServerRaw(std::string &raw, bool inbound, userrec* user) { }
+int            Module::OnUserPreJoin(userrec* user, chanrec* chan, const char* cname, std::string &privs) { return 0; }
+void           Module::OnMode(userrec* user, void* dest, int target_type, const std::string &text) { }
+Version                Module::GetVersion() { return Version(1,0,0,0,VF_VENDOR,-1); }
+void           Module::OnOper(userrec* user, const std::string &opertype) { }
+void           Module::OnPostOper(userrec* user, const std::string &opertype) { }
+void           Module::OnInfo(userrec* user) { }
+void           Module::OnWhois(userrec* source, userrec* dest) { }
+int            Module::OnUserPreInvite(userrec* source,userrec* dest,chanrec* channel) { return 0; }
+int            Module::OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text,char status, CUList &exempt_list) { return 0; }
+int            Module::OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text,char status, CUList &exempt_list) { return 0; }
+int            Module::OnUserPreNick(userrec* user, const std::string &newnick) { return 0; }
+void           Module::OnUserPostNick(userrec* user, const std::string &oldnick) { }
+int            Module::OnAccessCheck(userrec* source,userrec* dest,chanrec* channel,int access_type) { return ACR_DEFAULT; }
+void           Module::On005Numeric(std::string &output) { }
+int            Module::OnKill(userrec* source, userrec* dest, const std::string &reason) { return 0; }
+void           Module::OnLoadModule(Module* mod,const std::string &name) { }
+void           Module::OnUnloadModule(Module* mod,const std::string &name) { }
+void           Module::OnBackgroundTimer(time_t curtime) { }
+int            Module::OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line) { return 0; }
+void           Module::OnPostCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, CmdResult result, const std::string &original_line) { }
+bool           Module::OnCheckReady(userrec* user) { return true; }
+int            Module::OnUserRegister(userrec* user) { return 0; }
+int            Module::OnUserPreKick(userrec* source, userrec* user, chanrec* chan, const std::string &reason) { return 0; }
+void           Module::OnUserKick(userrec* source, userrec* user, chanrec* chan, const std::string &reason, bool &silent) { }
+int            Module::OnCheckInvite(userrec* user, chanrec* chan) { return 0; }
+int            Module::OnCheckKey(userrec* user, chanrec* chan, const std::string &keygiven) { return 0; }
+int            Module::OnCheckLimit(userrec* user, chanrec* chan) { return 0; }
+int            Module::OnCheckBan(userrec* user, chanrec* chan) { return 0; }
+int            Module::OnStats(char symbol, userrec* user, string_list &results) { return 0; }
+int            Module::OnChangeLocalUserHost(userrec* user, const std::string &newhost) { return 0; }
+int            Module::OnChangeLocalUserGECOS(userrec* user, const std::string &newhost) { return 0; }
+int            Module::OnLocalTopicChange(userrec* user, chanrec* chan, const std::string &topic) { return 0; }
+void           Module::OnEvent(Event* event) { return; }
+char*          Module::OnRequest(Request* request) { return NULL; }
+int            Module::OnOperCompare(const std::string &password, const std::string &input, int tagnumber) { return 0; }
+void           Module::OnGlobalOper(userrec* user) { }
+void           Module::OnPostConnect(userrec* user) { }
+int            Module::OnAddBan(userrec* source, chanrec* channel,const std::string &banmask) { return 0; }
+int            Module::OnDelBan(userrec* source, chanrec* channel,const std::string &banmask) { return 0; }
+void           Module::OnRawSocketAccept(int fd, const std::string &ip, int localport) { }
+int            Module::OnRawSocketWrite(int fd, const char* buffer, int count) { return 0; }
+void           Module::OnRawSocketClose(int fd) { }
+void           Module::OnRawSocketConnect(int fd) { }
+int            Module::OnRawSocketRead(int fd, char* buffer, unsigned int count, int &readresult) { return 0; }
+void           Module::OnUserMessage(userrec* user, void* dest, int target_type, const std::string &text, char status, const CUList &exempt_list) { }
+void           Module::OnUserNotice(userrec* user, void* dest, int target_type, const std::string &text, char status, const CUList &exempt_list) { }
+void           Module::OnRemoteKill(userrec* source, userrec* dest, const std::string &reason, const std::string &operreason) { }
+void           Module::OnUserInvite(userrec* source,userrec* dest,chanrec* channel) { }
+void           Module::OnPostLocalTopicChange(userrec* user, chanrec* chan, const std::string &topic) { }
+void           Module::OnGetServerDescription(const std::string &servername,std::string &description) { }
+void           Module::OnSyncUser(userrec* user, Module* proto, void* opaque) { }
+void           Module::OnSyncChannel(chanrec* chan, Module* proto, void* opaque) { }
+void           Module::ProtoSendMode(void* opaque, int target_type, void* target, const std::string &modeline) { }
+void           Module::OnSyncChannelMetaData(chanrec* chan, Module* proto,void* opaque, const std::string &extname, bool displayable) { }
+void           Module::OnSyncUserMetaData(userrec* user, Module* proto,void* opaque, const std::string &extname, bool displayable) { }
+void           Module::OnSyncOtherMetaData(Module* proto, void* opaque, bool displayable) { }
+void           Module::OnDecodeMetaData(int target_type, void* target, const std::string &extname, const std::string &extdata) { }
+void           Module::ProtoSendMetaData(void* opaque, int target_type, void* target, const std::string &extname, const std::string &extdata) { }
+void           Module::OnWallops(userrec* user, const std::string &text) { }
+void           Module::OnChangeHost(userrec* user, const std::string &newhost) { }
+void           Module::OnChangeName(userrec* user, const std::string &gecos) { }
+void           Module::OnAddGLine(long duration, userrec* source, const std::string &reason, const std::string &hostmask) { }
+void           Module::OnAddZLine(long duration, userrec* source, const std::string &reason, const std::string &ipmask) { }
+void           Module::OnAddKLine(long duration, userrec* source, const std::string &reason, const std::string &hostmask) { }
+void           Module::OnAddQLine(long duration, userrec* source, const std::string &reason, const std::string &nickmask) { }
+void           Module::OnAddELine(long duration, userrec* source, const std::string &reason, const std::string &hostmask) { }
+void           Module::OnDelGLine(userrec* source, const std::string &hostmask) { }
+void           Module::OnDelZLine(userrec* source, const std::string &ipmask) { }
+void           Module::OnDelKLine(userrec* source, const std::string &hostmask) { }
+void           Module::OnDelQLine(userrec* source, const std::string &nickmask) { }
+void           Module::OnDelELine(userrec* source, const std::string &hostmask) { }
+void           Module::OnCleanup(int target_type, void* item) { }
+void           Module::Implements(char* Implements) { for (int j = 0; j < 255; j++) Implements[j] = 0; }
+void           Module::OnChannelDelete(chanrec* chan) { }
+Priority       Module::Prioritize() { return PRIORITY_DONTCARE; }
+void           Module::OnSetAway(userrec* user) { }
+void           Module::OnCancelAway(userrec* user) { }
+int            Module::OnUserList(userrec* user, chanrec* Ptr, CUList* &userlist) { return 0; }
+int            Module::OnWhoisLine(userrec* user, userrec* dest, int &numeric, std::string &text) { return 0; }
+void           Module::OnBuildExemptList(MessageType message_type, chanrec* chan, userrec* sender, char status, CUList &exempt_list) { }
+void           Module::OnGarbageCollect() { }
+void           Module::OnBufferFlushed(userrec* user) { }
+
+long InspIRCd::PriorityAfter(const std::string &modulename)
+{
+       for (unsigned int j = 0; j < this->Config->module_names.size(); j++)
+       {
+               if (this->Config->module_names[j] == modulename)
+               {
+                       return ((j << 8) | PRIORITY_AFTER);
+               }
+       }
+       return PRIORITY_DONTCARE;
+}
+
+long InspIRCd::PriorityBefore(const std::string &modulename)
+{
+       for (unsigned int j = 0; j < this->Config->module_names.size(); j++)
+       {
+               if (this->Config->module_names[j] == modulename)
+               {
+                       return ((j << 8) | PRIORITY_BEFORE);
+               }
+       }
+       return PRIORITY_DONTCARE;
+}
+
+bool InspIRCd::PublishFeature(const std::string &FeatureName, Module* Mod)
+{
+       if (Features.find(FeatureName) == Features.end())
+       {
+               Features[FeatureName] = Mod;
+               return true;
+       }
+       return false;
+}
+
+bool InspIRCd::UnpublishFeature(const std::string &FeatureName)
+{
+       featurelist::iterator iter = Features.find(FeatureName);
+       
+       if (iter == Features.end())
+               return false;
+
+       Features.erase(iter);
+       return true;
+}
+
+Module* InspIRCd::FindFeature(const std::string &FeatureName)
+{
+       featurelist::iterator iter = Features.find(FeatureName);
+
+       if (iter == Features.end())
+               return NULL;
+
+       return iter->second;
+}
+
+bool InspIRCd::PublishInterface(const std::string &InterfaceName, Module* Mod)
+{
+       interfacelist::iterator iter = Interfaces.find(InterfaceName);
+
+       if (iter == Interfaces.end())
+       {
+               modulelist ml;
+               ml.push_back(Mod);
+               Interfaces[InterfaceName] = std::make_pair(0, ml);
+               return true;
+       }
+       else
+       {
+               iter->second.second.push_back(Mod);
+               return true;
+       }
+       return false;
+}
+
+bool InspIRCd::UnpublishInterface(const std::string &InterfaceName, Module* Mod)
+{
+       interfacelist::iterator iter = Interfaces.find(InterfaceName);
+
+       if (iter == Interfaces.end())
+               return false;
+
+       for (modulelist::iterator x = iter->second.second.begin(); x != iter->second.second.end(); x++)
+       {
+               if (*x == Mod)
+               {
+                       iter->second.second.erase(x);
+                       if (iter->second.second.empty())
+                               Interfaces.erase(InterfaceName);
+                       return true;
+               }
+       }
+       return false;
+}
+
+modulelist* InspIRCd::FindInterface(const std::string &InterfaceName)
+{
+       interfacelist::iterator iter = Interfaces.find(InterfaceName);
+       if (iter == Interfaces.end())
+               return NULL;
+       else
+               return &(iter->second.second);
+}
+
+void InspIRCd::UseInterface(const std::string &InterfaceName)
+{
+       interfacelist::iterator iter = Interfaces.find(InterfaceName);
+       if (iter != Interfaces.end())
+               iter->second.first++;
+
+}
+
+void InspIRCd::DoneWithInterface(const std::string &InterfaceName)
+{
+       interfacelist::iterator iter = Interfaces.find(InterfaceName);
+       if (iter != Interfaces.end())
+               iter->second.first--;
+}
+
+std::pair<int,std::string> InspIRCd::GetInterfaceInstanceCount(Module* m)
+{
+       for (interfacelist::iterator iter = Interfaces.begin(); iter != Interfaces.end(); iter++)
+       {
+               for (modulelist::iterator x = iter->second.second.begin(); x != iter->second.second.end(); x++)
+               {
+                       if (*x == m)
+                       {
+                               return std::make_pair(iter->second.first, iter->first);
+                       }
+               }
+       }
+       return std::make_pair(0, "");
+}
+
+const std::string& InspIRCd::GetModuleName(Module* m)
+{
+       static std::string nothing; /* Prevent compiler warning */
+
+       if (!this->GetModuleCount())
+               return nothing;
+
+       for (int i = 0; i <= this->GetModuleCount(); i++)
+       {
+               if (this->modules[i] == m)
+               {
+                       return this->Config->module_names[i];
+               }
+       }
+       return nothing; /* As above */
+}
+
+void InspIRCd::RehashServer()
+{
+       this->WriteOpers("*** Rehashing config file");
+       this->RehashUsersAndChans();
+       this->Config->Read(false,NULL);
+       this->ResetMaxBans();
+       this->Res->Rehash();
+}
+
+/* This is ugly, yes, but hash_map's arent designed to be
+ * addressed in this manner, and this is a bit of a kludge.
+ * Luckily its a specialist function and rarely used by
+ * many modules (in fact, it was specially created to make
+ * m_safelist possible, initially).
+ */
+
+chanrec* InspIRCd::GetChannelIndex(long index)
+{
+       int target = 0;
+       for (chan_hash::iterator n = this->chanlist->begin(); n != this->chanlist->end(); n++, target++)
+       {
+               if (index == target)
+                       return n->second;
+       }
+       return NULL;
+}
+
+bool InspIRCd::MatchText(const std::string &sliteral, const std::string &spattern)
+{
+       return match(sliteral.c_str(),spattern.c_str());
+}
+
+CmdResult InspIRCd::CallCommandHandler(const std::string &commandname, const char** parameters, int pcnt, userrec* user)
+{
+       return this->Parser->CallHandler(commandname,parameters,pcnt,user);
+}
+
+bool InspIRCd::IsValidModuleCommand(const std::string &commandname, int pcnt, userrec* user)
+{
+       return this->Parser->IsValidCommand(commandname, pcnt, user);
+}
+
+void InspIRCd::AddCommand(command_t *f)
+{
+       if (!this->Parser->CreateCommand(f))
+       {
+               ModuleException err("Command "+std::string(f->command)+" already exists.");
+               throw (err);
+       }
+}
+
+void InspIRCd::SendMode(const char** parameters, int pcnt, userrec *user)
+{
+       this->Modes->Process(parameters,pcnt,user,true);
+}
+
+void InspIRCd::DumpText(userrec* User, const std::string &LinePrefix, stringstream &TextStream)
+{
+       std::string CompleteLine = LinePrefix;
+       std::string Word;
+       while (TextStream >> Word)
+       {
+               if (CompleteLine.length() + Word.length() + 3 > 500)
+               {
+                       User->WriteServ(CompleteLine);
+                       CompleteLine = LinePrefix;
+               }
+               CompleteLine = CompleteLine + Word + " ";
+       }
+       User->WriteServ(CompleteLine);
+}
+
+userrec* InspIRCd::FindDescriptor(int socket)
+{
+       return reinterpret_cast<userrec*>(this->SE->GetRef(socket));
+}
+
+bool InspIRCd::AddMode(ModeHandler* mh, const unsigned char mode)
+{
+       return this->Modes->AddMode(mh,mode);
+}
+
+bool InspIRCd::AddModeWatcher(ModeWatcher* mw)
+{
+       return this->Modes->AddModeWatcher(mw);
+}
+
+bool InspIRCd::DelModeWatcher(ModeWatcher* mw)
+{
+       return this->Modes->DelModeWatcher(mw);
+}
+
+bool InspIRCd::AddResolver(Resolver* r, bool cached)
+{
+       if (!cached)
+               return this->Res->AddResolverClass(r);
+       else
+       {
+               r->TriggerCachedResult();
+               delete r;
+               return true;
+       }
+}
+
+void InspIRCd::AddGLine(long duration, const std::string &source, const std::string &reason, const std::string &hostmask)
+{
+       XLines->add_gline(duration, source.c_str(), reason.c_str(), hostmask.c_str());
+       XLines->apply_lines(APPLY_GLINES);
+}
+
+void InspIRCd::AddQLine(long duration, const std::string &source, const std::string &reason, const std::string &nickname)
+{
+       XLines->add_qline(duration, source.c_str(), reason.c_str(), nickname.c_str());
+       XLines->apply_lines(APPLY_QLINES);
+}
+
+void InspIRCd::AddZLine(long duration, const std::string &source, const std::string &reason, const std::string &ipaddr)
+{
+       XLines->add_zline(duration, source.c_str(), reason.c_str(), ipaddr.c_str());
+       XLines->apply_lines(APPLY_ZLINES);
+}
+
+void InspIRCd::AddKLine(long duration, const std::string &source, const std::string &reason, const std::string &hostmask)
+{
+       XLines->add_kline(duration, source.c_str(), reason.c_str(), hostmask.c_str());
+       XLines->apply_lines(APPLY_KLINES);
+}
+
+void InspIRCd::AddELine(long duration, const std::string &source, const std::string &reason, const std::string &hostmask)
+{
+       XLines->add_eline(duration, source.c_str(), reason.c_str(), hostmask.c_str());
+}
+
+bool InspIRCd::DelGLine(const std::string &hostmask)
+{
+       return XLines->del_gline(hostmask.c_str());
+}
+
+bool InspIRCd::DelQLine(const std::string &nickname)
+{
+       return XLines->del_qline(nickname.c_str());
+}
+
+bool InspIRCd::DelZLine(const std::string &ipaddr)
+{
+       return XLines->del_zline(ipaddr.c_str());
+}
+
+bool InspIRCd::DelKLine(const std::string &hostmask)
+{
+       return XLines->del_kline(hostmask.c_str());
+}
+
+bool InspIRCd::DelELine(const std::string &hostmask)
+{
+       return XLines->del_eline(hostmask.c_str());
+}
+
+/*
+ * XXX why on *earth* is this in modules.cpp...? I think
+ * perhaps we need a server.cpp for InspIRCd:: stuff where possible. -- w00t
+ */
+bool InspIRCd::IsValidMask(const std::string &mask)
+{
+       char* dest = (char*)mask.c_str();
+       if (strchr(dest,'!')==0)
+               return false;
+       if (strchr(dest,'@')==0)
+               return false;
+       for (char* i = dest; *i; i++)
+               if (*i < 32)
+                       return false;
+       for (char* i = dest; *i; i++)
+               if (*i > 126)
+                       return false;
+       unsigned int c = 0;
+       for (char* i = dest; *i; i++)
+               if (*i == '!')
+                       c++;
+       if (c>1)
+               return false;
+       c = 0;
+       for (char* i = dest; *i; i++)
+               if (*i == '@')
+                       c++;
+       if (c>1)
+               return false;
+
+       return true;
+}
+
+Module* InspIRCd::FindModule(const std::string &name)
+{
+       for (int i = 0; i <= this->GetModuleCount(); i++)
+       {
+               if (this->Config->module_names[i] == name)
+               {
+                       return this->modules[i];
+               }
+       }
+       return NULL;
+}
+
+ConfigReader::ConfigReader(InspIRCd* Instance) : ServerInstance(Instance)
+{
+       /* Is there any reason to load the entire config file again here?
+        * it's needed if they specify another config file, but using the
+        * default one we can just use the global config data - pre-parsed!
+        */
+       this->errorlog = new std::ostringstream(std::stringstream::in | std::stringstream::out);
+       
+       this->data = &ServerInstance->Config->config_data;
+       this->privatehash = false;
+}
+
+
+ConfigReader::~ConfigReader()
+{
+       if (this->errorlog)
+               DELETE(this->errorlog);
+       if(this->privatehash)
+               DELETE(this->data);
+}
+
+
+ConfigReader::ConfigReader(InspIRCd* Instance, const std::string &filename) : ServerInstance(Instance)
+{
+       ServerInstance->Config->ClearStack();
+
+       this->data = new ConfigDataHash;
+       this->privatehash = true;
+       this->errorlog = new std::ostringstream(std::stringstream::in | std::stringstream::out);
+       this->readerror = ServerInstance->Config->LoadConf(*this->data, filename, *this->errorlog);
+       if (!this->readerror)
+               this->error = CONF_FILE_NOT_FOUND;
+}
+
+
+std::string ConfigReader::ReadValue(const std::string &tag, const std::string &name, const std::string &default_value, int index, bool allow_linefeeds)
+{
+       /* Don't need to strlcpy() tag and name anymore, ReadConf() takes const char* */ 
+       std::string result;
+       
+       if (!ServerInstance->Config->ConfValue(*this->data, tag, name, default_value, index, result, allow_linefeeds))
+       {
+               this->error = CONF_VALUE_NOT_FOUND;
+       }
+       return result;
+}
+
+std::string ConfigReader::ReadValue(const std::string &tag, const std::string &name, int index, bool allow_linefeeds)
+{
+       return ReadValue(tag, name, "", index, allow_linefeeds);
+}
+
+bool ConfigReader::ReadFlag(const std::string &tag, const std::string &name, const std::string &default_value, int index)
+{
+       return ServerInstance->Config->ConfValueBool(*this->data, tag, name, default_value, index);
+}
+
+bool ConfigReader::ReadFlag(const std::string &tag, const std::string &name, int index)
+{
+       return ReadFlag(tag, name, "", index);
+}
+
+
+long ConfigReader::ReadInteger(const std::string &tag, const std::string &name, const std::string &default_value, int index, bool needs_unsigned)
+{
+       int result;
+       
+       if(!ServerInstance->Config->ConfValueInteger(*this->data, tag, name, default_value, index, result))
+       {
+               this->error = CONF_VALUE_NOT_FOUND;
+               return 0;
+       }
+       
+       if ((needs_unsigned) && (result < 0))
+       {
+               this->error = CONF_NOT_UNSIGNED;
+               return 0;
+       }
+       
+       return result;
+}
+
+long ConfigReader::ReadInteger(const std::string &tag, const std::string &name, int index, bool needs_unsigned)
+{
+       return ReadInteger(tag, name, "", index, needs_unsigned);
+}
+
+long ConfigReader::GetError()
+{
+       long olderr = this->error;
+       this->error = 0;
+       return olderr;
+}
+
+void ConfigReader::DumpErrors(bool bail, userrec* user)
+{
+       ServerInstance->Config->ReportConfigError(this->errorlog->str(), bail, user);
+}
+
+
+int ConfigReader::Enumerate(const std::string &tag)
+{
+       return ServerInstance->Config->ConfValueEnum(*this->data, tag);
+}
+
+int ConfigReader::EnumerateValues(const std::string &tag, int index)
+{
+       return ServerInstance->Config->ConfVarEnum(*this->data, tag, index);
+}
+
+bool ConfigReader::Verify()
+{
+       return this->readerror;
+}
+
+
+FileReader::FileReader(InspIRCd* Instance, const std::string &filename) : ServerInstance(Instance)
+{
+       LoadFile(filename);
+}
+
+FileReader::FileReader(InspIRCd* Instance) : ServerInstance(Instance)
+{
+}
+
+std::string FileReader::Contents()
+{
+       std::string x;
+       for (file_cache::iterator a = this->fc.begin(); a != this->fc.end(); a++)
+       {
+               x.append(*a);
+               x.append("\r\n");
+       }
+       return x;
+}
+
+unsigned long FileReader::ContentSize()
+{
+       return this->contentsize;
+}
+
+void FileReader::CalcSize()
+{
+       unsigned long n = 0;
+       for (file_cache::iterator a = this->fc.begin(); a != this->fc.end(); a++)
+               n += (a->length() + 2);
+       this->contentsize = n;
+}
+
+void FileReader::LoadFile(const std::string &filename)
+{
+       file_cache c;
+       c.clear();
+       if (ServerInstance->Config->ReadFile(c,filename.c_str()))
+       {
+               this->fc = c;
+               this->CalcSize();
+       }
+}
+
+
+FileReader::~FileReader()
+{
+}
+
+bool FileReader::Exists()
+{
+       return (!(fc.size() == 0));
+}
+
+std::string FileReader::GetLine(int x)
+{
+       if ((x<0) || ((unsigned)x>fc.size()))
+               return "";
+       return fc[x];
+}
+
+int FileReader::FileSize()
+{
+       return fc.size();
+}
+
+
index 4c4beef9d3eb1858011ea15b8036304176864873..7e3096b34e5a7dec055966b54acde53c7e0cf7f0 100644 (file)
@@ -1 +1,7 @@
-This directory stores modules which require external libraries to compile.\rFor example, m_filter_pcre requires the PCRE libraries.\r\rTo compile any of these modules first ensure you have the required dependencies\r(read the online documentation at http://www.inspircd.org/wiki/) and then cp\rthe .cpp file from this directory into the parent directory (src/modules/) and\rre-configure your inspircd with ./configure -update to detect the new module.\r
\ No newline at end of file
+This directory stores modules which require external libraries to compile.
+For example, m_filter_pcre requires the PCRE libraries.
+
+To compile any of these modules first ensure you have the required dependencies
+(read the online documentation at http://www.inspircd.org/wiki/) and then cp
+the .cpp file from this directory into the parent directory (src/modules/) and
+re-configure your inspircd with ./configure -update to detect the new module.
index 0c6c05c8ced460ebc2a2d785c8aeb32f3e5a30c0..6fe79a9814af9f818ba451877e0bf3277e231994 100644 (file)
@@ -1 +1,182 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *        the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include <pcre.h>\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r#include "m_filter.h"\r\r/* $ModDesc: m_filter with regexps */\r/* $CompileFlags: exec("pcre-config --cflags") */\r/* $LinkerFlags: exec("pcre-config --libs") rpath("pcre-config --libs") -lpcre */\r/* $ModDep: m_filter.h */\r\r#ifdef WINDOWS\r#pragma comment(lib, "pcre.lib")\r#endif\r\rclass PCREFilter : public FilterResult\r{\r public:\r    pcre* regexp;\r\r         PCREFilter(pcre* r, const std::string &rea, const std::string &act, long gline_time, const std::string &pat, const std::string &flags)\r                 : FilterResult(pat, rea, act, gline_time, flags), regexp(r)\r    {\r      }\r\r     PCREFilter()\r   {\r      }\r};\r\rclass ModuleFilterPCRE : public FilterBase\r{\r    std::vector<PCREFilter> filters;\r       pcre *re;\r      const char *error;\r     int erroffset;\r PCREFilter fr;\r\r public:\r       ModuleFilterPCRE(InspIRCd* Me)\r : FilterBase(Me, "m_filter_pcre.so")\r   {\r              OnRehash(NULL,"");\r     }\r\r     virtual ~ModuleFilterPCRE()\r    {\r      }\r\r     virtual FilterResult* FilterMatch(userrec* user, const std::string &text, int flags)\r   {\r              for (std::vector<PCREFilter>::iterator index = filters.begin(); index != filters.end(); index++)\r               {\r                      /* Skip ones that dont apply to us */\r\r                 if (!FilterBase::AppliesToMe(user, dynamic_cast<FilterResult*>(&(*index)), flags))\r                             continue;\r\r                     if (pcre_exec(index->regexp, NULL, text.c_str(), text.length(), 0, 0, NULL, 0) > -1)\r                   {\r                              fr = *index;\r                           if (index != filters.begin())\r                          {\r                                      filters.erase(index);\r                                  filters.insert(filters.begin(), fr);\r                           }\r                              return &fr;\r                    }\r              }\r              return NULL;\r   }\r\r     virtual bool DeleteFilter(const std::string &freeform)\r {\r              for (std::vector<PCREFilter>::iterator i = filters.begin(); i != filters.end(); i++)\r           {\r                      if (i->freeform == freeform)\r                   {\r                              pcre_free((*i).regexp);\r                                filters.erase(i);\r                              return true;\r                   }\r              }\r              return false;\r  }\r\r     virtual void SyncFilters(Module* proto, void* opaque)\r  {\r              for (std::vector<PCREFilter>::iterator i = filters.begin(); i != filters.end(); i++)\r           {\r                      this->SendFilter(proto, opaque, &(*i));\r                }\r      }\r\r     virtual std::pair<bool, std::string> AddFilter(const std::string &freeform, const std::string &type, const std::string &reason, long duration, const std::string &flags)\r       {\r              for (std::vector<PCREFilter>::iterator i = filters.begin(); i != filters.end(); i++)\r           {\r                      if (i->freeform == freeform)\r                   {\r                              return std::make_pair(false, "Filter already exists");\r                 }\r              }\r\r             re = pcre_compile(freeform.c_str(),0,&error,&erroffset,NULL);\r\r         if (!re)\r               {\r                      ServerInstance->Log(DEFAULT,"Error in regular expression: %s at offset %d: %s\n", freeform.c_str(), erroffset, error);\r                 ServerInstance->Log(DEFAULT,"Regular expression %s not loaded.", freeform.c_str());\r                    return std::make_pair(false, "Error in regular expression at offset " + ConvToStr(erroffset) + ": "+error);\r            }\r              else\r           {\r                      filters.push_back(PCREFilter(re, reason, type, duration, freeform, flags));\r                    return std::make_pair(true, "");\r               }\r      }\r\r     virtual void OnRehash(userrec* user, const std::string &parameter)\r     {               \r               ConfigReader MyConf(ServerInstance);\r\r          for (int index = 0; index < MyConf.Enumerate("keyword"); index++)\r              {\r                      this->DeleteFilter(MyConf.ReadValue("keyword", "pattern", index));\r\r                    std::string pattern = MyConf.ReadValue("keyword", "pattern", index);\r                   std::string reason = MyConf.ReadValue("keyword", "reason", index);\r                     std::string action = MyConf.ReadValue("keyword", "action", index);\r                     std::string flags = MyConf.ReadValue("keyword", "flags", index);\r                       long gline_time = ServerInstance->Duration(MyConf.ReadValue("keyword", "duration", index));\r                    if (action.empty())\r                            action = "none";\r                       if (flags.empty())\r                             flags = "*";\r\r                  re = pcre_compile(pattern.c_str(),0,&error,&erroffset,NULL);\r\r                  if (!re)\r                       {\r                              ServerInstance->Log(DEFAULT,"Error in regular expression: %s at offset %d: %s\n", pattern.c_str(), erroffset, error);\r                          ServerInstance->Log(DEFAULT,"Regular expression %s not loaded.", pattern.c_str());\r                     }\r                      else\r                   {\r                              filters.push_back(PCREFilter(re, reason, action, gline_time, pattern, flags));\r                         ServerInstance->Log(DEFAULT,"Regular expression %s loaded.", pattern.c_str());\r                 }\r              }\r      }\r\r     virtual int OnStats(char symbol, userrec* user, string_list &results)\r  {\r              if (symbol == 's')\r             {\r                      std::string sn = ServerInstance->Config->ServerName;\r                   for (std::vector<PCREFilter>::iterator i = filters.begin(); i != filters.end(); i++)\r                   {\r                              results.push_back(sn+" 223 "+user->nick+" :REGEXP:"+i->freeform+" "+i->flags+" "+i->action+" "+ConvToStr(i->gline_time)+" :"+i->reason);\r                       }\r              }\r              return 0;\r      }\r};\r\rMODULE_INIT(ModuleFilterPCRE);\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *         the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include <pcre.h>
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+#include "m_filter.h"
+
+/* $ModDesc: m_filter with regexps */
+/* $CompileFlags: exec("pcre-config --cflags") */
+/* $LinkerFlags: exec("pcre-config --libs") rpath("pcre-config --libs") -lpcre */
+/* $ModDep: m_filter.h */
+
+#ifdef WINDOWS
+#pragma comment(lib, "pcre.lib")
+#endif
+
+class PCREFilter : public FilterResult
+{
+ public:
+        pcre* regexp;
+
+        PCREFilter(pcre* r, const std::string &rea, const std::string &act, long gline_time, const std::string &pat, const std::string &flags)
+                : FilterResult(pat, rea, act, gline_time, flags), regexp(r)
+        {
+        }
+
+        PCREFilter()
+        {
+        }
+};
+
+class ModuleFilterPCRE : public FilterBase
+{
+       std::vector<PCREFilter> filters;
+       pcre *re;
+       const char *error;
+       int erroffset;
+       PCREFilter fr;
+
+ public:
+       ModuleFilterPCRE(InspIRCd* Me)
+       : FilterBase(Me, "m_filter_pcre.so")
+       {
+               OnRehash(NULL,"");
+       }
+
+       virtual ~ModuleFilterPCRE()
+       {
+       }
+
+       virtual FilterResult* FilterMatch(userrec* user, const std::string &text, int flags)
+       {
+               for (std::vector<PCREFilter>::iterator index = filters.begin(); index != filters.end(); index++)
+               {
+                       /* Skip ones that dont apply to us */
+
+                       if (!FilterBase::AppliesToMe(user, dynamic_cast<FilterResult*>(&(*index)), flags))
+                               continue;
+
+                       if (pcre_exec(index->regexp, NULL, text.c_str(), text.length(), 0, 0, NULL, 0) > -1)
+                       {
+                               fr = *index;
+                               if (index != filters.begin())
+                               {
+                                       filters.erase(index);
+                                       filters.insert(filters.begin(), fr);
+                               }
+                               return &fr;
+                       }
+               }
+               return NULL;
+       }
+
+       virtual bool DeleteFilter(const std::string &freeform)
+       {
+               for (std::vector<PCREFilter>::iterator i = filters.begin(); i != filters.end(); i++)
+               {
+                       if (i->freeform == freeform)
+                       {
+                               pcre_free((*i).regexp);
+                               filters.erase(i);
+                               return true;
+                       }
+               }
+               return false;
+       }
+
+       virtual void SyncFilters(Module* proto, void* opaque)
+       {
+               for (std::vector<PCREFilter>::iterator i = filters.begin(); i != filters.end(); i++)
+               {
+                       this->SendFilter(proto, opaque, &(*i));
+               }
+       }
+
+       virtual std::pair<bool, std::string> AddFilter(const std::string &freeform, const std::string &type, const std::string &reason, long duration, const std::string &flags)
+       {
+               for (std::vector<PCREFilter>::iterator i = filters.begin(); i != filters.end(); i++)
+               {
+                       if (i->freeform == freeform)
+                       {
+                               return std::make_pair(false, "Filter already exists");
+                       }
+               }
+
+               re = pcre_compile(freeform.c_str(),0,&error,&erroffset,NULL);
+
+               if (!re)
+               {
+                       ServerInstance->Log(DEFAULT,"Error in regular expression: %s at offset %d: %s\n", freeform.c_str(), erroffset, error);
+                       ServerInstance->Log(DEFAULT,"Regular expression %s not loaded.", freeform.c_str());
+                       return std::make_pair(false, "Error in regular expression at offset " + ConvToStr(erroffset) + ": "+error);
+               }
+               else
+               {
+                       filters.push_back(PCREFilter(re, reason, type, duration, freeform, flags));
+                       return std::make_pair(true, "");
+               }
+       }
+
+       virtual void OnRehash(userrec* user, const std::string &parameter)
+       {               
+               ConfigReader MyConf(ServerInstance);
+
+               for (int index = 0; index < MyConf.Enumerate("keyword"); index++)
+               {
+                       this->DeleteFilter(MyConf.ReadValue("keyword", "pattern", index));
+
+                       std::string pattern = MyConf.ReadValue("keyword", "pattern", index);
+                       std::string reason = MyConf.ReadValue("keyword", "reason", index);
+                       std::string action = MyConf.ReadValue("keyword", "action", index);
+                       std::string flags = MyConf.ReadValue("keyword", "flags", index);
+                       long gline_time = ServerInstance->Duration(MyConf.ReadValue("keyword", "duration", index));
+                       if (action.empty())
+                               action = "none";
+                       if (flags.empty())
+                               flags = "*";
+
+                       re = pcre_compile(pattern.c_str(),0,&error,&erroffset,NULL);
+
+                       if (!re)
+                       {
+                               ServerInstance->Log(DEFAULT,"Error in regular expression: %s at offset %d: %s\n", pattern.c_str(), erroffset, error);
+                               ServerInstance->Log(DEFAULT,"Regular expression %s not loaded.", pattern.c_str());
+                       }
+                       else
+                       {
+                               filters.push_back(PCREFilter(re, reason, action, gline_time, pattern, flags));
+                               ServerInstance->Log(DEFAULT,"Regular expression %s loaded.", pattern.c_str());
+                       }
+               }
+       }
+
+       virtual int OnStats(char symbol, userrec* user, string_list &results)
+       {
+               if (symbol == 's')
+               {
+                       std::string sn = ServerInstance->Config->ServerName;
+                       for (std::vector<PCREFilter>::iterator i = filters.begin(); i != filters.end(); i++)
+                       {
+                               results.push_back(sn+" 223 "+user->nick+" :REGEXP:"+i->freeform+" "+i->flags+" "+i->action+" "+ConvToStr(i->gline_time)+" :"+i->reason);
+                       }
+               }
+               return 0;
+       }
+};
+
+MODULE_INIT(ModuleFilterPCRE);
+
index 3f74b549b888c13ecef2496e1dd03d36fb9d4755..90e7a51590d704c897b47fa6d699da000523eeb2 100644 (file)
@@ -1 +1,81 @@
-/*     +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *          the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r#include "httpclient.h"\r\r/* $ModDep: httpclient.h */\r\rclass MyModule : public Module\r{\r\rpublic:\r\r  MyModule(InspIRCd* Me)\r         : Module::Module(Me)\r   {\r      }\r\r     virtual ~MyModule()\r    {\r      }\r\r     virtual void Implements(char* List)\r    {\r              List[I_OnRequest] = List[I_OnUserJoin] = List[I_OnUserPart] = 1;\r       }\r\r     virtual Version GetVersion()\r   {\r              return Version(1,0,0,1,VF_VENDOR,API_VERSION);\r }\r\r     virtual void OnUserJoin(userrec* user, chanrec* channel, bool &silent)\r {\r              // method called when a user joins a channel\r\r          std::string chan = channel->name;\r              std::string nick = user->nick;\r         ServerInstance->Log(DEBUG,"User " + nick + " joined " + chan);\r\r                Module* target = ServerInstance->FindModule("m_http_client.so");\r               if(target)\r             {\r                      HTTPClientRequest req(ServerInstance, this, target, "http://znc.in/~psychon");\r                 req.Send();\r            }\r              else\r                   ServerInstance->Log(DEBUG,"module not found, load it!!");\r      }\r\r     char* OnRequest(Request* req)\r  {\r              HTTPClientResponse* resp = (HTTPClientResponse*)req;\r           if(!strcmp(resp->GetId(), HTTP_CLIENT_RESPONSE))\r               {\r                      ServerInstance->Log(DEBUG, resp->GetData()); \r          }\r              return NULL;\r   }\r\r     virtual void OnUserPart(userrec* user, chanrec* channel, const std::string &partmessage, bool &silent)\r {\r      }\r\r};\r\rMODULE_INIT(MyModule);\r\r
\ No newline at end of file
+/*     +------------------------------------+
+ *     | Inspire Internet Relay Chat Daemon |
+ *     +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *         the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+#include "httpclient.h"
+
+/* $ModDep: httpclient.h */
+
+class MyModule : public Module
+{
+
+public:
+
+       MyModule(InspIRCd* Me)
+               : Module::Module(Me)
+       {
+       }
+
+       virtual ~MyModule()
+       {
+       }
+
+       virtual void Implements(char* List)
+       {
+               List[I_OnRequest] = List[I_OnUserJoin] = List[I_OnUserPart] = 1;
+       }
+
+       virtual Version GetVersion()
+       {
+               return Version(1,0,0,1,VF_VENDOR,API_VERSION);
+       }
+
+       virtual void OnUserJoin(userrec* user, chanrec* channel, bool &silent)
+       {
+               // method called when a user joins a channel
+
+               std::string chan = channel->name;
+               std::string nick = user->nick;
+               ServerInstance->Log(DEBUG,"User " + nick + " joined " + chan);
+
+               Module* target = ServerInstance->FindModule("m_http_client.so");
+               if(target)
+               {
+                       HTTPClientRequest req(ServerInstance, this, target, "http://znc.in/~psychon");
+                       req.Send();
+               }
+               else
+                       ServerInstance->Log(DEBUG,"module not found, load it!!");
+       }
+
+       char* OnRequest(Request* req)
+       {
+               HTTPClientResponse* resp = (HTTPClientResponse*)req;
+               if(!strcmp(resp->GetId(), HTTP_CLIENT_RESPONSE))
+               {
+                       ServerInstance->Log(DEBUG, resp->GetData()); 
+               }
+               return NULL;
+       }
+
+       virtual void OnUserPart(userrec* user, chanrec* channel, const std::string &partmessage, bool &silent)
+       {
+       }
+
+};
+
+MODULE_INIT(MyModule);
+
index eeabe5d4823977ae85084688f93cc400372b6d05..6605bed3c2f7722de92e2b5f99c1ccc869df27d0 100644 (file)
@@ -1 +1,889 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include <mysql.h>\r#include <pthread.h>\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r#include "m_sqlv2.h"\r\r/* VERSION 2 API: With nonblocking (threaded) requests */\r\r/* $ModDesc: SQL Service Provider module for all other m_sql* modules */\r/* $CompileFlags: exec("mysql_config --include") */\r/* $LinkerFlags: exec("mysql_config --libs_r") rpath("mysql_config --libs_r") */\r/* $ModDep: m_sqlv2.h */\r\r/* THE NONBLOCKING MYSQL API!\r * \r * MySQL provides no nonblocking (asyncronous) API of its own, and its developers recommend\r * that instead, you should thread your program. This is what i've done here to allow for\r * asyncronous SQL requests via mysql. The way this works is as follows:\r *\r * The module spawns a thread via pthreads, and performs its mysql queries in this thread,\r * using a queue with priorities. There is a mutex on either end which prevents two threads\r * adjusting the queue at the same time, and crashing the ircd. Every 50 milliseconds, the\r * worker thread wakes up, and checks if there is a request at the head of its queue.\r * If there is, it processes this request, blocking the worker thread but leaving the ircd\r * thread to go about its business as usual. During this period, the ircd thread is able\r * to insert futher pending requests into the queue.\r *\r * Once the processing of a request is complete, it is removed from the incoming queue to\r * an outgoing queue, and initialized as a 'response'. The worker thread then signals the\r * ircd thread (via a loopback socket) of the fact a result is available, by sending the\r * connection ID through the connection.\r *\r * The ircd thread then mutexes the queue once more, reads the outbound response off the head\r * of the queue, and sends it on its way to the original calling module.\r *\r * XXX: You might be asking "why doesnt he just send the response from within the worker thread?"\r * The answer to this is simple. The majority of InspIRCd, and in fact most ircd's are not\r * threadsafe. This module is designed to be threadsafe and is careful with its use of threads,\r * however, if we were to call a module's OnRequest even from within a thread which was not the\r * one the module was originally instantiated upon, there is a chance of all hell breaking loose\r * if a module is ever put in a re-enterant state (stack corruption could occur, crashes, data\r * corruption, and worse, so DONT think about it until the day comes when InspIRCd is 100%\r * gauranteed threadsafe!)\r *\r * For a diagram of this system please see http://www.inspircd.org/wiki/Mysql2\r */\r\r\rclass SQLConnection;\rclass Notifier;\r\r\rtypedef std::map<std::string, SQLConnection*> ConnMap;\rbool giveup = false;\rstatic Module* SQLModule = NULL;\rstatic Notifier* MessagePipe = NULL;\rint QueueFD = -1;\r\r\r#if !defined(MYSQL_VERSION_ID) || MYSQL_VERSION_ID<32224\r#define mysql_field_count mysql_num_fields\r#endif\r\rtypedef std::deque<SQLresult*> ResultQueue;\r\r/* A mutex to wrap around queue accesses */\rpthread_mutex_t queue_mutex = PTHREAD_MUTEX_INITIALIZER;\r\rpthread_mutex_t results_mutex = PTHREAD_MUTEX_INITIALIZER;\r\rpthread_mutex_t logging_mutex = PTHREAD_MUTEX_INITIALIZER;\r\r/** Represents a mysql result set\r */\rclass MySQLresult : public SQLresult\r{\r       int currentrow;\r        std::vector<std::string> colnames;\r     std::vector<SQLfieldList> fieldlists;\r  SQLfieldMap* fieldmap;\r SQLfieldMap fieldmap2;\r SQLfieldList emptyfieldlist;\r   int rows;\r public:\r\r    MySQLresult(Module* self, Module* to, MYSQL_RES* res, int affected_rows, unsigned int id) : SQLresult(self, to, id), currentrow(0), fieldmap(NULL)\r     {\r              /* A number of affected rows from from mysql_affected_rows.\r             */\r            fieldlists.clear();\r            rows = 0;\r              if (affected_rows >= 1)\r                {\r                      rows = affected_rows;\r                  fieldlists.resize(rows);\r               }\r              unsigned int field_count = 0;\r          if (res)\r               {\r                      MYSQL_ROW row;\r                 int n = 0;\r                     while ((row = mysql_fetch_row(res)))\r                   {\r                              if (fieldlists.size() < (unsigned int)rows+1)\r                          {\r                                      fieldlists.resize(fieldlists.size()+1);\r                                }\r                              field_count = 0;\r                               MYSQL_FIELD *fields = mysql_fetch_fields(res);\r                         if(mysql_num_fields(res) == 0)\r                                 break;\r                         if (fields && mysql_num_fields(res))\r                           {\r                                      colnames.clear();\r                                      while (field_count < mysql_num_fields(res))\r                                    {\r                                              std::string a = (fields[field_count].name ? fields[field_count].name : "");\r                                            std::string b = (row[field_count] ? row[field_count] : "");\r                                            SQLfield sqlf(b, !row[field_count]);\r                                           colnames.push_back(a);\r                                         fieldlists[n].push_back(sqlf); \r                                                field_count++;\r                                 }\r                                      n++;\r                           }\r                              rows++;\r                        }\r                      mysql_free_result(res);\r                }\r      }\r\r     MySQLresult(Module* self, Module* to, SQLerror e, unsigned int id) : SQLresult(self, to, id), currentrow(0)\r    {\r              rows = 0;\r              error = e;\r     }\r\r     ~MySQLresult()\r {\r      }\r\r     virtual int Rows()\r     {\r              return rows;\r   }\r\r     virtual int Cols()\r     {\r              return colnames.size();\r        }\r\r     virtual std::string ColName(int column)\r        {\r              if (column < (int)colnames.size())\r             {\r                      return colnames[column];\r               }\r              else\r           {\r                      throw SQLbadColName();\r         }\r              return "";\r     }\r\r     virtual int ColNum(const std::string &column)\r  {\r              for (unsigned int i = 0; i < colnames.size(); i++)\r             {\r                      if (column == colnames[i])\r                             return i;\r              }\r              throw SQLbadColName();\r         return 0;\r      }\r\r     virtual SQLfield GetValue(int row, int column)\r {\r              if ((row >= 0) && (row < rows) && (column >= 0) && (column < Cols()))\r          {\r                      return fieldlists[row][column];\r                }\r\r             throw SQLbadColName();\r\r                /* XXX: We never actually get here because of the throw */\r             return SQLfield("",true);\r      }\r\r     virtual SQLfieldList& GetRow()\r {\r              if (currentrow < rows)\r                 return fieldlists[currentrow];\r         else\r                   return emptyfieldlist;\r }\r\r     virtual SQLfieldMap& GetRowMap()\r       {\r              fieldmap2.clear();\r\r            if (currentrow < rows)\r         {\r                      for (int i = 0; i < Cols(); i++)\r                       {\r                              fieldmap2.insert(std::make_pair(colnames[i],GetValue(currentrow, i)));\r                 }\r                      currentrow++;\r          }\r\r             return fieldmap2;\r      }\r\r     virtual SQLfieldList* GetRowPtr()\r      {\r              SQLfieldList* fieldlist = new SQLfieldList();\r\r         if (currentrow < rows)\r         {\r                      for (int i = 0; i < Rows(); i++)\r                       {\r                              fieldlist->push_back(fieldlists[currentrow][i]);\r                       }\r                      currentrow++;\r          }\r              return fieldlist;\r      }\r\r     virtual SQLfieldMap* GetRowMapPtr()\r    {\r              fieldmap = new SQLfieldMap();\r          \r               if (currentrow < rows)\r         {\r                      for (int i = 0; i < Cols(); i++)\r                       {\r                              fieldmap->insert(std::make_pair(colnames[i],GetValue(currentrow, i)));\r                 }\r                      currentrow++;\r          }\r\r             return fieldmap;\r       }\r\r     virtual void Free(SQLfieldMap* fm)\r     {\r              delete fm;\r     }\r\r     virtual void Free(SQLfieldList* fl)\r    {\r              delete fl;\r     }\r};\r\rclass SQLConnection;\r\rvoid NotifyMainThread(SQLConnection* connection_with_new_result);\r\r/** Represents a connection to a mysql database\r */\rclass SQLConnection : public classbase\r{\r protected:\r\r       MYSQL connection;\r      MYSQL_RES *res;\r        MYSQL_ROW row;\r SQLhost host;\r  std::map<std::string,std::string> thisrow;\r     bool Enabled;\r\r public:\r\r       QueryQueue queue;\r      ResultQueue rq;\r\r       // This constructor creates an SQLConnection object with the given credentials, but does not connect yet.\r      SQLConnection(const SQLhost &hi) : host(hi), Enabled(false)\r    {\r      }\r\r     ~SQLConnection()\r       {\r              Close();\r       }\r\r     // This method connects to the database using the credentials supplied to the constructor, and returns\r // true upon success.\r  bool Connect()\r {\r              unsigned int timeout = 1;\r              mysql_init(&connection);\r               mysql_options(&connection,MYSQL_OPT_CONNECT_TIMEOUT,(char*)&timeout);\r          return mysql_real_connect(&connection, host.host.c_str(), host.user.c_str(), host.pass.c_str(), host.name.c_str(), host.port, NULL, 0);\r        }\r\r     void DoLeadingQuery()\r  {\r              if (!CheckConnection())\r                        return;\r\r               /* Parse the command string and dispatch it to mysql */\r                SQLrequest& req = queue.front();\r\r              /* Pointer to the buffer we screw around with substitution in */\r               char* query;\r\r          /* Pointer to the current end of query, where we append new stuff */\r           char* queryend;\r\r               /* Total length of the unescaped parameters */\r         unsigned long paramlen;\r\r               /* Total length of query, used for binary-safety in mysql_real_query */\r                unsigned long querylength = 0;\r\r                paramlen = 0;\r\r         for(ParamL::iterator i = req.query.p.begin(); i != req.query.p.end(); i++)\r             {\r                      paramlen += i->size();\r         }\r\r             /* To avoid a lot of allocations, allocate enough memory for the biggest the escaped query could possibly be.\r           * sizeofquery + (totalparamlength*2) + 1\r               *\r              * The +1 is for null-terminating the string for mysql_real_escape_string\r               */\r\r           query = new char[req.query.q.length() + (paramlen*2) + 1];\r             queryend = query;\r\r             /* Okay, now we have a buffer large enough we need to start copying the query into it and escaping and substituting\r             * the parameters into it...\r            */\r\r           for(unsigned long i = 0; i < req.query.q.length(); i++)\r                {\r                      if(req.query.q[i] == '?')\r                      {\r                              /* We found a place to substitute..what fun.\r                            * use mysql calls to escape and write the\r                              * escaped string onto the end of our query buffer,\r                             * then we "just" need to make sure queryend is\r                                 * pointing at the right place.\r                                 */\r                            if(req.query.p.size())\r                         {\r                                      unsigned long len = mysql_real_escape_string(&connection, queryend, req.query.p.front().c_str(), req.query.p.front().length());\r\r                                       queryend += len;\r                                       req.query.p.pop_front();\r                               }\r                              else\r                                   break;\r                 }\r                      else\r                   {\r                              *queryend = req.query.q[i];\r                            queryend++;\r                    }\r                      querylength++;\r         }\r\r             *queryend = 0;\r\r                pthread_mutex_lock(&queue_mutex);\r              req.query.q = query;\r           pthread_mutex_unlock(&queue_mutex);\r\r           if (!mysql_real_query(&connection, req.query.q.data(), req.query.q.length()))\r          {\r                      /* Successfull query */\r                        res = mysql_use_result(&connection);\r                   unsigned long rows = mysql_affected_rows(&connection);\r                 MySQLresult* r = new MySQLresult(SQLModule, req.GetSource(), res, rows, req.id);\r                       r->dbid = this->GetID();\r                       r->query = req.query.q;\r                        /* Put this new result onto the results queue.\r                  * XXX: Remember to mutex the queue!\r                    */\r                    pthread_mutex_lock(&results_mutex);\r                    rq.push_back(r);\r                       pthread_mutex_unlock(&results_mutex);\r          }\r              else\r           {\r                      /* XXX: See /usr/include/mysql/mysqld_error.h for a list of\r                     * possible error numbers and error messages */\r                        SQLerror e(QREPLY_FAIL, ConvToStr(mysql_errno(&connection)) + std::string(": ") + mysql_error(&connection));\r                   MySQLresult* r = new MySQLresult(SQLModule, req.GetSource(), e, req.id);\r                       r->dbid = this->GetID();\r                       r->query = req.query.q;\r\r                       pthread_mutex_lock(&results_mutex);\r                    rq.push_back(r);\r                       pthread_mutex_unlock(&results_mutex);\r          }\r\r             /* Now signal the main thread that we've got a result to process.\r               * Pass them this connection id as what to examine\r              */\r\r           delete[] query;\r\r               NotifyMainThread(this);\r        }\r\r     bool ConnectionLost()\r  {\r              if (&connection) {\r                     return (mysql_ping(&connection) != 0);\r         }\r              else return false;\r     }\r\r     bool CheckConnection()\r {\r              if (ConnectionLost()) {\r                        return Connect();\r              }\r              else return true;\r      }\r\r     std::string GetError()\r {\r              return mysql_error(&connection);\r       }\r\r     const std::string& GetID()\r     {\r              return host.id;\r        }\r\r     std::string GetHost()\r  {\r              return host.host;\r      }\r\r     void SetEnable(bool Enable)\r    {\r              Enabled = Enable;\r      }\r\r     bool IsEnabled()\r       {\r              return Enabled;\r        }\r\r     void Close()\r   {\r              mysql_close(&connection);\r      }\r\r     const SQLhost& GetConfHost()\r   {\r              return host;\r   }\r\r};\r\rConnMap Connections;\r\rbool HasHost(const SQLhost &host)\r{\r       for (ConnMap::iterator iter = Connections.begin(); iter != Connections.end(); iter++)\r  {\r              if (host == iter->second->GetConfHost())\r                       return true;\r   }\r      return false;\r}\r\rbool HostInConf(ConfigReader* conf, const SQLhost &h)\r{\r       for(int i = 0; i < conf->Enumerate("database"); i++)\r   {\r              SQLhost host;\r          host.id         = conf->ReadValue("database", "id", i);\r                host.host       = conf->ReadValue("database", "hostname", i);\r          host.port       = conf->ReadInteger("database", "port", i, true);\r              host.name       = conf->ReadValue("database", "name", i);\r              host.user       = conf->ReadValue("database", "username", i);\r          host.pass       = conf->ReadValue("database", "password", i);\r          host.ssl        = conf->ReadFlag("database", "ssl", i);\r                if (h == host)\r                 return true;\r   }\r      return false;\r}\r\rvoid ClearOldConnections(ConfigReader* conf)\r{\r        ConnMap::iterator i,safei;\r     for (i = Connections.begin(); i != Connections.end(); i++)\r     {\r              if (!HostInConf(conf, i->second->GetConfHost()))\r               {\r                      DELETE(i->second);\r                     safei = i;\r                     --i;\r                   Connections.erase(safei);\r              }\r      }\r}\r\rvoid ClearAllConnections()\r{\r      ConnMap::iterator i;\r   while ((i = Connections.begin()) != Connections.end())\r {\r              Connections.erase(i);\r          DELETE(i->second);\r     }\r}\r\rvoid ConnectDatabases(InspIRCd* ServerInstance)\r{\r for (ConnMap::iterator i = Connections.begin(); i != Connections.end(); i++)\r   {\r              if (i->second->IsEnabled())\r                    continue;\r\r             i->second->SetEnable(true);\r            if (!i->second->Connect())\r             {\r                      /* XXX: MUTEX */\r                       pthread_mutex_lock(&logging_mutex);\r                    ServerInstance->Log(DEFAULT,"SQL: Failed to connect database "+i->second->GetHost()+": Error: "+i->second->GetError());\r                        i->second->SetEnable(false);\r                   pthread_mutex_unlock(&logging_mutex);\r          }\r      }\r}\r\rvoid LoadDatabases(ConfigReader* conf, InspIRCd* ServerInstance)\r{\r        ClearOldConnections(conf);\r     for (int j =0; j < conf->Enumerate("database"); j++)\r   {\r              SQLhost host;\r          host.id         = conf->ReadValue("database", "id", j);\r                host.host       = conf->ReadValue("database", "hostname", j);\r          host.port       = conf->ReadInteger("database", "port", j, true);\r              host.name       = conf->ReadValue("database", "name", j);\r              host.user       = conf->ReadValue("database", "username", j);\r          host.pass       = conf->ReadValue("database", "password", j);\r          host.ssl        = conf->ReadFlag("database", "ssl", j);\r\r               if (HasHost(host))\r                     continue;\r\r             if (!host.id.empty() && !host.host.empty() && !host.name.empty() && !host.user.empty() && !host.pass.empty())\r          {\r                      SQLConnection* ThisSQL = new SQLConnection(host);\r                      Connections[host.id] = ThisSQL;\r                }\r      }\r      ConnectDatabases(ServerInstance);\r}\r\rchar FindCharId(const std::string &id)\r{\r  char i = 1;\r    for (ConnMap::iterator iter = Connections.begin(); iter != Connections.end(); ++iter, ++i)\r     {\r              if (iter->first == id)\r         {\r                      return i;\r              }\r      }\r      return 0;\r}\r\rConnMap::iterator GetCharId(char id)\r{\r    char i = 1;\r    for (ConnMap::iterator iter = Connections.begin(); iter != Connections.end(); ++iter, ++i)\r     {\r              if (i == id)\r                   return iter;\r   }\r      return Connections.end();\r}\r\rvoid NotifyMainThread(SQLConnection* connection_with_new_result)\r{\r        /* Here we write() to the socket the main thread has open\r       * and we connect()ed back to before our thread became active.\r  * The main thread is using a nonblocking socket tied into\r      * the socket engine, so they wont block and they'll receive\r    * nearly instant notification. Because we're in a seperate\r     * thread, we can just use standard connect(), and we can\r       * block if we like. We just send the connection id of the\r      * connection back.\r     *\r      * NOTE: We only send a single char down the connection, this\r   * way we know it wont get a partial read at the other end if\r   * the system is especially congested (see bug #263).\r   * The function FindCharId translates a connection name into a\r  * one character id, and GetCharId translates a character id\r    * back into an iterator.\r       */\r    char id = FindCharId(connection_with_new_result->GetID());\r     send(QueueFD, &id, 1, 0);\r}\r\rvoid* DispatcherThread(void* arg);\r\r/** Used by m_mysql to notify one thread when the other has a result\r */\rclass Notifier : public InspSocket\r{\r insp_sockaddr sock_us;\r socklen_t uslen;\r       \r\r public:\r\r    /* Create a socket on a random port. Let the tcp stack allocate us an available port */\r#ifdef IPV6\r    Notifier(InspIRCd* SI) : InspSocket(SI, "::1", 0, true, 3000)\r#else\r    Notifier(InspIRCd* SI) : InspSocket(SI, "127.0.0.1", 0, true, 3000)\r#endif\r     {\r              uslen = sizeof(sock_us);\r               if (getsockname(this->fd,(sockaddr*)&sock_us,&uslen))\r          {\r                      throw ModuleException("Could not create random listening port on localhost");\r          }\r      }\r\r     Notifier(InspIRCd* SI, int newfd, char* ip) : InspSocket(SI, newfd, ip)\r        {\r      }\r\r     /* Using getsockname and ntohs, we can determine which port number we were allocated */\r        int GetPort()\r  {\r#ifdef IPV6\r          return ntohs(sock_us.sin6_port);\r#else\r         return ntohs(sock_us.sin_port);\r#endif\r }\r\r     virtual int OnIncomingConnection(int newsock, char* ip)\r        {\r              Notifier* n = new Notifier(this->Instance, newsock, ip);\r               n = n; /* Stop bitching at me, GCC */\r          return true;\r   }\r\r     virtual bool OnDataReady()\r     {\r              char data = 0;\r         /* NOTE: Only a single character is read so we know we\r          * cant get a partial read. (We've been told that theres\r                * data waiting, so we wont ever get EAGAIN)\r            * The function GetCharId translates a single character\r                 * back into an iterator.\r               */\r            if (read(this->GetFd(), &data, 1) > 0)\r         {\r                      ConnMap::iterator iter = GetCharId(data);\r                      if (iter != Connections.end())\r                 {\r                              /* Lock the mutex, send back the data */\r                               pthread_mutex_lock(&results_mutex);\r                            ResultQueue::iterator n = iter->second->rq.begin();\r                            (*n)->Send();\r                          iter->second->rq.pop_front();\r                          pthread_mutex_unlock(&results_mutex);\r                          return true;\r                   }\r                      /* No error, but unknown id */\r                 return true;\r           }\r\r             /* Erk, error on descriptor! */\r                return false;\r  }\r};\r\r/** MySQL module\r */\rclass ModuleSQL : public Module\r{\r public:\r  \r       ConfigReader *Conf;\r    InspIRCd* PublicServerInstance;\r        pthread_t Dispatcher;\r  int currid;\r    bool rehashing;\r\r       ModuleSQL(InspIRCd* Me)\r        : Module::Module(Me), rehashing(false)\r {\r              ServerInstance->UseInterface("SQLutils");\r\r             Conf = new ConfigReader(ServerInstance);\r               PublicServerInstance = ServerInstance;\r         currid = 0;\r            SQLModule = this;\r\r             MessagePipe = new Notifier(ServerInstance);\r            \r               pthread_attr_t attribs;\r                pthread_attr_init(&attribs);\r           pthread_attr_setdetachstate(&attribs, PTHREAD_CREATE_DETACHED);\r                if (pthread_create(&this->Dispatcher, &attribs, DispatcherThread, (void *)this) != 0)\r          {\r                      throw ModuleException("m_mysql: Failed to create dispatcher thread: " + std::string(strerror(errno)));\r         }\r\r             if (!ServerInstance->PublishFeature("SQL", this))\r              {\r                      /* Tell worker thread to exit NOW */\r                   giveup = true;\r                 throw ModuleException("m_mysql: Unable to publish feature 'SQL'");\r             }\r\r             ServerInstance->PublishInterface("SQL", this);\r }\r\r     virtual ~ModuleSQL()\r   {\r              giveup = true;\r         ClearAllConnections();\r         DELETE(Conf);\r          ServerInstance->UnpublishInterface("SQL", this);\r               ServerInstance->UnpublishFeature("SQL");\r               ServerInstance->DoneWithInterface("SQLutils");\r }\r\r\r    void Implements(char* List)\r    {\r              List[I_OnRehash] = List[I_OnRequest] = 1;\r      }\r\r     unsigned long NewID()\r  {\r              if (currid+1 == 0)\r                     currid++;\r              return ++currid;\r       }\r\r     char* OnRequest(Request* request)\r      {\r              if(strcmp(SQLREQID, request->GetId()) == 0)\r            {\r                      SQLrequest* req = (SQLrequest*)request;\r\r                       /* XXX: Lock */\r                        pthread_mutex_lock(&queue_mutex);\r\r                     ConnMap::iterator iter;\r\r                       char* returnval = NULL;\r\r                       if((iter = Connections.find(req->dbid)) != Connections.end())\r                  {\r                              req->id = NewID();\r                             iter->second->queue.push(*req);\r                                returnval = SQLSUCCESS;\r                        }\r                      else\r                   {\r                              req->error.Id(BAD_DBID);\r                       }\r\r                     pthread_mutex_unlock(&queue_mutex);\r                    /* XXX: Unlock */\r\r                     return returnval;\r              }\r\r             return NULL;\r   }\r\r     virtual void OnRehash(userrec* user, const std::string &parameter)\r     {\r              rehashing = true;\r      }\r      \r       virtual Version GetVersion()\r   {\r              return Version(1,1,0,0,VF_VENDOR|VF_SERVICEPROVIDER,API_VERSION);\r      }\r      \r};\r\rvoid* DispatcherThread(void* arg)\r{\r       ModuleSQL* thismodule = (ModuleSQL*)arg;\r       LoadDatabases(thismodule->Conf, thismodule->PublicServerInstance);\r\r    /* Connect back to the Notifier */\r\r    if ((QueueFD = socket(AF_FAMILY, SOCK_STREAM, 0)) == -1)\r       {\r              /* crap, we're out of sockets... */\r            return NULL;\r   }\r\r     insp_sockaddr addr;\r\r#ifdef IPV6\r       insp_aton("::1", &addr.sin6_addr);\r     addr.sin6_family = AF_FAMILY;\r  addr.sin6_port = htons(MessagePipe->GetPort());\r#else\r  insp_inaddr ia;\r        insp_aton("127.0.0.1", &ia);\r   addr.sin_family = AF_FAMILY;\r   addr.sin_addr = ia;\r    addr.sin_port = htons(MessagePipe->GetPort());\r#endif\r\r if (connect(QueueFD, (sockaddr*)&addr,sizeof(addr)) == -1)\r     {\r              /* wtf, we cant connect to it, but we just created it! */\r              return NULL;\r   }\r\r     while (!giveup)\r        {\r              if (thismodule->rehashing)\r             {\r              /* XXX: Lock */\r                        pthread_mutex_lock(&queue_mutex);\r                      thismodule->rehashing = false;\r                 LoadDatabases(thismodule->Conf, thismodule->PublicServerInstance);\r                     pthread_mutex_unlock(&queue_mutex);\r                    /* XXX: Unlock */\r              }\r\r             SQLConnection* conn = NULL;\r            /* XXX: Lock here for safety */\r                pthread_mutex_lock(&queue_mutex);\r              for (ConnMap::iterator i = Connections.begin(); i != Connections.end(); i++)\r           {\r                      if (i->second->queue.totalsize())\r                      {\r                              conn = i->second;\r                              break;\r                 }\r              }\r              pthread_mutex_unlock(&queue_mutex);\r            /* XXX: Unlock */\r\r             /* Theres an item! */\r          if (conn)\r              {\r                      conn->DoLeadingQuery();\r\r                       /* XXX: Lock */\r                        pthread_mutex_lock(&queue_mutex);\r                      conn->queue.pop();\r                     pthread_mutex_unlock(&queue_mutex);\r                    /* XXX: Unlock */\r              }\r\r             usleep(50);\r    }\r\r     return NULL;\r}\r\rMODULE_INIT(ModuleSQL);\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include <mysql.h>
+#include <pthread.h>
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+#include "m_sqlv2.h"
+
+/* VERSION 2 API: With nonblocking (threaded) requests */
+
+/* $ModDesc: SQL Service Provider module for all other m_sql* modules */
+/* $CompileFlags: exec("mysql_config --include") */
+/* $LinkerFlags: exec("mysql_config --libs_r") rpath("mysql_config --libs_r") */
+/* $ModDep: m_sqlv2.h */
+
+/* THE NONBLOCKING MYSQL API!
+ * 
+ * MySQL provides no nonblocking (asyncronous) API of its own, and its developers recommend
+ * that instead, you should thread your program. This is what i've done here to allow for
+ * asyncronous SQL requests via mysql. The way this works is as follows:
+ *
+ * The module spawns a thread via pthreads, and performs its mysql queries in this thread,
+ * using a queue with priorities. There is a mutex on either end which prevents two threads
+ * adjusting the queue at the same time, and crashing the ircd. Every 50 milliseconds, the
+ * worker thread wakes up, and checks if there is a request at the head of its queue.
+ * If there is, it processes this request, blocking the worker thread but leaving the ircd
+ * thread to go about its business as usual. During this period, the ircd thread is able
+ * to insert futher pending requests into the queue.
+ *
+ * Once the processing of a request is complete, it is removed from the incoming queue to
+ * an outgoing queue, and initialized as a 'response'. The worker thread then signals the
+ * ircd thread (via a loopback socket) of the fact a result is available, by sending the
+ * connection ID through the connection.
+ *
+ * The ircd thread then mutexes the queue once more, reads the outbound response off the head
+ * of the queue, and sends it on its way to the original calling module.
+ *
+ * XXX: You might be asking "why doesnt he just send the response from within the worker thread?"
+ * The answer to this is simple. The majority of InspIRCd, and in fact most ircd's are not
+ * threadsafe. This module is designed to be threadsafe and is careful with its use of threads,
+ * however, if we were to call a module's OnRequest even from within a thread which was not the
+ * one the module was originally instantiated upon, there is a chance of all hell breaking loose
+ * if a module is ever put in a re-enterant state (stack corruption could occur, crashes, data
+ * corruption, and worse, so DONT think about it until the day comes when InspIRCd is 100%
+ * gauranteed threadsafe!)
+ *
+ * For a diagram of this system please see http://www.inspircd.org/wiki/Mysql2
+ */
+
+
+class SQLConnection;
+class Notifier;
+
+
+typedef std::map<std::string, SQLConnection*> ConnMap;
+bool giveup = false;
+static Module* SQLModule = NULL;
+static Notifier* MessagePipe = NULL;
+int QueueFD = -1;
+
+
+#if !defined(MYSQL_VERSION_ID) || MYSQL_VERSION_ID<32224
+#define mysql_field_count mysql_num_fields
+#endif
+
+typedef std::deque<SQLresult*> ResultQueue;
+
+/* A mutex to wrap around queue accesses */
+pthread_mutex_t queue_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+pthread_mutex_t results_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+pthread_mutex_t logging_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/** Represents a mysql result set
+ */
+class MySQLresult : public SQLresult
+{
+       int currentrow;
+       std::vector<std::string> colnames;
+       std::vector<SQLfieldList> fieldlists;
+       SQLfieldMap* fieldmap;
+       SQLfieldMap fieldmap2;
+       SQLfieldList emptyfieldlist;
+       int rows;
+ public:
+
+       MySQLresult(Module* self, Module* to, MYSQL_RES* res, int affected_rows, unsigned int id) : SQLresult(self, to, id), currentrow(0), fieldmap(NULL)
+       {
+               /* A number of affected rows from from mysql_affected_rows.
+                */
+               fieldlists.clear();
+               rows = 0;
+               if (affected_rows >= 1)
+               {
+                       rows = affected_rows;
+                       fieldlists.resize(rows);
+               }
+               unsigned int field_count = 0;
+               if (res)
+               {
+                       MYSQL_ROW row;
+                       int n = 0;
+                       while ((row = mysql_fetch_row(res)))
+                       {
+                               if (fieldlists.size() < (unsigned int)rows+1)
+                               {
+                                       fieldlists.resize(fieldlists.size()+1);
+                               }
+                               field_count = 0;
+                               MYSQL_FIELD *fields = mysql_fetch_fields(res);
+                               if(mysql_num_fields(res) == 0)
+                                       break;
+                               if (fields && mysql_num_fields(res))
+                               {
+                                       colnames.clear();
+                                       while (field_count < mysql_num_fields(res))
+                                       {
+                                               std::string a = (fields[field_count].name ? fields[field_count].name : "");
+                                               std::string b = (row[field_count] ? row[field_count] : "");
+                                               SQLfield sqlf(b, !row[field_count]);
+                                               colnames.push_back(a);
+                                               fieldlists[n].push_back(sqlf); 
+                                               field_count++;
+                                       }
+                                       n++;
+                               }
+                               rows++;
+                       }
+                       mysql_free_result(res);
+               }
+       }
+
+       MySQLresult(Module* self, Module* to, SQLerror e, unsigned int id) : SQLresult(self, to, id), currentrow(0)
+       {
+               rows = 0;
+               error = e;
+       }
+
+       ~MySQLresult()
+       {
+       }
+
+       virtual int Rows()
+       {
+               return rows;
+       }
+
+       virtual int Cols()
+       {
+               return colnames.size();
+       }
+
+       virtual std::string ColName(int column)
+       {
+               if (column < (int)colnames.size())
+               {
+                       return colnames[column];
+               }
+               else
+               {
+                       throw SQLbadColName();
+               }
+               return "";
+       }
+
+       virtual int ColNum(const std::string &column)
+       {
+               for (unsigned int i = 0; i < colnames.size(); i++)
+               {
+                       if (column == colnames[i])
+                               return i;
+               }
+               throw SQLbadColName();
+               return 0;
+       }
+
+       virtual SQLfield GetValue(int row, int column)
+       {
+               if ((row >= 0) && (row < rows) && (column >= 0) && (column < Cols()))
+               {
+                       return fieldlists[row][column];
+               }
+
+               throw SQLbadColName();
+
+               /* XXX: We never actually get here because of the throw */
+               return SQLfield("",true);
+       }
+
+       virtual SQLfieldList& GetRow()
+       {
+               if (currentrow < rows)
+                       return fieldlists[currentrow];
+               else
+                       return emptyfieldlist;
+       }
+
+       virtual SQLfieldMap& GetRowMap()
+       {
+               fieldmap2.clear();
+
+               if (currentrow < rows)
+               {
+                       for (int i = 0; i < Cols(); i++)
+                       {
+                               fieldmap2.insert(std::make_pair(colnames[i],GetValue(currentrow, i)));
+                       }
+                       currentrow++;
+               }
+
+               return fieldmap2;
+       }
+
+       virtual SQLfieldList* GetRowPtr()
+       {
+               SQLfieldList* fieldlist = new SQLfieldList();
+
+               if (currentrow < rows)
+               {
+                       for (int i = 0; i < Rows(); i++)
+                       {
+                               fieldlist->push_back(fieldlists[currentrow][i]);
+                       }
+                       currentrow++;
+               }
+               return fieldlist;
+       }
+
+       virtual SQLfieldMap* GetRowMapPtr()
+       {
+               fieldmap = new SQLfieldMap();
+               
+               if (currentrow < rows)
+               {
+                       for (int i = 0; i < Cols(); i++)
+                       {
+                               fieldmap->insert(std::make_pair(colnames[i],GetValue(currentrow, i)));
+                       }
+                       currentrow++;
+               }
+
+               return fieldmap;
+       }
+
+       virtual void Free(SQLfieldMap* fm)
+       {
+               delete fm;
+       }
+
+       virtual void Free(SQLfieldList* fl)
+       {
+               delete fl;
+       }
+};
+
+class SQLConnection;
+
+void NotifyMainThread(SQLConnection* connection_with_new_result);
+
+/** Represents a connection to a mysql database
+ */
+class SQLConnection : public classbase
+{
+ protected:
+
+       MYSQL connection;
+       MYSQL_RES *res;
+       MYSQL_ROW row;
+       SQLhost host;
+       std::map<std::string,std::string> thisrow;
+       bool Enabled;
+
+ public:
+
+       QueryQueue queue;
+       ResultQueue rq;
+
+       // This constructor creates an SQLConnection object with the given credentials, but does not connect yet.
+       SQLConnection(const SQLhost &hi) : host(hi), Enabled(false)
+       {
+       }
+
+       ~SQLConnection()
+       {
+               Close();
+       }
+
+       // This method connects to the database using the credentials supplied to the constructor, and returns
+       // true upon success.
+       bool Connect()
+       {
+               unsigned int timeout = 1;
+               mysql_init(&connection);
+               mysql_options(&connection,MYSQL_OPT_CONNECT_TIMEOUT,(char*)&timeout);
+               return mysql_real_connect(&connection, host.host.c_str(), host.user.c_str(), host.pass.c_str(), host.name.c_str(), host.port, NULL, 0);
+       }
+
+       void DoLeadingQuery()
+       {
+               if (!CheckConnection())
+                       return;
+
+               /* Parse the command string and dispatch it to mysql */
+               SQLrequest& req = queue.front();
+
+               /* Pointer to the buffer we screw around with substitution in */
+               char* query;
+
+               /* Pointer to the current end of query, where we append new stuff */
+               char* queryend;
+
+               /* Total length of the unescaped parameters */
+               unsigned long paramlen;
+
+               /* Total length of query, used for binary-safety in mysql_real_query */
+               unsigned long querylength = 0;
+
+               paramlen = 0;
+
+               for(ParamL::iterator i = req.query.p.begin(); i != req.query.p.end(); i++)
+               {
+                       paramlen += i->size();
+               }
+
+               /* To avoid a lot of allocations, allocate enough memory for the biggest the escaped query could possibly be.
+                * sizeofquery + (totalparamlength*2) + 1
+                *
+                * The +1 is for null-terminating the string for mysql_real_escape_string
+                */
+
+               query = new char[req.query.q.length() + (paramlen*2) + 1];
+               queryend = query;
+
+               /* Okay, now we have a buffer large enough we need to start copying the query into it and escaping and substituting
+                * the parameters into it...
+                */
+
+               for(unsigned long i = 0; i < req.query.q.length(); i++)
+               {
+                       if(req.query.q[i] == '?')
+                       {
+                               /* We found a place to substitute..what fun.
+                                * use mysql calls to escape and write the
+                                * escaped string onto the end of our query buffer,
+                                * then we "just" need to make sure queryend is
+                                * pointing at the right place.
+                                */
+                               if(req.query.p.size())
+                               {
+                                       unsigned long len = mysql_real_escape_string(&connection, queryend, req.query.p.front().c_str(), req.query.p.front().length());
+
+                                       queryend += len;
+                                       req.query.p.pop_front();
+                               }
+                               else
+                                       break;
+                       }
+                       else
+                       {
+                               *queryend = req.query.q[i];
+                               queryend++;
+                       }
+                       querylength++;
+               }
+
+               *queryend = 0;
+
+               pthread_mutex_lock(&queue_mutex);
+               req.query.q = query;
+               pthread_mutex_unlock(&queue_mutex);
+
+               if (!mysql_real_query(&connection, req.query.q.data(), req.query.q.length()))
+               {
+                       /* Successfull query */
+                       res = mysql_use_result(&connection);
+                       unsigned long rows = mysql_affected_rows(&connection);
+                       MySQLresult* r = new MySQLresult(SQLModule, req.GetSource(), res, rows, req.id);
+                       r->dbid = this->GetID();
+                       r->query = req.query.q;
+                       /* Put this new result onto the results queue.
+                        * XXX: Remember to mutex the queue!
+                        */
+                       pthread_mutex_lock(&results_mutex);
+                       rq.push_back(r);
+                       pthread_mutex_unlock(&results_mutex);
+               }
+               else
+               {
+                       /* XXX: See /usr/include/mysql/mysqld_error.h for a list of
+                        * possible error numbers and error messages */
+                       SQLerror e(QREPLY_FAIL, ConvToStr(mysql_errno(&connection)) + std::string(": ") + mysql_error(&connection));
+                       MySQLresult* r = new MySQLresult(SQLModule, req.GetSource(), e, req.id);
+                       r->dbid = this->GetID();
+                       r->query = req.query.q;
+
+                       pthread_mutex_lock(&results_mutex);
+                       rq.push_back(r);
+                       pthread_mutex_unlock(&results_mutex);
+               }
+
+               /* Now signal the main thread that we've got a result to process.
+                * Pass them this connection id as what to examine
+                */
+
+               delete[] query;
+
+               NotifyMainThread(this);
+       }
+
+       bool ConnectionLost()
+       {
+               if (&connection) {
+                       return (mysql_ping(&connection) != 0);
+               }
+               else return false;
+       }
+
+       bool CheckConnection()
+       {
+               if (ConnectionLost()) {
+                       return Connect();
+               }
+               else return true;
+       }
+
+       std::string GetError()
+       {
+               return mysql_error(&connection);
+       }
+
+       const std::string& GetID()
+       {
+               return host.id;
+       }
+
+       std::string GetHost()
+       {
+               return host.host;
+       }
+
+       void SetEnable(bool Enable)
+       {
+               Enabled = Enable;
+       }
+
+       bool IsEnabled()
+       {
+               return Enabled;
+       }
+
+       void Close()
+       {
+               mysql_close(&connection);
+       }
+
+       const SQLhost& GetConfHost()
+       {
+               return host;
+       }
+
+};
+
+ConnMap Connections;
+
+bool HasHost(const SQLhost &host)
+{
+       for (ConnMap::iterator iter = Connections.begin(); iter != Connections.end(); iter++)
+       {
+               if (host == iter->second->GetConfHost())
+                       return true;
+       }
+       return false;
+}
+
+bool HostInConf(ConfigReader* conf, const SQLhost &h)
+{
+       for(int i = 0; i < conf->Enumerate("database"); i++)
+       {
+               SQLhost host;
+               host.id         = conf->ReadValue("database", "id", i);
+               host.host       = conf->ReadValue("database", "hostname", i);
+               host.port       = conf->ReadInteger("database", "port", i, true);
+               host.name       = conf->ReadValue("database", "name", i);
+               host.user       = conf->ReadValue("database", "username", i);
+               host.pass       = conf->ReadValue("database", "password", i);
+               host.ssl        = conf->ReadFlag("database", "ssl", i);
+               if (h == host)
+                       return true;
+       }
+       return false;
+}
+
+void ClearOldConnections(ConfigReader* conf)
+{
+       ConnMap::iterator i,safei;
+       for (i = Connections.begin(); i != Connections.end(); i++)
+       {
+               if (!HostInConf(conf, i->second->GetConfHost()))
+               {
+                       DELETE(i->second);
+                       safei = i;
+                       --i;
+                       Connections.erase(safei);
+               }
+       }
+}
+
+void ClearAllConnections()
+{
+       ConnMap::iterator i;
+       while ((i = Connections.begin()) != Connections.end())
+       {
+               Connections.erase(i);
+               DELETE(i->second);
+       }
+}
+
+void ConnectDatabases(InspIRCd* ServerInstance)
+{
+       for (ConnMap::iterator i = Connections.begin(); i != Connections.end(); i++)
+       {
+               if (i->second->IsEnabled())
+                       continue;
+
+               i->second->SetEnable(true);
+               if (!i->second->Connect())
+               {
+                       /* XXX: MUTEX */
+                       pthread_mutex_lock(&logging_mutex);
+                       ServerInstance->Log(DEFAULT,"SQL: Failed to connect database "+i->second->GetHost()+": Error: "+i->second->GetError());
+                       i->second->SetEnable(false);
+                       pthread_mutex_unlock(&logging_mutex);
+               }
+       }
+}
+
+void LoadDatabases(ConfigReader* conf, InspIRCd* ServerInstance)
+{
+       ClearOldConnections(conf);
+       for (int j =0; j < conf->Enumerate("database"); j++)
+       {
+               SQLhost host;
+               host.id         = conf->ReadValue("database", "id", j);
+               host.host       = conf->ReadValue("database", "hostname", j);
+               host.port       = conf->ReadInteger("database", "port", j, true);
+               host.name       = conf->ReadValue("database", "name", j);
+               host.user       = conf->ReadValue("database", "username", j);
+               host.pass       = conf->ReadValue("database", "password", j);
+               host.ssl        = conf->ReadFlag("database", "ssl", j);
+
+               if (HasHost(host))
+                       continue;
+
+               if (!host.id.empty() && !host.host.empty() && !host.name.empty() && !host.user.empty() && !host.pass.empty())
+               {
+                       SQLConnection* ThisSQL = new SQLConnection(host);
+                       Connections[host.id] = ThisSQL;
+               }
+       }
+       ConnectDatabases(ServerInstance);
+}
+
+char FindCharId(const std::string &id)
+{
+       char i = 1;
+       for (ConnMap::iterator iter = Connections.begin(); iter != Connections.end(); ++iter, ++i)
+       {
+               if (iter->first == id)
+               {
+                       return i;
+               }
+       }
+       return 0;
+}
+
+ConnMap::iterator GetCharId(char id)
+{
+       char i = 1;
+       for (ConnMap::iterator iter = Connections.begin(); iter != Connections.end(); ++iter, ++i)
+       {
+               if (i == id)
+                       return iter;
+       }
+       return Connections.end();
+}
+
+void NotifyMainThread(SQLConnection* connection_with_new_result)
+{
+       /* Here we write() to the socket the main thread has open
+        * and we connect()ed back to before our thread became active.
+        * The main thread is using a nonblocking socket tied into
+        * the socket engine, so they wont block and they'll receive
+        * nearly instant notification. Because we're in a seperate
+        * thread, we can just use standard connect(), and we can
+        * block if we like. We just send the connection id of the
+        * connection back.
+        *
+        * NOTE: We only send a single char down the connection, this
+        * way we know it wont get a partial read at the other end if
+        * the system is especially congested (see bug #263).
+        * The function FindCharId translates a connection name into a
+        * one character id, and GetCharId translates a character id
+        * back into an iterator.
+        */
+       char id = FindCharId(connection_with_new_result->GetID());
+       send(QueueFD, &id, 1, 0);
+}
+
+void* DispatcherThread(void* arg);
+
+/** Used by m_mysql to notify one thread when the other has a result
+ */
+class Notifier : public InspSocket
+{
+       insp_sockaddr sock_us;
+       socklen_t uslen;
+       
+
+ public:
+
+       /* Create a socket on a random port. Let the tcp stack allocate us an available port */
+#ifdef IPV6
+       Notifier(InspIRCd* SI) : InspSocket(SI, "::1", 0, true, 3000)
+#else
+       Notifier(InspIRCd* SI) : InspSocket(SI, "127.0.0.1", 0, true, 3000)
+#endif
+       {
+               uslen = sizeof(sock_us);
+               if (getsockname(this->fd,(sockaddr*)&sock_us,&uslen))
+               {
+                       throw ModuleException("Could not create random listening port on localhost");
+               }
+       }
+
+       Notifier(InspIRCd* SI, int newfd, char* ip) : InspSocket(SI, newfd, ip)
+       {
+       }
+
+       /* Using getsockname and ntohs, we can determine which port number we were allocated */
+       int GetPort()
+       {
+#ifdef IPV6
+               return ntohs(sock_us.sin6_port);
+#else
+               return ntohs(sock_us.sin_port);
+#endif
+       }
+
+       virtual int OnIncomingConnection(int newsock, char* ip)
+       {
+               Notifier* n = new Notifier(this->Instance, newsock, ip);
+               n = n; /* Stop bitching at me, GCC */
+               return true;
+       }
+
+       virtual bool OnDataReady()
+       {
+               char data = 0;
+               /* NOTE: Only a single character is read so we know we
+                * cant get a partial read. (We've been told that theres
+                * data waiting, so we wont ever get EAGAIN)
+                * The function GetCharId translates a single character
+                * back into an iterator.
+                */
+               if (read(this->GetFd(), &data, 1) > 0)
+               {
+                       ConnMap::iterator iter = GetCharId(data);
+                       if (iter != Connections.end())
+                       {
+                               /* Lock the mutex, send back the data */
+                               pthread_mutex_lock(&results_mutex);
+                               ResultQueue::iterator n = iter->second->rq.begin();
+                               (*n)->Send();
+                               iter->second->rq.pop_front();
+                               pthread_mutex_unlock(&results_mutex);
+                               return true;
+                       }
+                       /* No error, but unknown id */
+                       return true;
+               }
+
+               /* Erk, error on descriptor! */
+               return false;
+       }
+};
+
+/** MySQL module
+ */
+class ModuleSQL : public Module
+{
+ public:
+       
+       ConfigReader *Conf;
+       InspIRCd* PublicServerInstance;
+       pthread_t Dispatcher;
+       int currid;
+       bool rehashing;
+
+       ModuleSQL(InspIRCd* Me)
+       : Module::Module(Me), rehashing(false)
+       {
+               ServerInstance->UseInterface("SQLutils");
+
+               Conf = new ConfigReader(ServerInstance);
+               PublicServerInstance = ServerInstance;
+               currid = 0;
+               SQLModule = this;
+
+               MessagePipe = new Notifier(ServerInstance);
+               
+               pthread_attr_t attribs;
+               pthread_attr_init(&attribs);
+               pthread_attr_setdetachstate(&attribs, PTHREAD_CREATE_DETACHED);
+               if (pthread_create(&this->Dispatcher, &attribs, DispatcherThread, (void *)this) != 0)
+               {
+                       throw ModuleException("m_mysql: Failed to create dispatcher thread: " + std::string(strerror(errno)));
+               }
+
+               if (!ServerInstance->PublishFeature("SQL", this))
+               {
+                       /* Tell worker thread to exit NOW */
+                       giveup = true;
+                       throw ModuleException("m_mysql: Unable to publish feature 'SQL'");
+               }
+
+               ServerInstance->PublishInterface("SQL", this);
+       }
+
+       virtual ~ModuleSQL()
+       {
+               giveup = true;
+               ClearAllConnections();
+               DELETE(Conf);
+               ServerInstance->UnpublishInterface("SQL", this);
+               ServerInstance->UnpublishFeature("SQL");
+               ServerInstance->DoneWithInterface("SQLutils");
+       }
+
+
+       void Implements(char* List)
+       {
+               List[I_OnRehash] = List[I_OnRequest] = 1;
+       }
+
+       unsigned long NewID()
+       {
+               if (currid+1 == 0)
+                       currid++;
+               return ++currid;
+       }
+
+       char* OnRequest(Request* request)
+       {
+               if(strcmp(SQLREQID, request->GetId()) == 0)
+               {
+                       SQLrequest* req = (SQLrequest*)request;
+
+                       /* XXX: Lock */
+                       pthread_mutex_lock(&queue_mutex);
+
+                       ConnMap::iterator iter;
+
+                       char* returnval = NULL;
+
+                       if((iter = Connections.find(req->dbid)) != Connections.end())
+                       {
+                               req->id = NewID();
+                               iter->second->queue.push(*req);
+                               returnval = SQLSUCCESS;
+                       }
+                       else
+                       {
+                               req->error.Id(BAD_DBID);
+                       }
+
+                       pthread_mutex_unlock(&queue_mutex);
+                       /* XXX: Unlock */
+
+                       return returnval;
+               }
+
+               return NULL;
+       }
+
+       virtual void OnRehash(userrec* user, const std::string &parameter)
+       {
+               rehashing = true;
+       }
+       
+       virtual Version GetVersion()
+       {
+               return Version(1,1,0,0,VF_VENDOR|VF_SERVICEPROVIDER,API_VERSION);
+       }
+       
+};
+
+void* DispatcherThread(void* arg)
+{
+       ModuleSQL* thismodule = (ModuleSQL*)arg;
+       LoadDatabases(thismodule->Conf, thismodule->PublicServerInstance);
+
+       /* Connect back to the Notifier */
+
+       if ((QueueFD = socket(AF_FAMILY, SOCK_STREAM, 0)) == -1)
+       {
+               /* crap, we're out of sockets... */
+               return NULL;
+       }
+
+       insp_sockaddr addr;
+
+#ifdef IPV6
+       insp_aton("::1", &addr.sin6_addr);
+       addr.sin6_family = AF_FAMILY;
+       addr.sin6_port = htons(MessagePipe->GetPort());
+#else
+       insp_inaddr ia;
+       insp_aton("127.0.0.1", &ia);
+       addr.sin_family = AF_FAMILY;
+       addr.sin_addr = ia;
+       addr.sin_port = htons(MessagePipe->GetPort());
+#endif
+
+       if (connect(QueueFD, (sockaddr*)&addr,sizeof(addr)) == -1)
+       {
+               /* wtf, we cant connect to it, but we just created it! */
+               return NULL;
+       }
+
+       while (!giveup)
+       {
+               if (thismodule->rehashing)
+               {
+               /* XXX: Lock */
+                       pthread_mutex_lock(&queue_mutex);
+                       thismodule->rehashing = false;
+                       LoadDatabases(thismodule->Conf, thismodule->PublicServerInstance);
+                       pthread_mutex_unlock(&queue_mutex);
+                       /* XXX: Unlock */
+               }
+
+               SQLConnection* conn = NULL;
+               /* XXX: Lock here for safety */
+               pthread_mutex_lock(&queue_mutex);
+               for (ConnMap::iterator i = Connections.begin(); i != Connections.end(); i++)
+               {
+                       if (i->second->queue.totalsize())
+                       {
+                               conn = i->second;
+                               break;
+                       }
+               }
+               pthread_mutex_unlock(&queue_mutex);
+               /* XXX: Unlock */
+
+               /* Theres an item! */
+               if (conn)
+               {
+                       conn->DoLeadingQuery();
+
+                       /* XXX: Lock */
+                       pthread_mutex_lock(&queue_mutex);
+                       conn->queue.pop();
+                       pthread_mutex_unlock(&queue_mutex);
+                       /* XXX: Unlock */
+               }
+
+               usleep(50);
+       }
+
+       return NULL;
+}
+
+MODULE_INIT(ModuleSQL);
+
index 9e85a40deace9c7d045fa5d095f8457b61bbc27c..5d267fc1acce29f481a414efc7aa3c12ecaa3201 100644 (file)
@@ -1 +1,984 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include <cstdlib>\r#include <sstream>\r#include <libpq-fe.h>\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r#include "configreader.h"\r#include "m_sqlv2.h"\r\r/* $ModDesc: PostgreSQL Service Provider module for all other m_sql* modules, uses v2 of the SQL API */\r/* $CompileFlags: -Iexec("pg_config --includedir") eval("my $s = `pg_config --version`;$s =~ /^.*?(\d+)\.(\d+)\.(\d+).*?$/;my $v = hex(sprintf("0x%02x%02x%02x", $1, $2, $3));print "-DPGSQL_HAS_ESCAPECONN" if(($v >= 0x080104) || ($v >= 0x07030F && $v < 0x070400) || ($v >= 0x07040D && $v < 0x080000) || ($v >= 0x080008 && $v < 0x080100));") */\r/* $LinkerFlags: -Lexec("pg_config --libdir") -lpq */\r/* $ModDep: m_sqlv2.h */\r\r\r/* SQLConn rewritten by peavey to\r * use EventHandler instead of\r * InspSocket. This is much neater\r * and gives total control of destroy\r * and delete of resources.\r */\r\r/* Forward declare, so we can have the typedef neatly at the top */\rclass SQLConn;\r\rtypedef std::map<std::string, SQLConn*> ConnMap;\r\r/* CREAD, Connecting and wants read event\r * CWRITE,      Connecting and wants write event\r * WREAD,      Connected/Working and wants read event\r * WWRITE,       Connected/Working and wants write event\r * RREAD,       Resetting and wants read event\r * RWRITE,       Resetting and wants write event\r */\renum SQLstatus { CREAD, CWRITE, WREAD, WWRITE, RREAD, RWRITE };\r\r/** SQLhost::GetDSN() - Overload to return correct DSN for PostgreSQL\r */\rstd::string SQLhost::GetDSN()\r{\r std::ostringstream conninfo("connect_timeout = '2'");\r\r if (ip.length())\r               conninfo << " hostaddr = '" << ip << "'";\r\r     if (port)\r              conninfo << " port = '" << port << "'";\r\r       if (name.length())\r             conninfo << " dbname = '" << name << "'";\r\r     if (user.length())\r             conninfo << " user = '" << user << "'";\r\r       if (pass.length())\r             conninfo << " password = '" << pass << "'";\r\r   if (ssl)\r       {\r              conninfo << " sslmode = 'require'";\r    }\r      else\r   {\r              conninfo << " sslmode = 'disable'";\r    }\r\r     return conninfo.str();\r}\r\rclass ReconnectTimer : public InspTimer\r{\r  private:\r Module* mod;\r  public:\r ReconnectTimer(InspIRCd* SI, Module* m)\r        : InspTimer(5, SI->Time(), false), mod(m)\r      {\r      }\r      virtual void Tick(time_t TIME);\r};\r\r\r/** Used to resolve sql server hostnames\r */\rclass SQLresolver : public Resolver\r{\r private:\r      SQLhost host;\r  Module* mod;\r public:\r  SQLresolver(Module* m, InspIRCd* Instance, const SQLhost& hi, bool &cached)\r    : Resolver(Instance, hi.host, DNS_QUERY_FORWARD, cached, (Module*)m), host(hi), mod(m)\r {\r      }\r\r     virtual void OnLookupComplete(const std::string &result, unsigned int ttl, bool cached);\r\r      virtual void OnError(ResolverError e, const std::string &errormessage)\r {\r              ServerInstance->Log(DEBUG, "PgSQL: DNS lookup failed (%s), dying horribly", errormessage.c_str());\r     }\r};\r\r/** PgSQLresult is a subclass of the mostly-pure-virtual class SQLresult.\r * All SQL providers must create their own subclass and define it's methods using that\r * database library's data retriveal functions. The aim is to avoid a slow and inefficient process\r * of converting all data to a common format before it reaches the result structure. This way\r * data is passes to the module nearly as directly as if it was using the API directly itself.\r */\r\rclass PgSQLresult : public SQLresult\r{\r     PGresult* res;\r int currentrow;\r        int rows;\r      int cols;\r\r     SQLfieldList* fieldlist;\r       SQLfieldMap* fieldmap;\rpublic:\r PgSQLresult(Module* self, Module* to, unsigned long id, PGresult* result)\r      : SQLresult(self, to, id), res(result), currentrow(0), fieldlist(NULL), fieldmap(NULL)\r {\r              rows = PQntuples(res);\r         cols = PQnfields(res);\r }\r\r     ~PgSQLresult()\r {\r              /* If we allocated these, free them... */\r              if(fieldlist)\r                  DELETE(fieldlist);\r\r            if(fieldmap)\r                   DELETE(fieldmap);\r\r             PQclear(res);\r  }\r\r     virtual int Rows()\r     {\r              if(!cols && !rows)\r             {\r                      return atoi(PQcmdTuples(res));\r         }\r              else\r           {\r                      return rows;\r           }\r      }\r\r     virtual int Cols()\r     {\r              return PQnfields(res);\r }\r\r     virtual std::string ColName(int column)\r        {\r              char* name = PQfname(res, column);\r\r            return (name) ? name : "";\r     }\r\r     virtual int ColNum(const std::string &column)\r  {\r              int n = PQfnumber(res, column.c_str());\r\r               if(n == -1)\r            {\r                      throw SQLbadColName();\r         }\r              else\r           {\r                      return n;\r              }\r      }\r\r     virtual SQLfield GetValue(int row, int column)\r {\r              char* v = PQgetvalue(res, row, column);\r\r               if(v)\r          {\r                      return SQLfield(std::string(v, PQgetlength(res, row, column)), PQgetisnull(res, row, column));\r         }\r              else\r           {\r                      throw SQLbadColName();\r         }\r      }\r\r     virtual SQLfieldList& GetRow()\r {\r              /* In an effort to reduce overhead we don't actually allocate the list\r          * until the first time it's needed...so...\r             */\r            if(fieldlist)\r          {\r                      fieldlist->clear();\r            }\r              else\r           {\r                      fieldlist = new SQLfieldList;\r          }\r\r             if(currentrow < PQntuples(res))\r                {\r                      int cols = PQnfields(res);\r\r                    for(int i = 0; i < cols; i++)\r                  {\r                              fieldlist->push_back(GetValue(currentrow, i));\r                 }\r\r                     currentrow++;\r          }\r\r             return *fieldlist;\r     }\r\r     virtual SQLfieldMap& GetRowMap()\r       {\r              /* In an effort to reduce overhead we don't actually allocate the map\r           * until the first time it's needed...so...\r             */\r            if(fieldmap)\r           {\r                      fieldmap->clear();\r             }\r              else\r           {\r                      fieldmap = new SQLfieldMap;\r            }\r\r             if(currentrow < PQntuples(res))\r                {\r                      int cols = PQnfields(res);\r\r                    for(int i = 0; i < cols; i++)\r                  {\r                              fieldmap->insert(std::make_pair(ColName(i), GetValue(currentrow, i)));\r                 }\r\r                     currentrow++;\r          }\r\r             return *fieldmap;\r      }\r\r     virtual SQLfieldList* GetRowPtr()\r      {\r              SQLfieldList* fl = new SQLfieldList;\r\r          if(currentrow < PQntuples(res))\r                {\r                      int cols = PQnfields(res);\r\r                    for(int i = 0; i < cols; i++)\r                  {\r                              fl->push_back(GetValue(currentrow, i));\r                        }\r\r                     currentrow++;\r          }\r\r             return fl;\r     }\r\r     virtual SQLfieldMap* GetRowMapPtr()\r    {\r              SQLfieldMap* fm = new SQLfieldMap;\r\r            if(currentrow < PQntuples(res))\r                {\r                      int cols = PQnfields(res);\r\r                    for(int i = 0; i < cols; i++)\r                  {\r                              fm->insert(std::make_pair(ColName(i), GetValue(currentrow, i)));\r                       }\r\r                     currentrow++;\r          }\r\r             return fm;\r     }\r\r     virtual void Free(SQLfieldMap* fm)\r     {\r              DELETE(fm);\r    }\r\r     virtual void Free(SQLfieldList* fl)\r    {\r              DELETE(fl);\r    }\r};\r\r/** SQLConn represents one SQL session.\r */\rclass SQLConn : public EventHandler\r{\r  private:\r     InspIRCd*               Instance;\r      SQLhost                 confhost;       /* The <database> entry */\r     Module*                 us;                     /* Pointer to the SQL provider itself */\r       PGconn*                 sql;            /* PgSQL database connection handle */\r SQLstatus               status;         /* PgSQL database connection status */\r bool                    qinprog;        /* If there is currently a query in progress */\r        QueryQueue              queue;          /* Queue of queries waiting to be executed on this connection */\r       time_t                  idle;           /* Time we last heard from the database */\r\r  public:\r  SQLConn(InspIRCd* SI, Module* self, const SQLhost& hi)\r : EventHandler(), Instance(SI), confhost(hi), us(self), sql(NULL), status(CWRITE), qinprog(false)\r      {\r              idle = this->Instance->Time();\r         if(!DoConnect())\r               {\r                      Instance->Log(DEFAULT, "WARNING: Could not connect to database with id: " + ConvToStr(hi.id));\r                 DelayReconnect();\r              }\r      }\r\r     ~SQLConn()\r     {\r              Close();\r       }\r\r     virtual void HandleEvent(EventType et, int errornum)\r   {\r              switch (et)\r            {\r                      case EVENT_READ:\r                               OnDataReady();\r                 break;\r\r                        case EVENT_WRITE:\r                              OnWriteReady();\r                        break;\r\r                        case EVENT_ERROR:\r                              DelayReconnect();\r                      break;\r\r                        default:\r                       break;\r         }\r      }\r\r     bool DoConnect()\r       {\r              if(!(sql = PQconnectStart(confhost.GetDSN().c_str())))\r                 return false;\r\r         if(PQstatus(sql) == CONNECTION_BAD)\r                    return false;\r\r         if(PQsetnonblocking(sql, 1) == -1)\r                     return false;\r\r         /* OK, we've initalised the connection, now to get it hooked into the socket engine\r            * and then start polling it.\r           */\r             this->fd = PQsocket(sql);\r\r             if(this->fd <= -1)\r                     return false;\r\r         if (!this->Instance->SE->AddFd(this))\r          {\r                      Instance->Log(DEBUG, "BUG: Couldn't add pgsql socket to socket engine");\r                       return false;\r          }\r\r             /* Socket all hooked into the engine, now to tell PgSQL to start connecting */\r         return DoPoll();\r       }\r\r     bool DoPoll()\r  {\r              switch(PQconnectPoll(sql))\r             {\r                      case PGRES_POLLING_WRITING:\r                            Instance->SE->WantWrite(this);\r                         status = CWRITE;\r                               return true;\r                   case PGRES_POLLING_READING:\r                            status = CREAD;\r                                return true;\r                   case PGRES_POLLING_FAILED:\r                             return false;\r                  case PGRES_POLLING_OK:\r                         status = WWRITE;\r                               return DoConnectedPoll();\r                      default:\r                               return true;\r           }\r      }\r\r     bool DoConnectedPoll()\r {\r              if(!qinprog && queue.totalsize())\r              {\r                      /* There's no query currently in progress, and there's queries in the queue. */\r                        SQLrequest& query = queue.front();\r                     DoQuery(query);\r                }\r\r             if(PQconsumeInput(sql))\r                {\r                      /* We just read stuff from the server, that counts as it being alive\r                    * so update the idle-since time :p\r                     */\r                    idle = this->Instance->Time();\r\r                        if (PQisBusy(sql))\r                     {\r                              /* Nothing happens here */\r                     }\r                      else if (qinprog)\r                      {\r                              /* Grab the request we're processing */\r                                SQLrequest& query = queue.front();\r\r                            /* Get a pointer to the module we're about to return the result to */\r                          Module* to = query.GetSource();\r\r                               /* Fetch the result.. */\r                               PGresult* result = PQgetResult(sql);\r\r                          /* PgSQL would allow a query string to be sent which has multiple\r                               * queries in it, this isn't portable across database backends and\r                              * we don't want modules doing it. But just in case we make sure we\r                             * drain any results there are and just use the last one.\r                               * If the module devs are behaving there will only be one result.\r                               */\r                            while (PGresult* temp = PQgetResult(sql))\r                              {\r                                      PQclear(result);\r                                       result = temp;\r                         }\r\r                             if(to)\r                         {\r                                      /* ..and the result */\r                                 PgSQLresult reply(us, to, query.id, result);\r\r                                  /* Fix by brain, make sure the original query gets sent back in the reply */\r                                   reply.query = query.query.q;\r\r                                  switch(PQresultStatus(result))\r                                 {\r                                              case PGRES_EMPTY_QUERY:\r                                                case PGRES_BAD_RESPONSE:\r                                               case PGRES_FATAL_ERROR:\r                                                        reply.error.Id(QREPLY_FAIL);\r                                                   reply.error.Str(PQresultErrorMessage(result));\r                                         default:;\r                                                      /* No action, other values are not errors */\r                                   }\r\r                                     reply.Send();\r\r                                 /* PgSQLresult's destructor will free the PGresult */\r                          }\r                              else\r                           {\r                                      /* If the client module is unloaded partway through a query then the provider will set\r                                  * the pointer to NULL. We cannot just cancel the query as the result will still come\r                                   * through at some point...and it could get messy if we play with invalid pointers...\r                                   */\r                                    PQclear(result);\r                               }\r                              qinprog = false;\r                               queue.pop();\r                           DoConnectedPoll();\r                     }\r                      return true;\r           }\r              else\r           {\r                      /* I think we'll assume this means the server died...it might not,\r                      * but I think that any error serious enough we actually get here\r                       * deserves to reconnect [/excuse]\r                      * Returning true so the core doesn't try and close the connection.\r                     */\r                    DelayReconnect();\r                      return true;\r           }\r      }\r\r     bool DoResetPoll()\r     {\r              switch(PQresetPoll(sql))\r               {\r                      case PGRES_POLLING_WRITING:\r                            Instance->SE->WantWrite(this);\r                         status = CWRITE;\r                               return DoPoll();\r                       case PGRES_POLLING_READING:\r                            status = CREAD;\r                                return true;\r                   case PGRES_POLLING_FAILED:\r                             return false;\r                  case PGRES_POLLING_OK:\r                         status = WWRITE;\r                               return DoConnectedPoll();\r                      default:\r                               return true;\r           }\r      }\r\r     bool OnDataReady()\r     {\r              /* Always return true here, false would close the socket - we need to do that ourselves with the pgsql API */\r          return DoEvent();\r      }\r\r     bool OnWriteReady()\r    {\r              /* Always return true here, false would close the socket - we need to do that ourselves with the pgsql API */\r          return DoEvent();\r      }\r\r     bool OnConnected()\r     {\r              return DoEvent();\r      }\r\r     void DelayReconnect();\r\r        bool DoEvent()\r {\r              bool ret;\r\r             if((status == CREAD) || (status == CWRITE))\r            {\r                      ret = DoPoll();\r                }\r              else if((status == RREAD) || (status == RWRITE))\r               {\r                      ret = DoResetPoll();\r           }\r              else\r           {\r                      ret = DoConnectedPoll();\r               }\r              return ret;\r    }\r\r     SQLerror DoQuery(SQLrequest &req)\r      {\r              if((status == WREAD) || (status == WWRITE))\r            {\r                      if(!qinprog)\r                   {\r                              /* Parse the command string and dispatch it */\r\r                                /* Pointer to the buffer we screw around with substitution in */\r                               char* query;\r                           /* Pointer to the current end of query, where we append new stuff */\r                           char* queryend;\r                                /* Total length of the unescaped parameters */\r                         unsigned int paramlen;\r\r                                paramlen = 0;\r\r                         for(ParamL::iterator i = req.query.p.begin(); i != req.query.p.end(); i++)\r                             {\r                                      paramlen += i->size();\r                         }\r\r                             /* To avoid a lot of allocations, allocate enough memory for the biggest the escaped query could possibly be.\r                           * sizeofquery + (totalparamlength*2) + 1\r                               *\r                              * The +1 is for null-terminating the string for PQsendQuery()\r                          */\r\r                           query = new char[req.query.q.length() + (paramlen*2) + 1];\r                             queryend = query;\r\r                             /* Okay, now we have a buffer large enough we need to start copying the query into it and escaping and substituting\r                             * the parameters into it...\r                            */\r\r                           for(unsigned int i = 0; i < req.query.q.length(); i++)\r                         {\r                                      if(req.query.q[i] == '?')\r                                      {\r                                              /* We found a place to substitute..what fun.\r                                            * Use the PgSQL calls to escape and write the\r                                          * escaped string onto the end of our query buffer,\r                                             * then we "just" need to make sure queryend is\r                                                 * pointing at the right place.\r                                                 */\r\r                                           if(req.query.p.size())\r                                         {\r                                                      int error = 0;\r                                                 size_t len = 0;\r\r#ifdef PGSQL_HAS_ESCAPECONN\r                                                   len = PQescapeStringConn(sql, queryend, req.query.p.front().c_str(), req.query.p.front().length(), &error);\r#else\r                                                      len = PQescapeString         (queryend, req.query.p.front().c_str(), req.query.p.front().length());\r#endif\r                                                     if(error)\r                                                      {\r                                                              Instance->Log(DEBUG, "BUG: Apparently PQescapeStringConn() failed somehow...don't know how or what to do...");\r                                                 }\r\r                                                     /* Incremenet queryend to the end of the newly escaped parameter */\r                                                    queryend += len;\r\r                                                      /* Remove the parameter we just substituted in */\r                                                      req.query.p.pop_front();\r                                               }\r                                              else\r                                           {\r                                                      Instance->Log(DEBUG, "BUG: Found a substitution location but no parameter to substitute :|");\r                                                  break;\r                                         }\r                                      }\r                                      else\r                                   {\r                                              *queryend = req.query.q[i];\r                                            queryend++;\r                                    }\r                              }\r\r                             /* Null-terminate the query */\r                         *queryend = 0;\r                         req.query.q = query;\r\r                          if(PQsendQuery(sql, query))\r                            {\r                                      qinprog = true;\r                                        delete[] query;\r                                        return SQLerror();\r                             }\r                              else\r                           {\r                                      delete[] query;\r                                        return SQLerror(QSEND_FAIL, PQerrorMessage(sql));\r                              }\r                      }\r              }\r              return SQLerror(BAD_CONN, "Can't query until connection is complete");\r }\r\r     SQLerror Query(const SQLrequest &req)\r  {\r              queue.push(req);\r\r              if(!qinprog && queue.totalsize())\r              {\r                      /* There's no query currently in progress, and there's queries in the queue. */\r                        SQLrequest& query = queue.front();\r                     return DoQuery(query);\r         }\r              else\r           {\r                      return SQLerror();\r             }\r      }\r\r     void OnUnloadModule(Module* mod)\r       {\r              queue.PurgeModule(mod);\r        }\r\r     const SQLhost GetConfHost()\r    {\r              return confhost;\r       }\r\r     void Close() {\r         if (!this->Instance->SE->DelFd(this))\r          {\r                      if (sql && PQstatus(sql) == CONNECTION_BAD)\r                    {\r                              this->Instance->SE->DelFd(this, true);\r                 }\r                      else\r                   {\r                              Instance->Log(DEBUG, "BUG: PQsocket cant be removed from socket engine!");\r                     }\r              }\r\r             if(sql)\r                {\r                      PQfinish(sql);\r                 sql = NULL;\r            }\r      }\r\r};\r\rclass ModulePgSQL : public Module\r{\r  private:\r  ConnMap connections;\r   unsigned long currid;\r  char* sqlsuccess;\r      ReconnectTimer* retimer;\r\r  public:\r    ModulePgSQL(InspIRCd* Me)\r      : Module::Module(Me), currid(0)\r        {\r              ServerInstance->UseInterface("SQLutils");\r\r             sqlsuccess = new char[strlen(SQLSUCCESS)+1];\r\r          strlcpy(sqlsuccess, SQLSUCCESS, strlen(SQLSUCCESS));\r\r          if (!ServerInstance->PublishFeature("SQL", this))\r              {\r                      throw ModuleException("BUG: PgSQL Unable to publish feature 'SQL'");\r           }\r\r             ReadConf();\r\r           ServerInstance->PublishInterface("SQL", this);\r }\r\r     virtual ~ModulePgSQL()\r {\r              if (retimer)\r                   ServerInstance->Timers->DelTimer(retimer);\r             ClearAllConnections();\r         delete[] sqlsuccess;\r           ServerInstance->UnpublishInterface("SQL", this);\r               ServerInstance->UnpublishFeature("SQL");\r               ServerInstance->DoneWithInterface("SQLutils");\r }\r\r     void Implements(char* List)\r    {\r              List[I_OnUnloadModule] = List[I_OnRequest] = List[I_OnRehash] = List[I_OnUserRegister] = List[I_OnCheckReady] = List[I_OnUserDisconnect] = 1;\r  }\r\r     virtual void OnRehash(userrec* user, const std::string &parameter)\r     {\r              ReadConf();\r    }\r\r     bool HasHost(const SQLhost &host)\r      {\r              for (ConnMap::iterator iter = connections.begin(); iter != connections.end(); iter++)\r          {\r                      if (host == iter->second->GetConfHost())\r                               return true;\r           }\r              return false;\r  }\r\r     bool HostInConf(const SQLhost &h)\r      {\r              ConfigReader conf(ServerInstance);\r             for(int i = 0; i < conf.Enumerate("database"); i++)\r            {\r                      SQLhost host;\r                  host.id         = conf.ReadValue("database", "id", i);\r                 host.host       = conf.ReadValue("database", "hostname", i);\r                   host.port       = conf.ReadInteger("database", "port", i, true);\r                       host.name       = conf.ReadValue("database", "name", i);\r                       host.user       = conf.ReadValue("database", "username", i);\r                   host.pass       = conf.ReadValue("database", "password", i);\r                   host.ssl        = conf.ReadFlag("database", "ssl", "0", i);\r                    if (h == host)\r                         return true;\r           }\r              return false;\r  }\r\r     void ReadConf()\r        {\r              ClearOldConnections();\r\r                ConfigReader conf(ServerInstance);\r             for(int i = 0; i < conf.Enumerate("database"); i++)\r            {\r                      SQLhost host;\r                  int ipvalid;\r\r                  host.id         = conf.ReadValue("database", "id", i);\r                 host.host       = conf.ReadValue("database", "hostname", i);\r                   host.port       = conf.ReadInteger("database", "port", i, true);\r                       host.name       = conf.ReadValue("database", "name", i);\r                       host.user       = conf.ReadValue("database", "username", i);\r                   host.pass       = conf.ReadValue("database", "password", i);\r                   host.ssl        = conf.ReadFlag("database", "ssl", "0", i);\r\r                   if (HasHost(host))\r                             continue;\r\r#ifdef IPV6\r                 if (strchr(host.host.c_str(),':'))\r                     {\r                              in6_addr blargle;\r                              ipvalid = inet_pton(AF_INET6, host.host.c_str(), &blargle);\r                    }\r                      else\r#endif\r                    {\r                              in_addr blargle;\r                               ipvalid = inet_aton(host.host.c_str(), &blargle);\r                      }\r\r                     if(ipvalid > 0)\r                        {\r                              /* The conversion succeeded, we were given an IP and we can give it straight to SQLConn */\r                             host.ip = host.host;\r                           this->AddConn(host);\r                   }\r                      else if(ipvalid == 0)\r                  {\r                              /* Conversion failed, assume it's a host */\r                            SQLresolver* resolver;\r\r                                try\r                            {\r                                      bool cached;\r                                   resolver = new SQLresolver(this, ServerInstance, host, cached);\r                                        ServerInstance->AddResolver(resolver, cached);\r                         }\r                              catch(...)\r                             {\r                                      /* THE WORLD IS COMING TO AN END! */\r                           }\r                      }\r                      else\r                   {\r                              /* Invalid address family, die horribly. */\r                            ServerInstance->Log(DEBUG, "BUG: insp_aton failed returning -1, oh noes.");\r                    }\r              }\r      }\r\r     void ClearOldConnections()\r     {\r              ConnMap::iterator iter,safei;\r          for (iter = connections.begin(); iter != connections.end(); iter++)\r            {\r                      if (!HostInConf(iter->second->GetConfHost()))\r                  {\r                              DELETE(iter->second);\r                          safei = iter;\r                          --iter;\r                                connections.erase(safei);\r                      }\r              }\r      }\r\r     void ClearAllConnections()\r     {\r              ConnMap::iterator i;\r           while ((i = connections.begin()) != connections.end())\r         {\r                      connections.erase(i);\r                  DELETE(i->second);\r             }\r      }\r\r     void AddConn(const SQLhost& hi)\r        {\r              if (HasHost(hi))\r               {\r                      ServerInstance->Log(DEFAULT, "WARNING: A pgsql connection with id: %s already exists, possibly due to DNS delay. Aborting connection attempt.", hi.id.c_str());\r                        return;\r                }\r\r             SQLConn* newconn;\r\r             /* The conversion succeeded, we were given an IP and we can give it straight to SQLConn */\r             newconn = new SQLConn(ServerInstance, this, hi);\r\r              connections.insert(std::make_pair(hi.id, newconn));\r    }\r\r     void ReconnectConn(SQLConn* conn)\r      {\r              for (ConnMap::iterator iter = connections.begin(); iter != connections.end(); iter++)\r          {\r                      if (conn == iter->second)\r                      {\r                              DELETE(iter->second);\r                          connections.erase(iter);\r                               break;\r                 }\r              }\r              retimer = new ReconnectTimer(ServerInstance, this);\r            ServerInstance->Timers->AddTimer(retimer);\r     }\r\r     virtual char* OnRequest(Request* request)\r      {\r              if(strcmp(SQLREQID, request->GetId()) == 0)\r            {\r                      SQLrequest* req = (SQLrequest*)request;\r                        ConnMap::iterator iter;\r                        if((iter = connections.find(req->dbid)) != connections.end())\r                  {\r                              /* Execute query */\r                            req->id = NewID();\r                             req->error = iter->second->Query(*req);\r\r                               return (req->error.Id() == NO_ERROR) ? sqlsuccess : NULL;\r                      }\r                      else\r                   {\r                              req->error.Id(BAD_DBID);\r                               return NULL;\r                   }\r              }\r              return NULL;\r   }\r\r     virtual void OnUnloadModule(Module* mod, const std::string&     name)\r  {\r              /* When a module unloads we have to check all the pending queries for all our connections\r               * and set the Module* specifying where the query came from to NULL. If the query has already\r           * been dispatched then when it is processed it will be dropped if the pointer is NULL.\r                 *\r              * If the queries we find are not already being executed then we can simply remove them immediately.\r            */\r            for(ConnMap::iterator iter = connections.begin(); iter != connections.end(); iter++)\r           {\r                      iter->second->OnUnloadModule(mod);\r             }\r      }\r\r     unsigned long NewID()\r  {\r              if (currid+1 == 0)\r                     currid++;\r\r             return ++currid;\r       }\r\r     virtual Version GetVersion()\r   {\r              return Version(1, 1, 0, 0, VF_VENDOR|VF_SERVICEPROVIDER, API_VERSION);\r }\r};\r\r/* move this here to use AddConn, rather that than having the whole\r * module above SQLConn, since this is buggin me right now :/\r */\rvoid SQLresolver::OnLookupComplete(const std::string &result, unsigned int ttl, bool cached)\r{\r     host.ip = result;\r      ((ModulePgSQL*)mod)->AddConn(host);\r    ((ModulePgSQL*)mod)->ClearOldConnections();\r}\r\rvoid ReconnectTimer::Tick(time_t time)\r{\r        ((ModulePgSQL*)mod)->ReadConf();\r}\r\rvoid SQLConn::DelayReconnect()\r{\r   ((ModulePgSQL*)us)->ReconnectConn(this);\r}\r\rMODULE_INIT(ModulePgSQL);\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include <cstdlib>
+#include <sstream>
+#include <libpq-fe.h>
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+#include "configreader.h"
+#include "m_sqlv2.h"
+
+/* $ModDesc: PostgreSQL Service Provider module for all other m_sql* modules, uses v2 of the SQL API */
+/* $CompileFlags: -Iexec("pg_config --includedir") eval("my $s = `pg_config --version`;$s =~ /^.*?(\d+)\.(\d+)\.(\d+).*?$/;my $v = hex(sprintf("0x%02x%02x%02x", $1, $2, $3));print "-DPGSQL_HAS_ESCAPECONN" if(($v >= 0x080104) || ($v >= 0x07030F && $v < 0x070400) || ($v >= 0x07040D && $v < 0x080000) || ($v >= 0x080008 && $v < 0x080100));") */
+/* $LinkerFlags: -Lexec("pg_config --libdir") -lpq */
+/* $ModDep: m_sqlv2.h */
+
+
+/* SQLConn rewritten by peavey to
+ * use EventHandler instead of
+ * InspSocket. This is much neater
+ * and gives total control of destroy
+ * and delete of resources.
+ */
+
+/* Forward declare, so we can have the typedef neatly at the top */
+class SQLConn;
+
+typedef std::map<std::string, SQLConn*> ConnMap;
+
+/* CREAD,      Connecting and wants read event
+ * CWRITE,     Connecting and wants write event
+ * WREAD,      Connected/Working and wants read event
+ * WWRITE,     Connected/Working and wants write event
+ * RREAD,      Resetting and wants read event
+ * RWRITE,     Resetting and wants write event
+ */
+enum SQLstatus { CREAD, CWRITE, WREAD, WWRITE, RREAD, RWRITE };
+
+/** SQLhost::GetDSN() - Overload to return correct DSN for PostgreSQL
+ */
+std::string SQLhost::GetDSN()
+{
+       std::ostringstream conninfo("connect_timeout = '2'");
+
+       if (ip.length())
+               conninfo << " hostaddr = '" << ip << "'";
+
+       if (port)
+               conninfo << " port = '" << port << "'";
+
+       if (name.length())
+               conninfo << " dbname = '" << name << "'";
+
+       if (user.length())
+               conninfo << " user = '" << user << "'";
+
+       if (pass.length())
+               conninfo << " password = '" << pass << "'";
+
+       if (ssl)
+       {
+               conninfo << " sslmode = 'require'";
+       }
+       else
+       {
+               conninfo << " sslmode = 'disable'";
+       }
+
+       return conninfo.str();
+}
+
+class ReconnectTimer : public InspTimer
+{
+  private:
+       Module* mod;
+  public:
+       ReconnectTimer(InspIRCd* SI, Module* m)
+       : InspTimer(5, SI->Time(), false), mod(m)
+       {
+       }
+       virtual void Tick(time_t TIME);
+};
+
+
+/** Used to resolve sql server hostnames
+ */
+class SQLresolver : public Resolver
+{
+ private:
+       SQLhost host;
+       Module* mod;
+ public:
+       SQLresolver(Module* m, InspIRCd* Instance, const SQLhost& hi, bool &cached)
+       : Resolver(Instance, hi.host, DNS_QUERY_FORWARD, cached, (Module*)m), host(hi), mod(m)
+       {
+       }
+
+       virtual void OnLookupComplete(const std::string &result, unsigned int ttl, bool cached);
+
+       virtual void OnError(ResolverError e, const std::string &errormessage)
+       {
+               ServerInstance->Log(DEBUG, "PgSQL: DNS lookup failed (%s), dying horribly", errormessage.c_str());
+       }
+};
+
+/** PgSQLresult is a subclass of the mostly-pure-virtual class SQLresult.
+ * All SQL providers must create their own subclass and define it's methods using that
+ * database library's data retriveal functions. The aim is to avoid a slow and inefficient process
+ * of converting all data to a common format before it reaches the result structure. This way
+ * data is passes to the module nearly as directly as if it was using the API directly itself.
+ */
+
+class PgSQLresult : public SQLresult
+{
+       PGresult* res;
+       int currentrow;
+       int rows;
+       int cols;
+
+       SQLfieldList* fieldlist;
+       SQLfieldMap* fieldmap;
+public:
+       PgSQLresult(Module* self, Module* to, unsigned long id, PGresult* result)
+       : SQLresult(self, to, id), res(result), currentrow(0), fieldlist(NULL), fieldmap(NULL)
+       {
+               rows = PQntuples(res);
+               cols = PQnfields(res);
+       }
+
+       ~PgSQLresult()
+       {
+               /* If we allocated these, free them... */
+               if(fieldlist)
+                       DELETE(fieldlist);
+
+               if(fieldmap)
+                       DELETE(fieldmap);
+
+               PQclear(res);
+       }
+
+       virtual int Rows()
+       {
+               if(!cols && !rows)
+               {
+                       return atoi(PQcmdTuples(res));
+               }
+               else
+               {
+                       return rows;
+               }
+       }
+
+       virtual int Cols()
+       {
+               return PQnfields(res);
+       }
+
+       virtual std::string ColName(int column)
+       {
+               char* name = PQfname(res, column);
+
+               return (name) ? name : "";
+       }
+
+       virtual int ColNum(const std::string &column)
+       {
+               int n = PQfnumber(res, column.c_str());
+
+               if(n == -1)
+               {
+                       throw SQLbadColName();
+               }
+               else
+               {
+                       return n;
+               }
+       }
+
+       virtual SQLfield GetValue(int row, int column)
+       {
+               char* v = PQgetvalue(res, row, column);
+
+               if(v)
+               {
+                       return SQLfield(std::string(v, PQgetlength(res, row, column)), PQgetisnull(res, row, column));
+               }
+               else
+               {
+                       throw SQLbadColName();
+               }
+       }
+
+       virtual SQLfieldList& GetRow()
+       {
+               /* In an effort to reduce overhead we don't actually allocate the list
+                * until the first time it's needed...so...
+                */
+               if(fieldlist)
+               {
+                       fieldlist->clear();
+               }
+               else
+               {
+                       fieldlist = new SQLfieldList;
+               }
+
+               if(currentrow < PQntuples(res))
+               {
+                       int cols = PQnfields(res);
+
+                       for(int i = 0; i < cols; i++)
+                       {
+                               fieldlist->push_back(GetValue(currentrow, i));
+                       }
+
+                       currentrow++;
+               }
+
+               return *fieldlist;
+       }
+
+       virtual SQLfieldMap& GetRowMap()
+       {
+               /* In an effort to reduce overhead we don't actually allocate the map
+                * until the first time it's needed...so...
+                */
+               if(fieldmap)
+               {
+                       fieldmap->clear();
+               }
+               else
+               {
+                       fieldmap = new SQLfieldMap;
+               }
+
+               if(currentrow < PQntuples(res))
+               {
+                       int cols = PQnfields(res);
+
+                       for(int i = 0; i < cols; i++)
+                       {
+                               fieldmap->insert(std::make_pair(ColName(i), GetValue(currentrow, i)));
+                       }
+
+                       currentrow++;
+               }
+
+               return *fieldmap;
+       }
+
+       virtual SQLfieldList* GetRowPtr()
+       {
+               SQLfieldList* fl = new SQLfieldList;
+
+               if(currentrow < PQntuples(res))
+               {
+                       int cols = PQnfields(res);
+
+                       for(int i = 0; i < cols; i++)
+                       {
+                               fl->push_back(GetValue(currentrow, i));
+                       }
+
+                       currentrow++;
+               }
+
+               return fl;
+       }
+
+       virtual SQLfieldMap* GetRowMapPtr()
+       {
+               SQLfieldMap* fm = new SQLfieldMap;
+
+               if(currentrow < PQntuples(res))
+               {
+                       int cols = PQnfields(res);
+
+                       for(int i = 0; i < cols; i++)
+                       {
+                               fm->insert(std::make_pair(ColName(i), GetValue(currentrow, i)));
+                       }
+
+                       currentrow++;
+               }
+
+               return fm;
+       }
+
+       virtual void Free(SQLfieldMap* fm)
+       {
+               DELETE(fm);
+       }
+
+       virtual void Free(SQLfieldList* fl)
+       {
+               DELETE(fl);
+       }
+};
+
+/** SQLConn represents one SQL session.
+ */
+class SQLConn : public EventHandler
+{
+  private:
+       InspIRCd*               Instance;
+       SQLhost                 confhost;       /* The <database> entry */
+       Module*                 us;                     /* Pointer to the SQL provider itself */
+       PGconn*                 sql;            /* PgSQL database connection handle */
+       SQLstatus               status;         /* PgSQL database connection status */
+       bool                    qinprog;        /* If there is currently a query in progress */
+       QueryQueue              queue;          /* Queue of queries waiting to be executed on this connection */
+       time_t                  idle;           /* Time we last heard from the database */
+
+  public:
+       SQLConn(InspIRCd* SI, Module* self, const SQLhost& hi)
+       : EventHandler(), Instance(SI), confhost(hi), us(self), sql(NULL), status(CWRITE), qinprog(false)
+       {
+               idle = this->Instance->Time();
+               if(!DoConnect())
+               {
+                       Instance->Log(DEFAULT, "WARNING: Could not connect to database with id: " + ConvToStr(hi.id));
+                       DelayReconnect();
+               }
+       }
+
+       ~SQLConn()
+       {
+               Close();
+       }
+
+       virtual void HandleEvent(EventType et, int errornum)
+       {
+               switch (et)
+               {
+                       case EVENT_READ:
+                               OnDataReady();
+                       break;
+
+                       case EVENT_WRITE:
+                               OnWriteReady();
+                       break;
+
+                       case EVENT_ERROR:
+                               DelayReconnect();
+                       break;
+
+                       default:
+                       break;
+               }
+       }
+
+       bool DoConnect()
+       {
+               if(!(sql = PQconnectStart(confhost.GetDSN().c_str())))
+                       return false;
+
+               if(PQstatus(sql) == CONNECTION_BAD)
+                       return false;
+
+               if(PQsetnonblocking(sql, 1) == -1)
+                       return false;
+
+               /* OK, we've initalised the connection, now to get it hooked into the socket engine
+               * and then start polling it.
+               */
+               this->fd = PQsocket(sql);
+
+               if(this->fd <= -1)
+                       return false;
+
+               if (!this->Instance->SE->AddFd(this))
+               {
+                       Instance->Log(DEBUG, "BUG: Couldn't add pgsql socket to socket engine");
+                       return false;
+               }
+
+               /* Socket all hooked into the engine, now to tell PgSQL to start connecting */
+               return DoPoll();
+       }
+
+       bool DoPoll()
+       {
+               switch(PQconnectPoll(sql))
+               {
+                       case PGRES_POLLING_WRITING:
+                               Instance->SE->WantWrite(this);
+                               status = CWRITE;
+                               return true;
+                       case PGRES_POLLING_READING:
+                               status = CREAD;
+                               return true;
+                       case PGRES_POLLING_FAILED:
+                               return false;
+                       case PGRES_POLLING_OK:
+                               status = WWRITE;
+                               return DoConnectedPoll();
+                       default:
+                               return true;
+               }
+       }
+
+       bool DoConnectedPoll()
+       {
+               if(!qinprog && queue.totalsize())
+               {
+                       /* There's no query currently in progress, and there's queries in the queue. */
+                       SQLrequest& query = queue.front();
+                       DoQuery(query);
+               }
+
+               if(PQconsumeInput(sql))
+               {
+                       /* We just read stuff from the server, that counts as it being alive
+                        * so update the idle-since time :p
+                        */
+                       idle = this->Instance->Time();
+
+                       if (PQisBusy(sql))
+                       {
+                               /* Nothing happens here */
+                       }
+                       else if (qinprog)
+                       {
+                               /* Grab the request we're processing */
+                               SQLrequest& query = queue.front();
+
+                               /* Get a pointer to the module we're about to return the result to */
+                               Module* to = query.GetSource();
+
+                               /* Fetch the result.. */
+                               PGresult* result = PQgetResult(sql);
+
+                               /* PgSQL would allow a query string to be sent which has multiple
+                                * queries in it, this isn't portable across database backends and
+                                * we don't want modules doing it. But just in case we make sure we
+                                * drain any results there are and just use the last one.
+                                * If the module devs are behaving there will only be one result.
+                                */
+                               while (PGresult* temp = PQgetResult(sql))
+                               {
+                                       PQclear(result);
+                                       result = temp;
+                               }
+
+                               if(to)
+                               {
+                                       /* ..and the result */
+                                       PgSQLresult reply(us, to, query.id, result);
+
+                                       /* Fix by brain, make sure the original query gets sent back in the reply */
+                                       reply.query = query.query.q;
+
+                                       switch(PQresultStatus(result))
+                                       {
+                                               case PGRES_EMPTY_QUERY:
+                                               case PGRES_BAD_RESPONSE:
+                                               case PGRES_FATAL_ERROR:
+                                                       reply.error.Id(QREPLY_FAIL);
+                                                       reply.error.Str(PQresultErrorMessage(result));
+                                               default:;
+                                                       /* No action, other values are not errors */
+                                       }
+
+                                       reply.Send();
+
+                                       /* PgSQLresult's destructor will free the PGresult */
+                               }
+                               else
+                               {
+                                       /* If the client module is unloaded partway through a query then the provider will set
+                                        * the pointer to NULL. We cannot just cancel the query as the result will still come
+                                        * through at some point...and it could get messy if we play with invalid pointers...
+                                        */
+                                       PQclear(result);
+                               }
+                               qinprog = false;
+                               queue.pop();
+                               DoConnectedPoll();
+                       }
+                       return true;
+               }
+               else
+               {
+                       /* I think we'll assume this means the server died...it might not,
+                        * but I think that any error serious enough we actually get here
+                        * deserves to reconnect [/excuse]
+                        * Returning true so the core doesn't try and close the connection.
+                        */
+                       DelayReconnect();
+                       return true;
+               }
+       }
+
+       bool DoResetPoll()
+       {
+               switch(PQresetPoll(sql))
+               {
+                       case PGRES_POLLING_WRITING:
+                               Instance->SE->WantWrite(this);
+                               status = CWRITE;
+                               return DoPoll();
+                       case PGRES_POLLING_READING:
+                               status = CREAD;
+                               return true;
+                       case PGRES_POLLING_FAILED:
+                               return false;
+                       case PGRES_POLLING_OK:
+                               status = WWRITE;
+                               return DoConnectedPoll();
+                       default:
+                               return true;
+               }
+       }
+
+       bool OnDataReady()
+       {
+               /* Always return true here, false would close the socket - we need to do that ourselves with the pgsql API */
+               return DoEvent();
+       }
+
+       bool OnWriteReady()
+       {
+               /* Always return true here, false would close the socket - we need to do that ourselves with the pgsql API */
+               return DoEvent();
+       }
+
+       bool OnConnected()
+       {
+               return DoEvent();
+       }
+
+       void DelayReconnect();
+
+       bool DoEvent()
+       {
+               bool ret;
+
+               if((status == CREAD) || (status == CWRITE))
+               {
+                       ret = DoPoll();
+               }
+               else if((status == RREAD) || (status == RWRITE))
+               {
+                       ret = DoResetPoll();
+               }
+               else
+               {
+                       ret = DoConnectedPoll();
+               }
+               return ret;
+       }
+
+       SQLerror DoQuery(SQLrequest &req)
+       {
+               if((status == WREAD) || (status == WWRITE))
+               {
+                       if(!qinprog)
+                       {
+                               /* Parse the command string and dispatch it */
+
+                               /* Pointer to the buffer we screw around with substitution in */
+                               char* query;
+                               /* Pointer to the current end of query, where we append new stuff */
+                               char* queryend;
+                               /* Total length of the unescaped parameters */
+                               unsigned int paramlen;
+
+                               paramlen = 0;
+
+                               for(ParamL::iterator i = req.query.p.begin(); i != req.query.p.end(); i++)
+                               {
+                                       paramlen += i->size();
+                               }
+
+                               /* To avoid a lot of allocations, allocate enough memory for the biggest the escaped query could possibly be.
+                                * sizeofquery + (totalparamlength*2) + 1
+                                *
+                                * The +1 is for null-terminating the string for PQsendQuery()
+                                */
+
+                               query = new char[req.query.q.length() + (paramlen*2) + 1];
+                               queryend = query;
+
+                               /* Okay, now we have a buffer large enough we need to start copying the query into it and escaping and substituting
+                                * the parameters into it...
+                                */
+
+                               for(unsigned int i = 0; i < req.query.q.length(); i++)
+                               {
+                                       if(req.query.q[i] == '?')
+                                       {
+                                               /* We found a place to substitute..what fun.
+                                                * Use the PgSQL calls to escape and write the
+                                                * escaped string onto the end of our query buffer,
+                                                * then we "just" need to make sure queryend is
+                                                * pointing at the right place.
+                                                */
+
+                                               if(req.query.p.size())
+                                               {
+                                                       int error = 0;
+                                                       size_t len = 0;
+
+#ifdef PGSQL_HAS_ESCAPECONN
+                                                       len = PQescapeStringConn(sql, queryend, req.query.p.front().c_str(), req.query.p.front().length(), &error);
+#else
+                                                       len = PQescapeString         (queryend, req.query.p.front().c_str(), req.query.p.front().length());
+#endif
+                                                       if(error)
+                                                       {
+                                                               Instance->Log(DEBUG, "BUG: Apparently PQescapeStringConn() failed somehow...don't know how or what to do...");
+                                                       }
+
+                                                       /* Incremenet queryend to the end of the newly escaped parameter */
+                                                       queryend += len;
+
+                                                       /* Remove the parameter we just substituted in */
+                                                       req.query.p.pop_front();
+                                               }
+                                               else
+                                               {
+                                                       Instance->Log(DEBUG, "BUG: Found a substitution location but no parameter to substitute :|");
+                                                       break;
+                                               }
+                                       }
+                                       else
+                                       {
+                                               *queryend = req.query.q[i];
+                                               queryend++;
+                                       }
+                               }
+
+                               /* Null-terminate the query */
+                               *queryend = 0;
+                               req.query.q = query;
+
+                               if(PQsendQuery(sql, query))
+                               {
+                                       qinprog = true;
+                                       delete[] query;
+                                       return SQLerror();
+                               }
+                               else
+                               {
+                                       delete[] query;
+                                       return SQLerror(QSEND_FAIL, PQerrorMessage(sql));
+                               }
+                       }
+               }
+               return SQLerror(BAD_CONN, "Can't query until connection is complete");
+       }
+
+       SQLerror Query(const SQLrequest &req)
+       {
+               queue.push(req);
+
+               if(!qinprog && queue.totalsize())
+               {
+                       /* There's no query currently in progress, and there's queries in the queue. */
+                       SQLrequest& query = queue.front();
+                       return DoQuery(query);
+               }
+               else
+               {
+                       return SQLerror();
+               }
+       }
+
+       void OnUnloadModule(Module* mod)
+       {
+               queue.PurgeModule(mod);
+       }
+
+       const SQLhost GetConfHost()
+       {
+               return confhost;
+       }
+
+       void Close() {
+               if (!this->Instance->SE->DelFd(this))
+               {
+                       if (sql && PQstatus(sql) == CONNECTION_BAD)
+                       {
+                               this->Instance->SE->DelFd(this, true);
+                       }
+                       else
+                       {
+                               Instance->Log(DEBUG, "BUG: PQsocket cant be removed from socket engine!");
+                       }
+               }
+
+               if(sql)
+               {
+                       PQfinish(sql);
+                       sql = NULL;
+               }
+       }
+
+};
+
+class ModulePgSQL : public Module
+{
+  private:
+       ConnMap connections;
+       unsigned long currid;
+       char* sqlsuccess;
+       ReconnectTimer* retimer;
+
+  public:
+       ModulePgSQL(InspIRCd* Me)
+       : Module::Module(Me), currid(0)
+       {
+               ServerInstance->UseInterface("SQLutils");
+
+               sqlsuccess = new char[strlen(SQLSUCCESS)+1];
+
+               strlcpy(sqlsuccess, SQLSUCCESS, strlen(SQLSUCCESS));
+
+               if (!ServerInstance->PublishFeature("SQL", this))
+               {
+                       throw ModuleException("BUG: PgSQL Unable to publish feature 'SQL'");
+               }
+
+               ReadConf();
+
+               ServerInstance->PublishInterface("SQL", this);
+       }
+
+       virtual ~ModulePgSQL()
+       {
+               if (retimer)
+                       ServerInstance->Timers->DelTimer(retimer);
+               ClearAllConnections();
+               delete[] sqlsuccess;
+               ServerInstance->UnpublishInterface("SQL", this);
+               ServerInstance->UnpublishFeature("SQL");
+               ServerInstance->DoneWithInterface("SQLutils");
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnUnloadModule] = List[I_OnRequest] = List[I_OnRehash] = List[I_OnUserRegister] = List[I_OnCheckReady] = List[I_OnUserDisconnect] = 1;
+       }
+
+       virtual void OnRehash(userrec* user, const std::string &parameter)
+       {
+               ReadConf();
+       }
+
+       bool HasHost(const SQLhost &host)
+       {
+               for (ConnMap::iterator iter = connections.begin(); iter != connections.end(); iter++)
+               {
+                       if (host == iter->second->GetConfHost())
+                               return true;
+               }
+               return false;
+       }
+
+       bool HostInConf(const SQLhost &h)
+       {
+               ConfigReader conf(ServerInstance);
+               for(int i = 0; i < conf.Enumerate("database"); i++)
+               {
+                       SQLhost host;
+                       host.id         = conf.ReadValue("database", "id", i);
+                       host.host       = conf.ReadValue("database", "hostname", i);
+                       host.port       = conf.ReadInteger("database", "port", i, true);
+                       host.name       = conf.ReadValue("database", "name", i);
+                       host.user       = conf.ReadValue("database", "username", i);
+                       host.pass       = conf.ReadValue("database", "password", i);
+                       host.ssl        = conf.ReadFlag("database", "ssl", "0", i);
+                       if (h == host)
+                               return true;
+               }
+               return false;
+       }
+
+       void ReadConf()
+       {
+               ClearOldConnections();
+
+               ConfigReader conf(ServerInstance);
+               for(int i = 0; i < conf.Enumerate("database"); i++)
+               {
+                       SQLhost host;
+                       int ipvalid;
+
+                       host.id         = conf.ReadValue("database", "id", i);
+                       host.host       = conf.ReadValue("database", "hostname", i);
+                       host.port       = conf.ReadInteger("database", "port", i, true);
+                       host.name       = conf.ReadValue("database", "name", i);
+                       host.user       = conf.ReadValue("database", "username", i);
+                       host.pass       = conf.ReadValue("database", "password", i);
+                       host.ssl        = conf.ReadFlag("database", "ssl", "0", i);
+
+                       if (HasHost(host))
+                               continue;
+
+#ifdef IPV6
+                       if (strchr(host.host.c_str(),':'))
+                       {
+                               in6_addr blargle;
+                               ipvalid = inet_pton(AF_INET6, host.host.c_str(), &blargle);
+                       }
+                       else
+#endif
+                       {
+                               in_addr blargle;
+                               ipvalid = inet_aton(host.host.c_str(), &blargle);
+                       }
+
+                       if(ipvalid > 0)
+                       {
+                               /* The conversion succeeded, we were given an IP and we can give it straight to SQLConn */
+                               host.ip = host.host;
+                               this->AddConn(host);
+                       }
+                       else if(ipvalid == 0)
+                       {
+                               /* Conversion failed, assume it's a host */
+                               SQLresolver* resolver;
+
+                               try
+                               {
+                                       bool cached;
+                                       resolver = new SQLresolver(this, ServerInstance, host, cached);
+                                       ServerInstance->AddResolver(resolver, cached);
+                               }
+                               catch(...)
+                               {
+                                       /* THE WORLD IS COMING TO AN END! */
+                               }
+                       }
+                       else
+                       {
+                               /* Invalid address family, die horribly. */
+                               ServerInstance->Log(DEBUG, "BUG: insp_aton failed returning -1, oh noes.");
+                       }
+               }
+       }
+
+       void ClearOldConnections()
+       {
+               ConnMap::iterator iter,safei;
+               for (iter = connections.begin(); iter != connections.end(); iter++)
+               {
+                       if (!HostInConf(iter->second->GetConfHost()))
+                       {
+                               DELETE(iter->second);
+                               safei = iter;
+                               --iter;
+                               connections.erase(safei);
+                       }
+               }
+       }
+
+       void ClearAllConnections()
+       {
+               ConnMap::iterator i;
+               while ((i = connections.begin()) != connections.end())
+               {
+                       connections.erase(i);
+                       DELETE(i->second);
+               }
+       }
+
+       void AddConn(const SQLhost& hi)
+       {
+               if (HasHost(hi))
+               {
+                       ServerInstance->Log(DEFAULT, "WARNING: A pgsql connection with id: %s already exists, possibly due to DNS delay. Aborting connection attempt.", hi.id.c_str());
+                       return;
+               }
+
+               SQLConn* newconn;
+
+               /* The conversion succeeded, we were given an IP and we can give it straight to SQLConn */
+               newconn = new SQLConn(ServerInstance, this, hi);
+
+               connections.insert(std::make_pair(hi.id, newconn));
+       }
+
+       void ReconnectConn(SQLConn* conn)
+       {
+               for (ConnMap::iterator iter = connections.begin(); iter != connections.end(); iter++)
+               {
+                       if (conn == iter->second)
+                       {
+                               DELETE(iter->second);
+                               connections.erase(iter);
+                               break;
+                       }
+               }
+               retimer = new ReconnectTimer(ServerInstance, this);
+               ServerInstance->Timers->AddTimer(retimer);
+       }
+
+       virtual char* OnRequest(Request* request)
+       {
+               if(strcmp(SQLREQID, request->GetId()) == 0)
+               {
+                       SQLrequest* req = (SQLrequest*)request;
+                       ConnMap::iterator iter;
+                       if((iter = connections.find(req->dbid)) != connections.end())
+                       {
+                               /* Execute query */
+                               req->id = NewID();
+                               req->error = iter->second->Query(*req);
+
+                               return (req->error.Id() == NO_ERROR) ? sqlsuccess : NULL;
+                       }
+                       else
+                       {
+                               req->error.Id(BAD_DBID);
+                               return NULL;
+                       }
+               }
+               return NULL;
+       }
+
+       virtual void OnUnloadModule(Module* mod, const std::string&     name)
+       {
+               /* When a module unloads we have to check all the pending queries for all our connections
+                * and set the Module* specifying where the query came from to NULL. If the query has already
+                * been dispatched then when it is processed it will be dropped if the pointer is NULL.
+                *
+                * If the queries we find are not already being executed then we can simply remove them immediately.
+                */
+               for(ConnMap::iterator iter = connections.begin(); iter != connections.end(); iter++)
+               {
+                       iter->second->OnUnloadModule(mod);
+               }
+       }
+
+       unsigned long NewID()
+       {
+               if (currid+1 == 0)
+                       currid++;
+
+               return ++currid;
+       }
+
+       virtual Version GetVersion()
+       {
+               return Version(1, 1, 0, 0, VF_VENDOR|VF_SERVICEPROVIDER, API_VERSION);
+       }
+};
+
+/* move this here to use AddConn, rather that than having the whole
+ * module above SQLConn, since this is buggin me right now :/
+ */
+void SQLresolver::OnLookupComplete(const std::string &result, unsigned int ttl, bool cached)
+{
+       host.ip = result;
+       ((ModulePgSQL*)mod)->AddConn(host);
+       ((ModulePgSQL*)mod)->ClearOldConnections();
+}
+
+void ReconnectTimer::Tick(time_t time)
+{
+       ((ModulePgSQL*)mod)->ReadConf();
+}
+
+void SQLConn::DelayReconnect()
+{
+       ((ModulePgSQL*)us)->ReconnectConn(this);
+}
+
+MODULE_INIT(ModulePgSQL);
+
index 8629299196b3e5d469a17524b29db9fb6092b642..6b05ee521f8907aba943359e541e964ca50cface 100644 (file)
@@ -1 +1,194 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r#include "m_sqlv2.h"\r#include "m_sqlutils.h"\r\r/* $ModDesc: Allow/Deny connections based upon an arbitary SQL table */\r/* $ModDep: m_sqlv2.h m_sqlutils.h */\r\rclass ModuleSQLAuth : public Module\r{\r    Module* SQLutils;\r      Module* SQLprovider;\r\r  std::string usertable;\r std::string userfield;\r std::string passfield;\r std::string encryption;\r        std::string killreason;\r        std::string allowpattern;\r      std::string databaseid;\r        \r       bool verbose;\r  \rpublic:\r       ModuleSQLAuth(InspIRCd* Me)\r    : Module::Module(Me)\r   {\r              ServerInstance->UseInterface("SQLutils");\r              ServerInstance->UseInterface("SQL");\r\r          SQLutils = ServerInstance->FindModule("m_sqlutils.so");\r                if (!SQLutils)\r                 throw ModuleException("Can't find m_sqlutils.so. Please load m_sqlutils.so before m_sqlauth.so.");\r\r            SQLprovider = ServerInstance->FindFeature("SQL");\r              if (!SQLprovider)\r                      throw ModuleException("Can't find an SQL provider module. Please load one before attempting to load m_sqlauth.");\r\r             OnRehash(NULL,"");\r     }\r\r     virtual ~ModuleSQLAuth()\r       {\r              ServerInstance->DoneWithInterface("SQL");\r              ServerInstance->DoneWithInterface("SQLutils");\r }\r\r     void Implements(char* List)\r    {\r              List[I_OnUserDisconnect] = List[I_OnCheckReady] = List[I_OnRequest] = List[I_OnRehash] = List[I_OnUserRegister] = 1;\r   }\r\r     virtual void OnRehash(userrec* user, const std::string &parameter)\r     {\r              ConfigReader Conf(ServerInstance);\r             \r               usertable       = Conf.ReadValue("sqlauth", "usertable", 0);    /* User table name */\r          databaseid      = Conf.ReadValue("sqlauth", "dbid", 0);                 /* Database ID, given to the SQL service provider */\r           userfield       = Conf.ReadValue("sqlauth", "userfield", 0);    /* Field name where username can be found */\r           passfield       = Conf.ReadValue("sqlauth", "passfield", 0);    /* Field name where password can be found */\r           killreason      = Conf.ReadValue("sqlauth", "killreason", 0);   /* Reason to give when access is denied to a user (put your reg details here) */\r               allowpattern= Conf.ReadValue("sqlauth", "allowpattern",0 );     /* Allow nicks matching this pattern without requiring auth */\r         encryption      = Conf.ReadValue("sqlauth", "encryption", 0);   /* Name of sql function used to encrypt password, e.g. "md5" or "passwd".\r                                                                                                                                       * define, but leave blank if no encryption is to be used.\r                                                                                                                                      */\r            verbose         = Conf.ReadFlag("sqlauth", "verbose", 0);               /* Set to true if failed connects should be reported to operators */\r           \r               if (encryption.find("(") == std::string::npos)\r         {\r                      encryption.append("(");\r                }\r      }       \r\r      virtual int OnUserRegister(userrec* user)\r      {\r              if ((!allowpattern.empty()) && (ServerInstance->MatchText(user->nick,allowpattern)))\r           {\r                      user->Extend("sqlauthed");\r                     return 0;\r              }\r              \r               if (!CheckCredentials(user))\r           {\r                      userrec::QuitUser(ServerInstance,user,killreason);\r                     return 1;\r              }\r              return 0;\r      }\r\r     bool CheckCredentials(userrec* user)\r   {\r              SQLrequest req = SQLreq(this, SQLprovider, databaseid, "SELECT ? FROM ? WHERE ? = '?' AND ? = ?'?')", userfield, usertable, userfield, user->nick, passfield, encryption, user->password);\r                     \r               if(req.Send())\r         {\r                      /* When we get the query response from the service provider we will be given an ID to play with,\r                        * just an ID number which is unique to this query. We need a way of associating that ID with a userrec\r                         * so we insert it into a map mapping the IDs to users.\r                         * Thankfully m_sqlutils provides this, it will associate a ID with a user or channel, and if the user quits it removes the\r                     * association. This means that if the user quits during a query we will just get a failed lookup from m_sqlutils - telling\r                     * us to discard the query.\r                     */\r                    AssociateUser(this, SQLutils, req.id, user).Send();\r                            \r                       return true;\r           }\r              else\r           {\r                      if (verbose)\r                           ServerInstance->WriteOpers("Forbidden connection from %s!%s@%s (SQL query failed: %s)", user->nick, user->ident, user->host, req.error.Str());\r                 return false;\r          }\r      }\r      \r       virtual char* OnRequest(Request* request)\r      {\r              if(strcmp(SQLRESID, request->GetId()) == 0)\r            {\r                      SQLresult* res = static_cast<SQLresult*>(request);\r\r                    userrec* user = GetAssocUser(this, SQLutils, res->id).S().user;\r                        UnAssociate(this, SQLutils, res->id).S();\r                      \r                       if(user)\r                       {\r                              if(res->error.Id() == NO_ERROR)\r                                {\r                                      if(res->Rows())\r                                        {\r                                              /* We got a row in the result, this is enough really */\r                                                user->Extend("sqlauthed");\r                                     }\r                                      else if (verbose)\r                                      {\r                                              /* No rows in result, this means there was no record matching the user */\r                                              ServerInstance->WriteOpers("Forbidden connection from %s!%s@%s (SQL query returned no matches)", user->nick, user->ident, user->host);\r                                         user->Extend("sqlauth_failed");\r                                        }\r                              }\r                              else if (verbose)\r                              {\r                                      ServerInstance->WriteOpers("Forbidden connection from %s!%s@%s (SQL query failed: %s)", user->nick, user->ident, user->host, res->error.Str());\r                                        user->Extend("sqlauth_failed");\r                                }\r                      }\r                      else\r                   {\r                              return NULL;\r                   }\r\r                     if (!user->GetExt("sqlauthed"))\r                        {\r                              userrec::QuitUser(ServerInstance,user,killreason);\r                     }\r                      return SQLSUCCESS;\r             }               \r               return NULL;\r   }\r      \r       virtual void OnUserDisconnect(userrec* user)\r   {\r              user->Shrink("sqlauthed");\r             user->Shrink("sqlauth_failed");         \r       }\r      \r       virtual bool OnCheckReady(userrec* user)\r       {\r              return user->GetExt("sqlauthed");\r      }\r\r     virtual Version GetVersion()\r   {\r              return Version(1,1,1,0,VF_VENDOR,API_VERSION);\r }\r      \r};\r\rMODULE_INIT(ModuleSQLAuth);\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+#include "m_sqlv2.h"
+#include "m_sqlutils.h"
+
+/* $ModDesc: Allow/Deny connections based upon an arbitary SQL table */
+/* $ModDep: m_sqlv2.h m_sqlutils.h */
+
+class ModuleSQLAuth : public Module
+{
+       Module* SQLutils;
+       Module* SQLprovider;
+
+       std::string usertable;
+       std::string userfield;
+       std::string passfield;
+       std::string encryption;
+       std::string killreason;
+       std::string allowpattern;
+       std::string databaseid;
+       
+       bool verbose;
+       
+public:
+       ModuleSQLAuth(InspIRCd* Me)
+       : Module::Module(Me)
+       {
+               ServerInstance->UseInterface("SQLutils");
+               ServerInstance->UseInterface("SQL");
+
+               SQLutils = ServerInstance->FindModule("m_sqlutils.so");
+               if (!SQLutils)
+                       throw ModuleException("Can't find m_sqlutils.so. Please load m_sqlutils.so before m_sqlauth.so.");
+
+               SQLprovider = ServerInstance->FindFeature("SQL");
+               if (!SQLprovider)
+                       throw ModuleException("Can't find an SQL provider module. Please load one before attempting to load m_sqlauth.");
+
+               OnRehash(NULL,"");
+       }
+
+       virtual ~ModuleSQLAuth()
+       {
+               ServerInstance->DoneWithInterface("SQL");
+               ServerInstance->DoneWithInterface("SQLutils");
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnUserDisconnect] = List[I_OnCheckReady] = List[I_OnRequest] = List[I_OnRehash] = List[I_OnUserRegister] = 1;
+       }
+
+       virtual void OnRehash(userrec* user, const std::string &parameter)
+       {
+               ConfigReader Conf(ServerInstance);
+               
+               usertable       = Conf.ReadValue("sqlauth", "usertable", 0);    /* User table name */
+               databaseid      = Conf.ReadValue("sqlauth", "dbid", 0);                 /* Database ID, given to the SQL service provider */
+               userfield       = Conf.ReadValue("sqlauth", "userfield", 0);    /* Field name where username can be found */
+               passfield       = Conf.ReadValue("sqlauth", "passfield", 0);    /* Field name where password can be found */
+               killreason      = Conf.ReadValue("sqlauth", "killreason", 0);   /* Reason to give when access is denied to a user (put your reg details here) */
+               allowpattern= Conf.ReadValue("sqlauth", "allowpattern",0 );     /* Allow nicks matching this pattern without requiring auth */
+               encryption      = Conf.ReadValue("sqlauth", "encryption", 0);   /* Name of sql function used to encrypt password, e.g. "md5" or "passwd".
+                                                                                                                                        * define, but leave blank if no encryption is to be used.
+                                                                                                                                        */
+               verbose         = Conf.ReadFlag("sqlauth", "verbose", 0);               /* Set to true if failed connects should be reported to operators */
+               
+               if (encryption.find("(") == std::string::npos)
+               {
+                       encryption.append("(");
+               }
+       }       
+
+       virtual int OnUserRegister(userrec* user)
+       {
+               if ((!allowpattern.empty()) && (ServerInstance->MatchText(user->nick,allowpattern)))
+               {
+                       user->Extend("sqlauthed");
+                       return 0;
+               }
+               
+               if (!CheckCredentials(user))
+               {
+                       userrec::QuitUser(ServerInstance,user,killreason);
+                       return 1;
+               }
+               return 0;
+       }
+
+       bool CheckCredentials(userrec* user)
+       {
+               SQLrequest req = SQLreq(this, SQLprovider, databaseid, "SELECT ? FROM ? WHERE ? = '?' AND ? = ?'?')", userfield, usertable, userfield, user->nick, passfield, encryption, user->password);
+                       
+               if(req.Send())
+               {
+                       /* When we get the query response from the service provider we will be given an ID to play with,
+                        * just an ID number which is unique to this query. We need a way of associating that ID with a userrec
+                        * so we insert it into a map mapping the IDs to users.
+                        * Thankfully m_sqlutils provides this, it will associate a ID with a user or channel, and if the user quits it removes the
+                        * association. This means that if the user quits during a query we will just get a failed lookup from m_sqlutils - telling
+                        * us to discard the query.
+                        */
+                       AssociateUser(this, SQLutils, req.id, user).Send();
+                               
+                       return true;
+               }
+               else
+               {
+                       if (verbose)
+                               ServerInstance->WriteOpers("Forbidden connection from %s!%s@%s (SQL query failed: %s)", user->nick, user->ident, user->host, req.error.Str());
+                       return false;
+               }
+       }
+       
+       virtual char* OnRequest(Request* request)
+       {
+               if(strcmp(SQLRESID, request->GetId()) == 0)
+               {
+                       SQLresult* res = static_cast<SQLresult*>(request);
+
+                       userrec* user = GetAssocUser(this, SQLutils, res->id).S().user;
+                       UnAssociate(this, SQLutils, res->id).S();
+                       
+                       if(user)
+                       {
+                               if(res->error.Id() == NO_ERROR)
+                               {
+                                       if(res->Rows())
+                                       {
+                                               /* We got a row in the result, this is enough really */
+                                               user->Extend("sqlauthed");
+                                       }
+                                       else if (verbose)
+                                       {
+                                               /* No rows in result, this means there was no record matching the user */
+                                               ServerInstance->WriteOpers("Forbidden connection from %s!%s@%s (SQL query returned no matches)", user->nick, user->ident, user->host);
+                                               user->Extend("sqlauth_failed");
+                                       }
+                               }
+                               else if (verbose)
+                               {
+                                       ServerInstance->WriteOpers("Forbidden connection from %s!%s@%s (SQL query failed: %s)", user->nick, user->ident, user->host, res->error.Str());
+                                       user->Extend("sqlauth_failed");
+                               }
+                       }
+                       else
+                       {
+                               return NULL;
+                       }
+
+                       if (!user->GetExt("sqlauthed"))
+                       {
+                               userrec::QuitUser(ServerInstance,user,killreason);
+                       }
+                       return SQLSUCCESS;
+               }               
+               return NULL;
+       }
+       
+       virtual void OnUserDisconnect(userrec* user)
+       {
+               user->Shrink("sqlauthed");
+               user->Shrink("sqlauth_failed");         
+       }
+       
+       virtual bool OnCheckReady(userrec* user)
+       {
+               return user->GetExt("sqlauthed");
+       }
+
+       virtual Version GetVersion()
+       {
+               return Version(1,1,1,0,VF_VENDOR,API_VERSION);
+       }
+       
+};
+
+MODULE_INIT(ModuleSQLAuth);
+
index 6741d77459f8db24479cb3cbb330f4532a328344..66955de0717127e7f37dae2c02987229a6d63d46 100644 (file)
@@ -1 +1,660 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include <sqlite3.h>\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r\r#include "m_sqlv2.h"\r\r/* $ModDesc: sqlite3 provider */\r/* $CompileFlags: pkgconfversion("sqlite3","3.3") pkgconfincludes("sqlite3","/sqlite3.h","") */\r/* $LinkerFlags: pkgconflibs("sqlite3","/libsqlite3.so","-lsqlite3") */\r/* $ModDep: m_sqlv2.h */\r\r\rclass SQLConn;\rclass SQLite3Result;\rclass ResultNotifier;\r\rtypedef std::map<std::string, SQLConn*> ConnMap;\rtypedef std::deque<classbase*> paramlist;\rtypedef std::deque<SQLite3Result*> ResultQueue;\r\rResultNotifier* resultnotify = NULL;\r\r\rclass ResultNotifier : public InspSocket\r{\r      Module* mod;\r   insp_sockaddr sock_us;\r socklen_t uslen;\r\r public:\r     /* Create a socket on a random port. Let the tcp stack allocate us an available port */\r#ifdef IPV6\r    ResultNotifier(InspIRCd* SI, Module* m) : InspSocket(SI, "::1", 0, true, 3000), mod(m)\r#else\r   ResultNotifier(InspIRCd* SI, Module* m) : InspSocket(SI, "127.0.0.1", 0, true, 3000), mod(m)\r#endif\r    {\r              uslen = sizeof(sock_us);\r               if (getsockname(this->fd,(sockaddr*)&sock_us,&uslen))\r          {\r                      throw ModuleException("Could not create random listening port on localhost");\r          }\r      }\r\r     ResultNotifier(InspIRCd* SI, Module* m, int newfd, char* ip) : InspSocket(SI, newfd, ip), mod(m)\r       {\r      }\r\r     /* Using getsockname and ntohs, we can determine which port number we were allocated */\r        int GetPort()\r  {\r#ifdef IPV6\r          return ntohs(sock_us.sin6_port);\r#else\r         return ntohs(sock_us.sin_port);\r#endif\r }\r\r     virtual int OnIncomingConnection(int newsock, char* ip)\r        {\r              Dispatch();\r            return false;\r  }\r\r     void Dispatch();\r};\r\r\rclass SQLite3Result : public SQLresult\r{\r  private:\r      int currentrow;\r        int rows;\r      int cols;\r\r     std::vector<std::string> colnames;\r     std::vector<SQLfieldList> fieldlists;\r  SQLfieldList emptyfieldlist;\r\r  SQLfieldList* fieldlist;\r       SQLfieldMap* fieldmap;\r\r  public:\r      SQLite3Result(Module* self, Module* to, unsigned int id)\r       : SQLresult(self, to, id), currentrow(0), rows(0), cols(0), fieldlist(NULL), fieldmap(NULL)\r    {\r      }\r\r     ~SQLite3Result()\r       {\r      }\r\r     void AddRow(int colsnum, char **data, char **colname)\r  {\r              colnames.clear();\r              cols = colsnum;\r                for (int i = 0; i < colsnum; i++)\r              {\r                      fieldlists.resize(fieldlists.size()+1);\r                        colnames.push_back(colname[i]);\r                        SQLfield sf(data[i] ? data[i] : "", data[i] ? false : true);\r                   fieldlists[rows].push_back(sf);\r                }\r              rows++;\r        }\r\r     void UpdateAffectedCount()\r     {\r              rows++;\r        }\r\r     virtual int Rows()\r     {\r              return rows;\r   }\r\r     virtual int Cols()\r     {\r              return cols;\r   }\r\r     virtual std::string ColName(int column)\r        {\r              if (column < (int)colnames.size())\r             {\r                      return colnames[column];\r               }\r              else\r           {\r                      throw SQLbadColName();\r         }\r              return "";\r     }\r\r     virtual int ColNum(const std::string &column)\r  {\r              for (unsigned int i = 0; i < colnames.size(); i++)\r             {\r                      if (column == colnames[i])\r                             return i;\r              }\r              throw SQLbadColName();\r         return 0;\r      }\r\r     virtual SQLfield GetValue(int row, int column)\r {\r              if ((row >= 0) && (row < rows) && (column >= 0) && (column < Cols()))\r          {\r                      return fieldlists[row][column];\r                }\r\r             throw SQLbadColName();\r\r                /* XXX: We never actually get here because of the throw */\r             return SQLfield("",true);\r      }\r\r     virtual SQLfieldList& GetRow()\r {\r              if (currentrow < rows)\r                 return fieldlists[currentrow];\r         else\r                   return emptyfieldlist;\r }\r\r     virtual SQLfieldMap& GetRowMap()\r       {\r              /* In an effort to reduce overhead we don't actually allocate the map\r           * until the first time it's needed...so...\r             */\r            if(fieldmap)\r           {\r                      fieldmap->clear();\r             }\r              else\r           {\r                      fieldmap = new SQLfieldMap;\r            }\r\r             if (currentrow < rows)\r         {\r                      for (int i = 0; i < Cols(); i++)\r                       {\r                              fieldmap->insert(std::make_pair(ColName(i), GetValue(currentrow, i)));\r                 }\r                      currentrow++;\r          }\r\r             return *fieldmap;\r      }\r\r     virtual SQLfieldList* GetRowPtr()\r      {\r              fieldlist = new SQLfieldList();\r\r               if (currentrow < rows)\r         {\r                      for (int i = 0; i < Rows(); i++)\r                       {\r                              fieldlist->push_back(fieldlists[currentrow][i]);\r                       }\r                      currentrow++;\r          }\r              return fieldlist;\r      }\r\r     virtual SQLfieldMap* GetRowMapPtr()\r    {\r              fieldmap = new SQLfieldMap();\r\r         if (currentrow < rows)\r         {\r                      for (int i = 0; i < Cols(); i++)\r                       {\r                              fieldmap->insert(std::make_pair(colnames[i],GetValue(currentrow, i)));\r                 }\r                      currentrow++;\r          }\r\r             return fieldmap;\r       }\r\r     virtual void Free(SQLfieldMap* fm)\r     {\r              delete fm;\r     }\r\r     virtual void Free(SQLfieldList* fl)\r    {\r              delete fl;\r     }\r\r\r};\r\rclass SQLConn : public classbase\r{\r  private:\r  ResultQueue results;\r   InspIRCd* Instance;\r    Module* mod;\r   SQLhost host;\r  sqlite3* conn;\r\r  public:\r      SQLConn(InspIRCd* SI, Module* m, const SQLhost& hi)\r    : Instance(SI), mod(m), host(hi)\r       {\r              if (OpenDB() != SQLITE_OK)\r             {\r                      Instance->Log(DEFAULT, "WARNING: Could not open DB with id: " + host.id);\r                      CloseDB();\r             }\r      }\r\r     ~SQLConn()\r     {\r              CloseDB();\r     }\r\r     SQLerror Query(SQLrequest &req)\r        {\r              /* Pointer to the buffer we screw around with substitution in */\r               char* query;\r\r          /* Pointer to the current end of query, where we append new stuff */\r           char* queryend;\r\r               /* Total length of the unescaped parameters */\r         unsigned long paramlen;\r\r               /* Total length of query, used for binary-safety in mysql_real_query */\r                unsigned long querylength = 0;\r\r                paramlen = 0;\r          for(ParamL::iterator i = req.query.p.begin(); i != req.query.p.end(); i++)\r             {\r                      paramlen += i->size();\r         }\r\r             /* To avoid a lot of allocations, allocate enough memory for the biggest the escaped query could possibly be.\r           * sizeofquery + (totalparamlength*2) + 1\r               *\r              * The +1 is for null-terminating the string for mysql_real_escape_string\r               */\r            query = new char[req.query.q.length() + (paramlen*2) + 1];\r             queryend = query;\r\r             for(unsigned long i = 0; i < req.query.q.length(); i++)\r                {\r                      if(req.query.q[i] == '?')\r                      {\r                              if(req.query.p.size())\r                         {\r                                      char* escaped;\r                                 escaped = sqlite3_mprintf("%q", req.query.p.front().c_str());\r                                  for (char* n = escaped; *n; n++)\r                                       {\r                                              *queryend = *n;\r                                                queryend++;\r                                    }\r                                      sqlite3_free(escaped);\r                                 req.query.p.pop_front();\r                               }\r                              else\r                                   break;\r                 }\r                      else\r                   {\r                              *queryend = req.query.q[i];\r                            queryend++;\r                    }\r                      querylength++;\r         }\r              *queryend = 0;\r         req.query.q = query;\r\r          SQLite3Result* res = new SQLite3Result(mod, req.GetSource(), req.id);\r          res->dbid = host.id;\r           res->query = req.query.q;\r              paramlist params;\r              params.push_back(this);\r                params.push_back(res);\r\r                char *errmsg = 0;\r              sqlite3_update_hook(conn, QueryUpdateHook, &params);\r           if (sqlite3_exec(conn, req.query.q.data(), QueryResult, &params, &errmsg) != SQLITE_OK)\r                {\r                      std::string error(errmsg);\r                     sqlite3_free(errmsg);\r                  delete[] query;\r                        delete res;\r                    return SQLerror(QSEND_FAIL, error);\r            }\r              delete[] query;\r\r               results.push_back(res);\r                SendNotify();\r          return SQLerror();\r     }\r\r     static int QueryResult(void *params, int argc, char **argv, char **azColName)\r  {\r              paramlist* p = (paramlist*)params;\r             ((SQLConn*)(*p)[0])->ResultReady(((SQLite3Result*)(*p)[1]), argc, argv, azColName);\r            return 0;\r      }\r\r     static void QueryUpdateHook(void *params, int eventid, char const * azSQLite, char const * azColName, sqlite_int64 rowid)\r      {\r              paramlist* p = (paramlist*)params;\r             ((SQLConn*)(*p)[0])->AffectedReady(((SQLite3Result*)(*p)[1]));\r }\r\r     void ResultReady(SQLite3Result *res, int cols, char **data, char **colnames)\r   {\r              res->AddRow(cols, data, colnames);\r     }\r\r     void AffectedReady(SQLite3Result *res)\r {\r              res->UpdateAffectedCount();\r    }\r\r     int OpenDB()\r   {\r              return sqlite3_open(host.host.c_str(), &conn);\r }\r\r     void CloseDB()\r {\r              sqlite3_interrupt(conn);\r               sqlite3_close(conn);\r   }\r\r     SQLhost GetConfHost()\r  {\r              return host;\r   }\r\r     void SendResults()\r     {\r              while (results.size())\r         {\r                      SQLite3Result* res = results[0];\r                       if (res->GetDest())\r                    {\r                              res->Send();\r                   }\r                      else\r                   {\r                              /* If the client module is unloaded partway through a query then the provider will set\r                          * the pointer to NULL. We cannot just cancel the query as the result will still come\r                           * through at some point...and it could get messy if we play with invalid pointers...\r                           */\r                            delete res;\r                    }\r                      results.pop_front();\r           }\r      }\r\r     void ClearResults()\r    {\r              while (results.size())\r         {\r                      SQLite3Result* res = results[0];\r                       delete res;\r                    results.pop_front();\r           }\r      }\r\r     void SendNotify()\r      {\r              int QueueFD;\r           if ((QueueFD = socket(AF_FAMILY, SOCK_STREAM, 0)) == -1)\r               {\r                      /* crap, we're out of sockets... */\r                    return;\r                }\r\r             insp_sockaddr addr;\r\r#ifdef IPV6\r               insp_aton("::1", &addr.sin6_addr);\r             addr.sin6_family = AF_FAMILY;\r          addr.sin6_port = htons(resultnotify->GetPort());\r#else\r         insp_inaddr ia;\r                insp_aton("127.0.0.1", &ia);\r           addr.sin_family = AF_FAMILY;\r           addr.sin_addr = ia;\r            addr.sin_port = htons(resultnotify->GetPort());\r#endif\r\r                if (connect(QueueFD, (sockaddr*)&addr,sizeof(addr)) == -1)\r             {\r                      /* wtf, we cant connect to it, but we just created it! */\r                      return;\r                }\r      }\r\r};\r\r\rclass ModuleSQLite3 : public Module\r{\r  private:\r       ConnMap connections;\r   unsigned long currid;\r\r  public:\r       ModuleSQLite3(InspIRCd* Me)\r    : Module::Module(Me), currid(0)\r        {\r              ServerInstance->UseInterface("SQLutils");\r\r             if (!ServerInstance->PublishFeature("SQL", this))\r              {\r                      throw ModuleException("m_sqlite3: Unable to publish feature 'SQL'");\r           }\r\r             resultnotify = new ResultNotifier(ServerInstance, this);\r\r              ReadConf();\r\r           ServerInstance->PublishInterface("SQL", this);\r }\r\r     virtual ~ModuleSQLite3()\r       {\r              ClearQueue();\r          ClearAllConnections();\r         resultnotify->SetFd(-1);\r               resultnotify->state = I_ERROR;\r         resultnotify->OnError(I_ERR_SOCKET);\r           resultnotify->ClosePending = true;\r             delete resultnotify;\r           ServerInstance->UnpublishInterface("SQL", this);\r               ServerInstance->UnpublishFeature("SQL");\r               ServerInstance->DoneWithInterface("SQLutils");\r }\r\r     void Implements(char* List)\r    {\r              List[I_OnRequest] = List[I_OnRehash] = 1;\r      }\r\r     void SendQueue()\r       {\r              for (ConnMap::iterator iter = connections.begin(); iter != connections.end(); iter++)\r          {\r                      iter->second->SendResults();\r           }\r      }\r\r     void ClearQueue()\r      {\r              for (ConnMap::iterator iter = connections.begin(); iter != connections.end(); iter++)\r          {\r                      iter->second->ClearResults();\r          }\r      }\r\r     bool HasHost(const SQLhost &host)\r      {\r              for (ConnMap::iterator iter = connections.begin(); iter != connections.end(); iter++)\r          {\r                      if (host == iter->second->GetConfHost())\r                               return true;\r           }\r              return false;\r  }\r\r     bool HostInConf(const SQLhost &h)\r      {\r              ConfigReader conf(ServerInstance);\r             for(int i = 0; i < conf.Enumerate("database"); i++)\r            {\r                      SQLhost host;\r                  host.id         = conf.ReadValue("database", "id", i);\r                 host.host       = conf.ReadValue("database", "hostname", i);\r                   host.port       = conf.ReadInteger("database", "port", i, true);\r                       host.name       = conf.ReadValue("database", "name", i);\r                       host.user       = conf.ReadValue("database", "username", i);\r                   host.pass       = conf.ReadValue("database", "password", i);\r                   host.ssl        = conf.ReadFlag("database", "ssl", "0", i);\r                    if (h == host)\r                         return true;\r           }\r              return false;\r  }\r\r     void ReadConf()\r        {\r              ClearOldConnections();\r\r                ConfigReader conf(ServerInstance);\r             for(int i = 0; i < conf.Enumerate("database"); i++)\r            {\r                      SQLhost host;\r\r                 host.id         = conf.ReadValue("database", "id", i);\r                 host.host       = conf.ReadValue("database", "hostname", i);\r                   host.port       = conf.ReadInteger("database", "port", i, true);\r                       host.name       = conf.ReadValue("database", "name", i);\r                       host.user       = conf.ReadValue("database", "username", i);\r                   host.pass       = conf.ReadValue("database", "password", i);\r                   host.ssl        = conf.ReadFlag("database", "ssl", "0", i);\r\r                   if (HasHost(host))\r                             continue;\r\r                     this->AddConn(host);\r           }\r      }\r\r     void AddConn(const SQLhost& hi)\r        {\r              if (HasHost(hi))\r               {\r                      ServerInstance->Log(DEFAULT, "WARNING: A sqlite connection with id: %s already exists. Aborting database open attempt.", hi.id.c_str());\r                       return;\r                }\r\r             SQLConn* newconn;\r\r             newconn = new SQLConn(ServerInstance, this, hi);\r\r              connections.insert(std::make_pair(hi.id, newconn));\r    }\r\r     void ClearOldConnections()\r     {\r              ConnMap::iterator iter,safei;\r          for (iter = connections.begin(); iter != connections.end(); iter++)\r            {\r                      if (!HostInConf(iter->second->GetConfHost()))\r                  {\r                              DELETE(iter->second);\r                          safei = iter;\r                          --iter;\r                                connections.erase(safei);\r                      }\r              }\r      }\r\r     void ClearAllConnections()\r     {\r              ConnMap::iterator i;\r           while ((i = connections.begin()) != connections.end())\r         {\r                      connections.erase(i);\r                  DELETE(i->second);\r             }\r      }\r\r     virtual void OnRehash(userrec* user, const std::string &parameter)\r     {\r              ReadConf();\r    }\r\r     virtual char* OnRequest(Request* request)\r      {\r              if(strcmp(SQLREQID, request->GetId()) == 0)\r            {\r                      SQLrequest* req = (SQLrequest*)request;\r                        ConnMap::iterator iter;\r                        if((iter = connections.find(req->dbid)) != connections.end())\r                  {\r                              req->id = NewID();\r                             req->error = iter->second->Query(*req);\r                                return SQLSUCCESS;\r                     }\r                      else\r                   {\r                              req->error.Id(BAD_DBID);\r                               return NULL;\r                   }\r              }\r              return NULL;\r   }\r\r     unsigned long NewID()\r  {\r              if (currid+1 == 0)\r                     currid++;\r\r             return ++currid;\r       }\r\r     virtual Version GetVersion()\r   {\r              return Version(1,1,0,0,VF_VENDOR|VF_SERVICEPROVIDER,API_VERSION);\r      }\r\r};\r\rvoid ResultNotifier::Dispatch()\r{\r       ((ModuleSQLite3*)mod)->SendQueue();\r}\r\rMODULE_INIT(ModuleSQLite3);\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include <sqlite3.h>
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+
+#include "m_sqlv2.h"
+
+/* $ModDesc: sqlite3 provider */
+/* $CompileFlags: pkgconfversion("sqlite3","3.3") pkgconfincludes("sqlite3","/sqlite3.h","") */
+/* $LinkerFlags: pkgconflibs("sqlite3","/libsqlite3.so","-lsqlite3") */
+/* $ModDep: m_sqlv2.h */
+
+
+class SQLConn;
+class SQLite3Result;
+class ResultNotifier;
+
+typedef std::map<std::string, SQLConn*> ConnMap;
+typedef std::deque<classbase*> paramlist;
+typedef std::deque<SQLite3Result*> ResultQueue;
+
+ResultNotifier* resultnotify = NULL;
+
+
+class ResultNotifier : public InspSocket
+{
+       Module* mod;
+       insp_sockaddr sock_us;
+       socklen_t uslen;
+
+ public:
+       /* Create a socket on a random port. Let the tcp stack allocate us an available port */
+#ifdef IPV6
+       ResultNotifier(InspIRCd* SI, Module* m) : InspSocket(SI, "::1", 0, true, 3000), mod(m)
+#else
+       ResultNotifier(InspIRCd* SI, Module* m) : InspSocket(SI, "127.0.0.1", 0, true, 3000), mod(m)
+#endif
+       {
+               uslen = sizeof(sock_us);
+               if (getsockname(this->fd,(sockaddr*)&sock_us,&uslen))
+               {
+                       throw ModuleException("Could not create random listening port on localhost");
+               }
+       }
+
+       ResultNotifier(InspIRCd* SI, Module* m, int newfd, char* ip) : InspSocket(SI, newfd, ip), mod(m)
+       {
+       }
+
+       /* Using getsockname and ntohs, we can determine which port number we were allocated */
+       int GetPort()
+       {
+#ifdef IPV6
+               return ntohs(sock_us.sin6_port);
+#else
+               return ntohs(sock_us.sin_port);
+#endif
+       }
+
+       virtual int OnIncomingConnection(int newsock, char* ip)
+       {
+               Dispatch();
+               return false;
+       }
+
+       void Dispatch();
+};
+
+
+class SQLite3Result : public SQLresult
+{
+  private:
+       int currentrow;
+       int rows;
+       int cols;
+
+       std::vector<std::string> colnames;
+       std::vector<SQLfieldList> fieldlists;
+       SQLfieldList emptyfieldlist;
+
+       SQLfieldList* fieldlist;
+       SQLfieldMap* fieldmap;
+
+  public:
+       SQLite3Result(Module* self, Module* to, unsigned int id)
+       : SQLresult(self, to, id), currentrow(0), rows(0), cols(0), fieldlist(NULL), fieldmap(NULL)
+       {
+       }
+
+       ~SQLite3Result()
+       {
+       }
+
+       void AddRow(int colsnum, char **data, char **colname)
+       {
+               colnames.clear();
+               cols = colsnum;
+               for (int i = 0; i < colsnum; i++)
+               {
+                       fieldlists.resize(fieldlists.size()+1);
+                       colnames.push_back(colname[i]);
+                       SQLfield sf(data[i] ? data[i] : "", data[i] ? false : true);
+                       fieldlists[rows].push_back(sf);
+               }
+               rows++;
+       }
+
+       void UpdateAffectedCount()
+       {
+               rows++;
+       }
+
+       virtual int Rows()
+       {
+               return rows;
+       }
+
+       virtual int Cols()
+       {
+               return cols;
+       }
+
+       virtual std::string ColName(int column)
+       {
+               if (column < (int)colnames.size())
+               {
+                       return colnames[column];
+               }
+               else
+               {
+                       throw SQLbadColName();
+               }
+               return "";
+       }
+
+       virtual int ColNum(const std::string &column)
+       {
+               for (unsigned int i = 0; i < colnames.size(); i++)
+               {
+                       if (column == colnames[i])
+                               return i;
+               }
+               throw SQLbadColName();
+               return 0;
+       }
+
+       virtual SQLfield GetValue(int row, int column)
+       {
+               if ((row >= 0) && (row < rows) && (column >= 0) && (column < Cols()))
+               {
+                       return fieldlists[row][column];
+               }
+
+               throw SQLbadColName();
+
+               /* XXX: We never actually get here because of the throw */
+               return SQLfield("",true);
+       }
+
+       virtual SQLfieldList& GetRow()
+       {
+               if (currentrow < rows)
+                       return fieldlists[currentrow];
+               else
+                       return emptyfieldlist;
+       }
+
+       virtual SQLfieldMap& GetRowMap()
+       {
+               /* In an effort to reduce overhead we don't actually allocate the map
+                * until the first time it's needed...so...
+                */
+               if(fieldmap)
+               {
+                       fieldmap->clear();
+               }
+               else
+               {
+                       fieldmap = new SQLfieldMap;
+               }
+
+               if (currentrow < rows)
+               {
+                       for (int i = 0; i < Cols(); i++)
+                       {
+                               fieldmap->insert(std::make_pair(ColName(i), GetValue(currentrow, i)));
+                       }
+                       currentrow++;
+               }
+
+               return *fieldmap;
+       }
+
+       virtual SQLfieldList* GetRowPtr()
+       {
+               fieldlist = new SQLfieldList();
+
+               if (currentrow < rows)
+               {
+                       for (int i = 0; i < Rows(); i++)
+                       {
+                               fieldlist->push_back(fieldlists[currentrow][i]);
+                       }
+                       currentrow++;
+               }
+               return fieldlist;
+       }
+
+       virtual SQLfieldMap* GetRowMapPtr()
+       {
+               fieldmap = new SQLfieldMap();
+
+               if (currentrow < rows)
+               {
+                       for (int i = 0; i < Cols(); i++)
+                       {
+                               fieldmap->insert(std::make_pair(colnames[i],GetValue(currentrow, i)));
+                       }
+                       currentrow++;
+               }
+
+               return fieldmap;
+       }
+
+       virtual void Free(SQLfieldMap* fm)
+       {
+               delete fm;
+       }
+
+       virtual void Free(SQLfieldList* fl)
+       {
+               delete fl;
+       }
+
+
+};
+
+class SQLConn : public classbase
+{
+  private:
+       ResultQueue results;
+       InspIRCd* Instance;
+       Module* mod;
+       SQLhost host;
+       sqlite3* conn;
+
+  public:
+       SQLConn(InspIRCd* SI, Module* m, const SQLhost& hi)
+       : Instance(SI), mod(m), host(hi)
+       {
+               if (OpenDB() != SQLITE_OK)
+               {
+                       Instance->Log(DEFAULT, "WARNING: Could not open DB with id: " + host.id);
+                       CloseDB();
+               }
+       }
+
+       ~SQLConn()
+       {
+               CloseDB();
+       }
+
+       SQLerror Query(SQLrequest &req)
+       {
+               /* Pointer to the buffer we screw around with substitution in */
+               char* query;
+
+               /* Pointer to the current end of query, where we append new stuff */
+               char* queryend;
+
+               /* Total length of the unescaped parameters */
+               unsigned long paramlen;
+
+               /* Total length of query, used for binary-safety in mysql_real_query */
+               unsigned long querylength = 0;
+
+               paramlen = 0;
+               for(ParamL::iterator i = req.query.p.begin(); i != req.query.p.end(); i++)
+               {
+                       paramlen += i->size();
+               }
+
+               /* To avoid a lot of allocations, allocate enough memory for the biggest the escaped query could possibly be.
+                * sizeofquery + (totalparamlength*2) + 1
+                *
+                * The +1 is for null-terminating the string for mysql_real_escape_string
+                */
+               query = new char[req.query.q.length() + (paramlen*2) + 1];
+               queryend = query;
+
+               for(unsigned long i = 0; i < req.query.q.length(); i++)
+               {
+                       if(req.query.q[i] == '?')
+                       {
+                               if(req.query.p.size())
+                               {
+                                       char* escaped;
+                                       escaped = sqlite3_mprintf("%q", req.query.p.front().c_str());
+                                       for (char* n = escaped; *n; n++)
+                                       {
+                                               *queryend = *n;
+                                               queryend++;
+                                       }
+                                       sqlite3_free(escaped);
+                                       req.query.p.pop_front();
+                               }
+                               else
+                                       break;
+                       }
+                       else
+                       {
+                               *queryend = req.query.q[i];
+                               queryend++;
+                       }
+                       querylength++;
+               }
+               *queryend = 0;
+               req.query.q = query;
+
+               SQLite3Result* res = new SQLite3Result(mod, req.GetSource(), req.id);
+               res->dbid = host.id;
+               res->query = req.query.q;
+               paramlist params;
+               params.push_back(this);
+               params.push_back(res);
+
+               char *errmsg = 0;
+               sqlite3_update_hook(conn, QueryUpdateHook, &params);
+               if (sqlite3_exec(conn, req.query.q.data(), QueryResult, &params, &errmsg) != SQLITE_OK)
+               {
+                       std::string error(errmsg);
+                       sqlite3_free(errmsg);
+                       delete[] query;
+                       delete res;
+                       return SQLerror(QSEND_FAIL, error);
+               }
+               delete[] query;
+
+               results.push_back(res);
+               SendNotify();
+               return SQLerror();
+       }
+
+       static int QueryResult(void *params, int argc, char **argv, char **azColName)
+       {
+               paramlist* p = (paramlist*)params;
+               ((SQLConn*)(*p)[0])->ResultReady(((SQLite3Result*)(*p)[1]), argc, argv, azColName);
+               return 0;
+       }
+
+       static void QueryUpdateHook(void *params, int eventid, char const * azSQLite, char const * azColName, sqlite_int64 rowid)
+       {
+               paramlist* p = (paramlist*)params;
+               ((SQLConn*)(*p)[0])->AffectedReady(((SQLite3Result*)(*p)[1]));
+       }
+
+       void ResultReady(SQLite3Result *res, int cols, char **data, char **colnames)
+       {
+               res->AddRow(cols, data, colnames);
+       }
+
+       void AffectedReady(SQLite3Result *res)
+       {
+               res->UpdateAffectedCount();
+       }
+
+       int OpenDB()
+       {
+               return sqlite3_open(host.host.c_str(), &conn);
+       }
+
+       void CloseDB()
+       {
+               sqlite3_interrupt(conn);
+               sqlite3_close(conn);
+       }
+
+       SQLhost GetConfHost()
+       {
+               return host;
+       }
+
+       void SendResults()
+       {
+               while (results.size())
+               {
+                       SQLite3Result* res = results[0];
+                       if (res->GetDest())
+                       {
+                               res->Send();
+                       }
+                       else
+                       {
+                               /* If the client module is unloaded partway through a query then the provider will set
+                                * the pointer to NULL. We cannot just cancel the query as the result will still come
+                                * through at some point...and it could get messy if we play with invalid pointers...
+                                */
+                               delete res;
+                       }
+                       results.pop_front();
+               }
+       }
+
+       void ClearResults()
+       {
+               while (results.size())
+               {
+                       SQLite3Result* res = results[0];
+                       delete res;
+                       results.pop_front();
+               }
+       }
+
+       void SendNotify()
+       {
+               int QueueFD;
+               if ((QueueFD = socket(AF_FAMILY, SOCK_STREAM, 0)) == -1)
+               {
+                       /* crap, we're out of sockets... */
+                       return;
+               }
+
+               insp_sockaddr addr;
+
+#ifdef IPV6
+               insp_aton("::1", &addr.sin6_addr);
+               addr.sin6_family = AF_FAMILY;
+               addr.sin6_port = htons(resultnotify->GetPort());
+#else
+               insp_inaddr ia;
+               insp_aton("127.0.0.1", &ia);
+               addr.sin_family = AF_FAMILY;
+               addr.sin_addr = ia;
+               addr.sin_port = htons(resultnotify->GetPort());
+#endif
+
+               if (connect(QueueFD, (sockaddr*)&addr,sizeof(addr)) == -1)
+               {
+                       /* wtf, we cant connect to it, but we just created it! */
+                       return;
+               }
+       }
+
+};
+
+
+class ModuleSQLite3 : public Module
+{
+  private:
+       ConnMap connections;
+       unsigned long currid;
+
+  public:
+       ModuleSQLite3(InspIRCd* Me)
+       : Module::Module(Me), currid(0)
+       {
+               ServerInstance->UseInterface("SQLutils");
+
+               if (!ServerInstance->PublishFeature("SQL", this))
+               {
+                       throw ModuleException("m_sqlite3: Unable to publish feature 'SQL'");
+               }
+
+               resultnotify = new ResultNotifier(ServerInstance, this);
+
+               ReadConf();
+
+               ServerInstance->PublishInterface("SQL", this);
+       }
+
+       virtual ~ModuleSQLite3()
+       {
+               ClearQueue();
+               ClearAllConnections();
+               resultnotify->SetFd(-1);
+               resultnotify->state = I_ERROR;
+               resultnotify->OnError(I_ERR_SOCKET);
+               resultnotify->ClosePending = true;
+               delete resultnotify;
+               ServerInstance->UnpublishInterface("SQL", this);
+               ServerInstance->UnpublishFeature("SQL");
+               ServerInstance->DoneWithInterface("SQLutils");
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnRequest] = List[I_OnRehash] = 1;
+       }
+
+       void SendQueue()
+       {
+               for (ConnMap::iterator iter = connections.begin(); iter != connections.end(); iter++)
+               {
+                       iter->second->SendResults();
+               }
+       }
+
+       void ClearQueue()
+       {
+               for (ConnMap::iterator iter = connections.begin(); iter != connections.end(); iter++)
+               {
+                       iter->second->ClearResults();
+               }
+       }
+
+       bool HasHost(const SQLhost &host)
+       {
+               for (ConnMap::iterator iter = connections.begin(); iter != connections.end(); iter++)
+               {
+                       if (host == iter->second->GetConfHost())
+                               return true;
+               }
+               return false;
+       }
+
+       bool HostInConf(const SQLhost &h)
+       {
+               ConfigReader conf(ServerInstance);
+               for(int i = 0; i < conf.Enumerate("database"); i++)
+               {
+                       SQLhost host;
+                       host.id         = conf.ReadValue("database", "id", i);
+                       host.host       = conf.ReadValue("database", "hostname", i);
+                       host.port       = conf.ReadInteger("database", "port", i, true);
+                       host.name       = conf.ReadValue("database", "name", i);
+                       host.user       = conf.ReadValue("database", "username", i);
+                       host.pass       = conf.ReadValue("database", "password", i);
+                       host.ssl        = conf.ReadFlag("database", "ssl", "0", i);
+                       if (h == host)
+                               return true;
+               }
+               return false;
+       }
+
+       void ReadConf()
+       {
+               ClearOldConnections();
+
+               ConfigReader conf(ServerInstance);
+               for(int i = 0; i < conf.Enumerate("database"); i++)
+               {
+                       SQLhost host;
+
+                       host.id         = conf.ReadValue("database", "id", i);
+                       host.host       = conf.ReadValue("database", "hostname", i);
+                       host.port       = conf.ReadInteger("database", "port", i, true);
+                       host.name       = conf.ReadValue("database", "name", i);
+                       host.user       = conf.ReadValue("database", "username", i);
+                       host.pass       = conf.ReadValue("database", "password", i);
+                       host.ssl        = conf.ReadFlag("database", "ssl", "0", i);
+
+                       if (HasHost(host))
+                               continue;
+
+                       this->AddConn(host);
+               }
+       }
+
+       void AddConn(const SQLhost& hi)
+       {
+               if (HasHost(hi))
+               {
+                       ServerInstance->Log(DEFAULT, "WARNING: A sqlite connection with id: %s already exists. Aborting database open attempt.", hi.id.c_str());
+                       return;
+               }
+
+               SQLConn* newconn;
+
+               newconn = new SQLConn(ServerInstance, this, hi);
+
+               connections.insert(std::make_pair(hi.id, newconn));
+       }
+
+       void ClearOldConnections()
+       {
+               ConnMap::iterator iter,safei;
+               for (iter = connections.begin(); iter != connections.end(); iter++)
+               {
+                       if (!HostInConf(iter->second->GetConfHost()))
+                       {
+                               DELETE(iter->second);
+                               safei = iter;
+                               --iter;
+                               connections.erase(safei);
+                       }
+               }
+       }
+
+       void ClearAllConnections()
+       {
+               ConnMap::iterator i;
+               while ((i = connections.begin()) != connections.end())
+               {
+                       connections.erase(i);
+                       DELETE(i->second);
+               }
+       }
+
+       virtual void OnRehash(userrec* user, const std::string &parameter)
+       {
+               ReadConf();
+       }
+
+       virtual char* OnRequest(Request* request)
+       {
+               if(strcmp(SQLREQID, request->GetId()) == 0)
+               {
+                       SQLrequest* req = (SQLrequest*)request;
+                       ConnMap::iterator iter;
+                       if((iter = connections.find(req->dbid)) != connections.end())
+                       {
+                               req->id = NewID();
+                               req->error = iter->second->Query(*req);
+                               return SQLSUCCESS;
+                       }
+                       else
+                       {
+                               req->error.Id(BAD_DBID);
+                               return NULL;
+                       }
+               }
+               return NULL;
+       }
+
+       unsigned long NewID()
+       {
+               if (currid+1 == 0)
+                       currid++;
+
+               return ++currid;
+       }
+
+       virtual Version GetVersion()
+       {
+               return Version(1,1,0,0,VF_VENDOR|VF_SERVICEPROVIDER,API_VERSION);
+       }
+
+};
+
+void ResultNotifier::Dispatch()
+{
+       ((ModuleSQLite3*)mod)->SendQueue();
+}
+
+MODULE_INIT(ModuleSQLite3);
+
index 04eb1fef1b5cdeb93e489ca1b097aeb178b59f18..391e4bbba4ffb6a82081c504e7c8995b0fc50300 100644 (file)
@@ -1 +1,310 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r#include "configreader.h"\r#include "m_sqlv2.h"\r\rstatic Module* SQLModule;\rstatic Module* MyMod;\rstatic std::string dbid;\r\renum LogTypes { LT_OPER = 1, LT_KILL, LT_SERVLINK, LT_XLINE, LT_CONNECT, LT_DISCONNECT, LT_FLOOD, LT_LOADMODULE };\r\renum QueryState { FIND_SOURCE, FIND_NICK, FIND_HOST, DONE};\r\rclass QueryInfo;\r\rstd::map<unsigned long,QueryInfo*> active_queries;\r\rclass QueryInfo\r{\rpublic:\r    QueryState qs;\r unsigned long id;\r      std::string nick;\r      std::string source;\r    std::string hostname;\r  int sourceid;\r  int nickid;\r    int hostid;\r    int category;\r  time_t date;\r   bool insert;\r\r  QueryInfo(const std::string &n, const std::string &s, const std::string &h, unsigned long i, int cat)\r  {\r              qs = FIND_SOURCE;\r              nick = n;\r              source = s;\r            hostname = h;\r          id = i;\r                category = cat;\r                sourceid = nickid = hostid = -1;\r               date = time(NULL);\r             insert = false;\r        }\r\r     void Go(SQLresult* res)\r        {\r              SQLrequest req = SQLreq(MyMod, SQLModule, dbid, "", "");\r               switch (qs)\r            {\r                      case FIND_SOURCE:\r                              if (res->Rows() && sourceid == -1 && !insert)\r                          {\r                                      sourceid = atoi(res->GetValue(0,0).d.c_str());\r                                 req = SQLreq(MyMod, SQLModule, dbid, "SELECT id,actor FROM ircd_log_actors WHERE actor='?'", nick);\r                                    if(req.Send())\r                                 {\r                                              insert = false;\r                                                qs = FIND_NICK;\r                                                active_queries[req.id] = this;\r                                 }\r                              }\r                              else if (res->Rows() && sourceid == -1 && insert)\r                              {\r                                      req = SQLreq(MyMod, SQLModule, dbid, "SELECT id,actor FROM ircd_log_actors WHERE actor='?'", source);\r                                  if(req.Send())\r                                 {\r                                              insert = false;\r                                                qs = FIND_SOURCE;\r                                              active_queries[req.id] = this;\r                                 }\r                              }\r                              else\r                           {\r                                      req = SQLreq(MyMod, SQLModule, dbid, "INSERT INTO ircd_log_actors (actor) VALUES('?')", source);\r                                       if(req.Send())\r                                 {\r                                              insert = true;\r                                         qs = FIND_SOURCE;\r                                              active_queries[req.id] = this;\r                                 }\r                              }\r                      break;\r\r                        case FIND_NICK:\r                                if (res->Rows() && nickid == -1 && !insert)\r                            {\r                                      nickid = atoi(res->GetValue(0,0).d.c_str());\r                                   req = SQLreq(MyMod, SQLModule, dbid, "SELECT id,hostname FROM ircd_log_hosts WHERE hostname='?'", hostname);\r                                   if(req.Send())\r                                 {\r                                              insert = false;\r                                                qs = FIND_HOST;\r                                                active_queries[req.id] = this;\r                                 }\r                              }\r                              else if (res->Rows() && nickid == -1 && insert)\r                                {\r                                      req = SQLreq(MyMod, SQLModule, dbid, "SELECT id,actor FROM ircd_log_actors WHERE actor='?'", nick);\r                                    if(req.Send())\r                                 {\r                                              insert = false;\r                                                qs = FIND_NICK;\r                                                active_queries[req.id] = this;\r                                 }\r                              }\r                              else\r                           {\r                                      req = SQLreq(MyMod, SQLModule, dbid, "INSERT INTO ircd_log_actors (actor) VALUES('?')",nick);\r                                  if(req.Send())\r                                 {\r                                              insert = true;\r                                         qs = FIND_NICK;\r                                                active_queries[req.id] = this;\r                                 }\r                              }\r                      break;\r\r                        case FIND_HOST:\r                                if (res->Rows() && hostid == -1 && !insert)\r                            {\r                                      hostid = atoi(res->GetValue(0,0).d.c_str());\r                                   req = SQLreq(MyMod, SQLModule, dbid, "INSERT INTO ircd_log (category_id,nick,host,source,dtime) VALUES("+ConvToStr(category)+","+ConvToStr(nickid)+","+ConvToStr(hostid)+","+ConvToStr(sourceid)+","+ConvToStr(date)+")");\r                                     if(req.Send())\r                                 {\r                                              insert = true;\r                                         qs = DONE;\r                                             active_queries[req.id] = this;\r                                 }\r                              }\r                              else if (res->Rows() && hostid == -1 && insert)\r                                {\r                                      req = SQLreq(MyMod, SQLModule, dbid, "SELECT id,hostname FROM ircd_log_hosts WHERE hostname='?'", hostname);\r                                   if(req.Send())\r                                 {\r                                              insert = false;\r                                                qs = FIND_HOST;\r                                                active_queries[req.id] = this;\r                                 }\r                              }\r                              else\r                           {\r                                      req = SQLreq(MyMod, SQLModule, dbid, "INSERT INTO ircd_log_hosts (hostname) VALUES('?')", hostname);\r                                   if(req.Send())\r                                 {\r                                              insert = true;\r                                         qs = FIND_HOST;\r                                                active_queries[req.id] = this;\r                                 }\r                              }\r                      break;\r\r                        case DONE:\r                             delete active_queries[req.id];\r                         active_queries[req.id] = NULL;\r                 break;\r         }\r      }\r};\r\r/* $ModDesc: Logs network-wide data to an SQL database */\r\rclass ModuleSQLLog : public Module\r{\r  ConfigReader* Conf;\r\r public:\r  ModuleSQLLog(InspIRCd* Me)\r     : Module::Module(Me)\r   {\r              ServerInstance->UseInterface("SQLutils");\r              ServerInstance->UseInterface("SQL");\r\r          Module* SQLutils = ServerInstance->FindModule("m_sqlutils.so");\r                if (!SQLutils)\r                 throw ModuleException("Can't find m_sqlutils.so. Please load m_sqlutils.so before m_sqlauth.so.");\r\r            SQLModule = ServerInstance->FindFeature("SQL");\r\r               OnRehash(NULL,"");\r             MyMod = this;\r          active_queries.clear();\r        }\r\r     virtual ~ModuleSQLLog()\r        {\r              ServerInstance->DoneWithInterface("SQL");\r              ServerInstance->DoneWithInterface("SQLutils");\r }\r\r     void Implements(char* List)\r    {\r              List[I_OnRehash] = List[I_OnOper] = List[I_OnGlobalOper] = List[I_OnKill] = 1;\r         List[I_OnPreCommand] = List[I_OnUserConnect] = 1;\r              List[I_OnUserQuit] = List[I_OnLoadModule] = List[I_OnRequest] = 1;\r     }\r\r     void ReadConfig()\r      {\r              ConfigReader Conf(ServerInstance);\r             dbid = Conf.ReadValue("sqllog","dbid",0);       // database id of a database configured in sql module\r  }\r\r     virtual void OnRehash(userrec* user, const std::string &parameter)\r     {\r              ReadConfig();\r  }\r\r     virtual char* OnRequest(Request* request)\r      {\r              if(strcmp(SQLRESID, request->GetId()) == 0)\r            {\r                      SQLresult* res;\r                        std::map<unsigned long, QueryInfo*>::iterator n;\r\r                      res = static_cast<SQLresult*>(request);\r                        n = active_queries.find(res->id);\r\r                     if (n != active_queries.end())\r                 {\r                              n->second->Go(res);\r                            std::map<unsigned long, QueryInfo*>::iterator n = active_queries.find(res->id);\r                                active_queries.erase(n);\r                       }\r\r                     return SQLSUCCESS;\r             }\r\r             return NULL;\r   }\r\r     void AddLogEntry(int category, const std::string &nick, const std::string &host, const std::string &source)\r    {\r              // is the sql module loaded? If not, we don't attempt to do anything.\r          if (!SQLModule)\r                        return;\r\r               SQLrequest req = SQLreq(this, SQLModule, dbid, "SELECT id,actor FROM ircd_log_actors WHERE actor='?'", source);\r                if(req.Send())\r         {\r                      QueryInfo* i = new QueryInfo(nick, source, host, req.id, category);\r                    i->qs = FIND_SOURCE;\r                   active_queries[req.id] = i;\r            }\r      }\r\r     virtual void OnOper(userrec* user, const std::string &opertype)\r        {\r              AddLogEntry(LT_OPER,user->nick,user->host,user->server);\r       }\r\r     virtual void OnGlobalOper(userrec* user)\r       {\r              AddLogEntry(LT_OPER,user->nick,user->host,user->server);\r       }\r\r     virtual int OnKill(userrec* source, userrec* dest, const std::string &reason)\r  {\r              AddLogEntry(LT_KILL,dest->nick,dest->host,source->nick);\r               return 0;\r      }\r\r     virtual int OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line)\r       {\r              if ((command == "GLINE" || command == "KLINE" || command == "ELINE" || command == "ZLINE") && validated)\r               {\r                      AddLogEntry(LT_XLINE,user->nick,command[0]+std::string(":")+std::string(parameters[0]),user->server);\r          }\r              return 0;\r      }\r\r     virtual void OnUserConnect(userrec* user)\r      {\r              AddLogEntry(LT_CONNECT,user->nick,user->host,user->server);\r    }\r\r     virtual void OnUserQuit(userrec* user, const std::string &reason, const std::string &oper_message)\r     {\r              AddLogEntry(LT_DISCONNECT,user->nick,user->host,user->server);\r }\r\r     virtual void OnLoadModule(Module* mod, const std::string &name)\r        {\r              AddLogEntry(LT_LOADMODULE,name,ServerInstance->Config->ServerName, ServerInstance->Config->ServerName);\r        }\r\r     virtual Version GetVersion()\r   {\r              return Version(1,1,0,1,VF_VENDOR,API_VERSION);\r }\r      \r};\r\rMODULE_INIT(ModuleSQLLog);\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+#include "configreader.h"
+#include "m_sqlv2.h"
+
+static Module* SQLModule;
+static Module* MyMod;
+static std::string dbid;
+
+enum LogTypes { LT_OPER = 1, LT_KILL, LT_SERVLINK, LT_XLINE, LT_CONNECT, LT_DISCONNECT, LT_FLOOD, LT_LOADMODULE };
+
+enum QueryState { FIND_SOURCE, FIND_NICK, FIND_HOST, DONE};
+
+class QueryInfo;
+
+std::map<unsigned long,QueryInfo*> active_queries;
+
+class QueryInfo
+{
+public:
+       QueryState qs;
+       unsigned long id;
+       std::string nick;
+       std::string source;
+       std::string hostname;
+       int sourceid;
+       int nickid;
+       int hostid;
+       int category;
+       time_t date;
+       bool insert;
+
+       QueryInfo(const std::string &n, const std::string &s, const std::string &h, unsigned long i, int cat)
+       {
+               qs = FIND_SOURCE;
+               nick = n;
+               source = s;
+               hostname = h;
+               id = i;
+               category = cat;
+               sourceid = nickid = hostid = -1;
+               date = time(NULL);
+               insert = false;
+       }
+
+       void Go(SQLresult* res)
+       {
+               SQLrequest req = SQLreq(MyMod, SQLModule, dbid, "", "");
+               switch (qs)
+               {
+                       case FIND_SOURCE:
+                               if (res->Rows() && sourceid == -1 && !insert)
+                               {
+                                       sourceid = atoi(res->GetValue(0,0).d.c_str());
+                                       req = SQLreq(MyMod, SQLModule, dbid, "SELECT id,actor FROM ircd_log_actors WHERE actor='?'", nick);
+                                       if(req.Send())
+                                       {
+                                               insert = false;
+                                               qs = FIND_NICK;
+                                               active_queries[req.id] = this;
+                                       }
+                               }
+                               else if (res->Rows() && sourceid == -1 && insert)
+                               {
+                                       req = SQLreq(MyMod, SQLModule, dbid, "SELECT id,actor FROM ircd_log_actors WHERE actor='?'", source);
+                                       if(req.Send())
+                                       {
+                                               insert = false;
+                                               qs = FIND_SOURCE;
+                                               active_queries[req.id] = this;
+                                       }
+                               }
+                               else
+                               {
+                                       req = SQLreq(MyMod, SQLModule, dbid, "INSERT INTO ircd_log_actors (actor) VALUES('?')", source);
+                                       if(req.Send())
+                                       {
+                                               insert = true;
+                                               qs = FIND_SOURCE;
+                                               active_queries[req.id] = this;
+                                       }
+                               }
+                       break;
+
+                       case FIND_NICK:
+                               if (res->Rows() && nickid == -1 && !insert)
+                               {
+                                       nickid = atoi(res->GetValue(0,0).d.c_str());
+                                       req = SQLreq(MyMod, SQLModule, dbid, "SELECT id,hostname FROM ircd_log_hosts WHERE hostname='?'", hostname);
+                                       if(req.Send())
+                                       {
+                                               insert = false;
+                                               qs = FIND_HOST;
+                                               active_queries[req.id] = this;
+                                       }
+                               }
+                               else if (res->Rows() && nickid == -1 && insert)
+                               {
+                                       req = SQLreq(MyMod, SQLModule, dbid, "SELECT id,actor FROM ircd_log_actors WHERE actor='?'", nick);
+                                       if(req.Send())
+                                       {
+                                               insert = false;
+                                               qs = FIND_NICK;
+                                               active_queries[req.id] = this;
+                                       }
+                               }
+                               else
+                               {
+                                       req = SQLreq(MyMod, SQLModule, dbid, "INSERT INTO ircd_log_actors (actor) VALUES('?')",nick);
+                                       if(req.Send())
+                                       {
+                                               insert = true;
+                                               qs = FIND_NICK;
+                                               active_queries[req.id] = this;
+                                       }
+                               }
+                       break;
+
+                       case FIND_HOST:
+                               if (res->Rows() && hostid == -1 && !insert)
+                               {
+                                       hostid = atoi(res->GetValue(0,0).d.c_str());
+                                       req = SQLreq(MyMod, SQLModule, dbid, "INSERT INTO ircd_log (category_id,nick,host,source,dtime) VALUES("+ConvToStr(category)+","+ConvToStr(nickid)+","+ConvToStr(hostid)+","+ConvToStr(sourceid)+","+ConvToStr(date)+")");
+                                       if(req.Send())
+                                       {
+                                               insert = true;
+                                               qs = DONE;
+                                               active_queries[req.id] = this;
+                                       }
+                               }
+                               else if (res->Rows() && hostid == -1 && insert)
+                               {
+                                       req = SQLreq(MyMod, SQLModule, dbid, "SELECT id,hostname FROM ircd_log_hosts WHERE hostname='?'", hostname);
+                                       if(req.Send())
+                                       {
+                                               insert = false;
+                                               qs = FIND_HOST;
+                                               active_queries[req.id] = this;
+                                       }
+                               }
+                               else
+                               {
+                                       req = SQLreq(MyMod, SQLModule, dbid, "INSERT INTO ircd_log_hosts (hostname) VALUES('?')", hostname);
+                                       if(req.Send())
+                                       {
+                                               insert = true;
+                                               qs = FIND_HOST;
+                                               active_queries[req.id] = this;
+                                       }
+                               }
+                       break;
+
+                       case DONE:
+                               delete active_queries[req.id];
+                               active_queries[req.id] = NULL;
+                       break;
+               }
+       }
+};
+
+/* $ModDesc: Logs network-wide data to an SQL database */
+
+class ModuleSQLLog : public Module
+{
+       ConfigReader* Conf;
+
+ public:
+       ModuleSQLLog(InspIRCd* Me)
+       : Module::Module(Me)
+       {
+               ServerInstance->UseInterface("SQLutils");
+               ServerInstance->UseInterface("SQL");
+
+               Module* SQLutils = ServerInstance->FindModule("m_sqlutils.so");
+               if (!SQLutils)
+                       throw ModuleException("Can't find m_sqlutils.so. Please load m_sqlutils.so before m_sqlauth.so.");
+
+               SQLModule = ServerInstance->FindFeature("SQL");
+
+               OnRehash(NULL,"");
+               MyMod = this;
+               active_queries.clear();
+       }
+
+       virtual ~ModuleSQLLog()
+       {
+               ServerInstance->DoneWithInterface("SQL");
+               ServerInstance->DoneWithInterface("SQLutils");
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnRehash] = List[I_OnOper] = List[I_OnGlobalOper] = List[I_OnKill] = 1;
+               List[I_OnPreCommand] = List[I_OnUserConnect] = 1;
+               List[I_OnUserQuit] = List[I_OnLoadModule] = List[I_OnRequest] = 1;
+       }
+
+       void ReadConfig()
+       {
+               ConfigReader Conf(ServerInstance);
+               dbid = Conf.ReadValue("sqllog","dbid",0);       // database id of a database configured in sql module
+       }
+
+       virtual void OnRehash(userrec* user, const std::string &parameter)
+       {
+               ReadConfig();
+       }
+
+       virtual char* OnRequest(Request* request)
+       {
+               if(strcmp(SQLRESID, request->GetId()) == 0)
+               {
+                       SQLresult* res;
+                       std::map<unsigned long, QueryInfo*>::iterator n;
+
+                       res = static_cast<SQLresult*>(request);
+                       n = active_queries.find(res->id);
+
+                       if (n != active_queries.end())
+                       {
+                               n->second->Go(res);
+                               std::map<unsigned long, QueryInfo*>::iterator n = active_queries.find(res->id);
+                               active_queries.erase(n);
+                       }
+
+                       return SQLSUCCESS;
+               }
+
+               return NULL;
+       }
+
+       void AddLogEntry(int category, const std::string &nick, const std::string &host, const std::string &source)
+       {
+               // is the sql module loaded? If not, we don't attempt to do anything.
+               if (!SQLModule)
+                       return;
+
+               SQLrequest req = SQLreq(this, SQLModule, dbid, "SELECT id,actor FROM ircd_log_actors WHERE actor='?'", source);
+               if(req.Send())
+               {
+                       QueryInfo* i = new QueryInfo(nick, source, host, req.id, category);
+                       i->qs = FIND_SOURCE;
+                       active_queries[req.id] = i;
+               }
+       }
+
+       virtual void OnOper(userrec* user, const std::string &opertype)
+       {
+               AddLogEntry(LT_OPER,user->nick,user->host,user->server);
+       }
+
+       virtual void OnGlobalOper(userrec* user)
+       {
+               AddLogEntry(LT_OPER,user->nick,user->host,user->server);
+       }
+
+       virtual int OnKill(userrec* source, userrec* dest, const std::string &reason)
+       {
+               AddLogEntry(LT_KILL,dest->nick,dest->host,source->nick);
+               return 0;
+       }
+
+       virtual int OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line)
+       {
+               if ((command == "GLINE" || command == "KLINE" || command == "ELINE" || command == "ZLINE") && validated)
+               {
+                       AddLogEntry(LT_XLINE,user->nick,command[0]+std::string(":")+std::string(parameters[0]),user->server);
+               }
+               return 0;
+       }
+
+       virtual void OnUserConnect(userrec* user)
+       {
+               AddLogEntry(LT_CONNECT,user->nick,user->host,user->server);
+       }
+
+       virtual void OnUserQuit(userrec* user, const std::string &reason, const std::string &oper_message)
+       {
+               AddLogEntry(LT_DISCONNECT,user->nick,user->host,user->server);
+       }
+
+       virtual void OnLoadModule(Module* mod, const std::string &name)
+       {
+               AddLogEntry(LT_LOADMODULE,name,ServerInstance->Config->ServerName, ServerInstance->Config->ServerName);
+       }
+
+       virtual Version GetVersion()
+       {
+               return Version(1,1,0,1,VF_VENDOR,API_VERSION);
+       }
+       
+};
+
+MODULE_INIT(ModuleSQLLog);
+
index 4b09ac26eb377607593acf530424192b348dda1f..520869e210b3074d1fa02ffe3f6f0a34a7a19d24 100644 (file)
@@ -1 +1,283 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r#include "configreader.h"\r\r#include "m_sqlv2.h"\r#include "m_sqlutils.h"\r#include "m_hash.h"\r#include "commands/cmd_oper.h"\r\r/* $ModDesc: Allows storage of oper credentials in an SQL table */\r/* $ModDep: m_sqlv2.h m_sqlutils.h */\r\rclass ModuleSQLOper : public Module\r{\r   Module* SQLutils;\r      Module* HashModule;\r    std::string databaseid;\r\rpublic:\r       ModuleSQLOper(InspIRCd* Me)\r    : Module::Module(Me)\r   {\r              ServerInstance->UseInterface("SQLutils");\r              ServerInstance->UseInterface("SQL");\r           ServerInstance->UseInterface("HashRequest");\r\r          /* Attempt to locate the md5 service provider, bail if we can't find it */\r             HashModule = ServerInstance->FindModule("m_md5.so");\r           if (!HashModule)\r                       throw ModuleException("Can't find m_md5.so. Please load m_md5.so before m_sqloper.so.");\r\r              SQLutils = ServerInstance->FindModule("m_sqlutils.so");\r                if (!SQLutils)\r                 throw ModuleException("Can't find m_sqlutils.so. Please load m_sqlutils.so before m_sqloper.so.");\r\r            OnRehash(NULL,"");\r     }\r\r     virtual ~ModuleSQLOper()\r       {\r              ServerInstance->DoneWithInterface("SQL");\r              ServerInstance->DoneWithInterface("SQLutils");\r         ServerInstance->DoneWithInterface("HashRequest");\r      }\r\r     void Implements(char* List)\r    {\r              List[I_OnRequest] = List[I_OnRehash] = List[I_OnPreCommand] = 1;\r       }\r\r     virtual void OnRehash(userrec* user, const std::string &parameter)\r     {\r              ConfigReader Conf(ServerInstance);\r             \r               databaseid = Conf.ReadValue("sqloper", "dbid", 0); /* Database ID of a database configured for the service provider module */\r  }\r\r     virtual int OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line)\r       {\r              if ((validated) && (command == "OPER"))\r                {\r                      if (LookupOper(user, parameters[0], parameters[1]))\r                    {       \r                               /* Returning true here just means the query is in progress, or on it's way to being\r                             * in progress. Nothing about the /oper actually being successful..\r                             * If the oper lookup fails later, we pass the command to the original handler\r                          * for /oper by calling its Handle method directly.\r                             */\r                            return 1;\r                      }\r              }\r              return 0;\r      }\r\r     bool LookupOper(userrec* user, const std::string &username, const std::string &password)\r       {\r              Module* target;\r                \r               target = ServerInstance->FindFeature("SQL");\r\r          if (target)\r            {\r                      /* Reset hash module first back to MD5 standard state */\r                       HashResetRequest(this, HashModule).Send();\r                     /* Make an MD5 hash of the password for using in the query */\r                  std::string md5_pass_hash = HashSumRequest(this, HashModule, password.c_str()).Send();\r\r                        /* We generate our own MD5 sum here because some database providers (e.g. SQLite) dont have a builtin md5 function,\r                     * also hashing it in the module and only passing a remote query containing a hash is more secure.\r                      */\r\r                   SQLrequest req = SQLreq(this, target, databaseid, "SELECT username, password, hostname, type FROM ircd_opers WHERE username = '?' AND password='?'", username, md5_pass_hash);\r                 \r                       if (req.Send())\r                        {\r                              /* When we get the query response from the service provider we will be given an ID to play with,\r                                * just an ID number which is unique to this query. We need a way of associating that ID with a userrec\r                                 * so we insert it into a map mapping the IDs to users.\r                                 * Thankfully m_sqlutils provides this, it will associate a ID with a user or channel, and if the user quits it removes the\r                             * association. This means that if the user quits during a query we will just get a failed lookup from m_sqlutils - telling\r                             * us to discard the query.\r                             */\r                            AssociateUser(this, SQLutils, req.id, user).Send();\r\r                           user->Extend("oper_user", strdup(username.c_str()));\r                           user->Extend("oper_pass", strdup(password.c_str()));\r                                   \r                               return true;\r                   }\r                      else\r                   {\r                              return false;\r                  }\r              }\r              else\r           {\r                      ServerInstance->Log(SPARSE, "WARNING: Couldn't find SQL provider module. NOBODY will be able to oper up unless their o:line is statically configured");\r                        return false;\r          }\r      }\r      \r       virtual char* OnRequest(Request* request)\r      {\r              if (strcmp(SQLRESID, request->GetId()) == 0)\r           {\r                      SQLresult* res = static_cast<SQLresult*>(request);\r\r                    userrec* user = GetAssocUser(this, SQLutils, res->id).S().user;\r                        UnAssociate(this, SQLutils, res->id).S();\r\r                     char* tried_user = NULL;\r                       char* tried_pass = NULL;\r\r                      user->GetExt("oper_user", tried_user);\r                 user->GetExt("oper_pass", tried_pass);\r                 \r                       if (user)\r                      {\r                              if (res->error.Id() == NO_ERROR)\r                               {\r                                      if (res->Rows())\r                                       {\r                                              /* We got a row in the result, this means there was a record for the oper..\r                                             * now we just need to check if their host matches, and if it does then\r                                                 * oper them up.\r                                                * \r                                             * We now (previous versions of the module didn't) support multiple SQL\r                                                 * rows per-oper in the same way the config file does, all rows will be tried\r                                           * until one is found which matches. This is useful to define several different\r                                                 * hosts for a single oper.\r                                             * \r                                             * The for() loop works as SQLresult::GetRowMap() returns an empty map when there\r                                               * are no more rows to return.\r                                          */\r                                            \r                                               for (SQLfieldMap& row = res->GetRowMap(); row.size(); row = res->GetRowMap())\r                                          {                                                       \r                                                       if (OperUser(user, row["username"].d, row["password"].d, row["hostname"].d, row["type"].d))\r                                                    {\r                                                              /* If/when one of the rows matches, stop checking and return */\r                                                                return SQLSUCCESS;\r                                                     }\r                                                      if (tried_user && tried_pass)\r                                                  {\r                                                              LoginFail(user, tried_user, tried_pass);\r                                                               free(tried_user);\r                                                              free(tried_pass);\r                                                              user->Shrink("oper_user");\r                                                             user->Shrink("oper_pass");\r                                                     }\r                                              }\r                                      }\r                                      else\r                                   {\r                                              /* No rows in result, this means there was no oper line for the user,\r                                           * we should have already checked the o:lines so now we need an\r                                                 * "insufficient awesomeness" (invalid credentials) error\r                                               */\r                                            if (tried_user && tried_pass)\r                                          {\r                                                      LoginFail(user, tried_user, tried_pass);\r                                                       free(tried_user);\r                                                      free(tried_pass);\r                                                      user->Shrink("oper_user");\r                                                     user->Shrink("oper_pass");\r                                             }\r                                      }\r                              }\r                              else\r                           {\r                                      /* This one shouldn't happen, the query failed for some reason.\r                                         * We have to fail the /oper request and give them the same error\r                                       * as above.\r                                    */\r                                    if (tried_user && tried_pass)\r                                  {\r                                              LoginFail(user, tried_user, tried_pass);\r                                               free(tried_user);\r                                              free(tried_pass);\r                                              user->Shrink("oper_user");\r                                             user->Shrink("oper_pass");\r                                     }\r\r                             }\r                      }\r              \r                       return SQLSUCCESS;\r             }\r\r             return NULL;\r   }\r\r     void LoginFail(userrec* user, const std::string &username, const std::string &pass)\r    {\r              command_t* oper_command = ServerInstance->Parser->GetHandler("OPER");\r\r         if (oper_command)\r              {\r                      const char* params[] = { username.c_str(), pass.c_str() };\r                     oper_command->Handle(params, 2, user);\r         }\r              else\r           {\r                      ServerInstance->Log(DEBUG, "BUG: WHAT?! Why do we have no OPER command?!");\r            }\r      }\r\r     bool OperUser(userrec* user, const std::string &username, const std::string &password, const std::string &pattern, const std::string &type)\r    {\r              ConfigReader Conf(ServerInstance);\r             \r               for (int j = 0; j < Conf.Enumerate("type"); j++)\r               {\r                      std::string tname = Conf.ReadValue("type","name",j);\r                   std::string hostname(user->ident);\r\r                    hostname.append("@").append(user->host);\r                                                       \r                       if ((tname == type) && OneOfMatches(hostname.c_str(), user->GetIPString(), pattern.c_str()))\r                   {\r                              /* Opertype and host match, looks like this is it. */\r                          std::string operhost = Conf.ReadValue("type", "host", j);\r\r                             if (operhost.size())\r                                   user->ChangeDisplayedHost(operhost.c_str());\r\r                          ServerInstance->SNO->WriteToSnoMask('o',"%s (%s@%s) is now an IRC operator of type %s", user->nick, user->ident, user->host, type.c_str());\r                            user->WriteServ("381 %s :You are now an IRC operator of type %s", user->nick, type.c_str());\r\r                          if (!user->modes[UM_OPERATOR])\r                                 user->Oper(type);\r\r                             return true;\r                   }\r              }\r              \r               return false;\r  }\r\r     virtual Version GetVersion()\r   {\r              return Version(1,1,1,0,VF_VENDOR,API_VERSION);\r }\r      \r};\r\rMODULE_INIT(ModuleSQLOper);\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+#include "configreader.h"
+
+#include "m_sqlv2.h"
+#include "m_sqlutils.h"
+#include "m_hash.h"
+#include "commands/cmd_oper.h"
+
+/* $ModDesc: Allows storage of oper credentials in an SQL table */
+/* $ModDep: m_sqlv2.h m_sqlutils.h */
+
+class ModuleSQLOper : public Module
+{
+       Module* SQLutils;
+       Module* HashModule;
+       std::string databaseid;
+
+public:
+       ModuleSQLOper(InspIRCd* Me)
+       : Module::Module(Me)
+       {
+               ServerInstance->UseInterface("SQLutils");
+               ServerInstance->UseInterface("SQL");
+               ServerInstance->UseInterface("HashRequest");
+
+               /* Attempt to locate the md5 service provider, bail if we can't find it */
+               HashModule = ServerInstance->FindModule("m_md5.so");
+               if (!HashModule)
+                       throw ModuleException("Can't find m_md5.so. Please load m_md5.so before m_sqloper.so.");
+
+               SQLutils = ServerInstance->FindModule("m_sqlutils.so");
+               if (!SQLutils)
+                       throw ModuleException("Can't find m_sqlutils.so. Please load m_sqlutils.so before m_sqloper.so.");
+
+               OnRehash(NULL,"");
+       }
+
+       virtual ~ModuleSQLOper()
+       {
+               ServerInstance->DoneWithInterface("SQL");
+               ServerInstance->DoneWithInterface("SQLutils");
+               ServerInstance->DoneWithInterface("HashRequest");
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnRequest] = List[I_OnRehash] = List[I_OnPreCommand] = 1;
+       }
+
+       virtual void OnRehash(userrec* user, const std::string &parameter)
+       {
+               ConfigReader Conf(ServerInstance);
+               
+               databaseid = Conf.ReadValue("sqloper", "dbid", 0); /* Database ID of a database configured for the service provider module */
+       }
+
+       virtual int OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line)
+       {
+               if ((validated) && (command == "OPER"))
+               {
+                       if (LookupOper(user, parameters[0], parameters[1]))
+                       {       
+                               /* Returning true here just means the query is in progress, or on it's way to being
+                                * in progress. Nothing about the /oper actually being successful..
+                                * If the oper lookup fails later, we pass the command to the original handler
+                                * for /oper by calling its Handle method directly.
+                                */
+                               return 1;
+                       }
+               }
+               return 0;
+       }
+
+       bool LookupOper(userrec* user, const std::string &username, const std::string &password)
+       {
+               Module* target;
+               
+               target = ServerInstance->FindFeature("SQL");
+
+               if (target)
+               {
+                       /* Reset hash module first back to MD5 standard state */
+                       HashResetRequest(this, HashModule).Send();
+                       /* Make an MD5 hash of the password for using in the query */
+                       std::string md5_pass_hash = HashSumRequest(this, HashModule, password.c_str()).Send();
+
+                       /* We generate our own MD5 sum here because some database providers (e.g. SQLite) dont have a builtin md5 function,
+                        * also hashing it in the module and only passing a remote query containing a hash is more secure.
+                        */
+
+                       SQLrequest req = SQLreq(this, target, databaseid, "SELECT username, password, hostname, type FROM ircd_opers WHERE username = '?' AND password='?'", username, md5_pass_hash);
+                       
+                       if (req.Send())
+                       {
+                               /* When we get the query response from the service provider we will be given an ID to play with,
+                                * just an ID number which is unique to this query. We need a way of associating that ID with a userrec
+                                * so we insert it into a map mapping the IDs to users.
+                                * Thankfully m_sqlutils provides this, it will associate a ID with a user or channel, and if the user quits it removes the
+                                * association. This means that if the user quits during a query we will just get a failed lookup from m_sqlutils - telling
+                                * us to discard the query.
+                                */
+                               AssociateUser(this, SQLutils, req.id, user).Send();
+
+                               user->Extend("oper_user", strdup(username.c_str()));
+                               user->Extend("oper_pass", strdup(password.c_str()));
+                                       
+                               return true;
+                       }
+                       else
+                       {
+                               return false;
+                       }
+               }
+               else
+               {
+                       ServerInstance->Log(SPARSE, "WARNING: Couldn't find SQL provider module. NOBODY will be able to oper up unless their o:line is statically configured");
+                       return false;
+               }
+       }
+       
+       virtual char* OnRequest(Request* request)
+       {
+               if (strcmp(SQLRESID, request->GetId()) == 0)
+               {
+                       SQLresult* res = static_cast<SQLresult*>(request);
+
+                       userrec* user = GetAssocUser(this, SQLutils, res->id).S().user;
+                       UnAssociate(this, SQLutils, res->id).S();
+
+                       char* tried_user = NULL;
+                       char* tried_pass = NULL;
+
+                       user->GetExt("oper_user", tried_user);
+                       user->GetExt("oper_pass", tried_pass);
+                       
+                       if (user)
+                       {
+                               if (res->error.Id() == NO_ERROR)
+                               {
+                                       if (res->Rows())
+                                       {
+                                               /* We got a row in the result, this means there was a record for the oper..
+                                                * now we just need to check if their host matches, and if it does then
+                                                * oper them up.
+                                                * 
+                                                * We now (previous versions of the module didn't) support multiple SQL
+                                                * rows per-oper in the same way the config file does, all rows will be tried
+                                                * until one is found which matches. This is useful to define several different
+                                                * hosts for a single oper.
+                                                * 
+                                                * The for() loop works as SQLresult::GetRowMap() returns an empty map when there
+                                                * are no more rows to return.
+                                                */
+                                               
+                                               for (SQLfieldMap& row = res->GetRowMap(); row.size(); row = res->GetRowMap())
+                                               {                                                       
+                                                       if (OperUser(user, row["username"].d, row["password"].d, row["hostname"].d, row["type"].d))
+                                                       {
+                                                               /* If/when one of the rows matches, stop checking and return */
+                                                               return SQLSUCCESS;
+                                                       }
+                                                       if (tried_user && tried_pass)
+                                                       {
+                                                               LoginFail(user, tried_user, tried_pass);
+                                                               free(tried_user);
+                                                               free(tried_pass);
+                                                               user->Shrink("oper_user");
+                                                               user->Shrink("oper_pass");
+                                                       }
+                                               }
+                                       }
+                                       else
+                                       {
+                                               /* No rows in result, this means there was no oper line for the user,
+                                                * we should have already checked the o:lines so now we need an
+                                                * "insufficient awesomeness" (invalid credentials) error
+                                                */
+                                               if (tried_user && tried_pass)
+                                               {
+                                                       LoginFail(user, tried_user, tried_pass);
+                                                       free(tried_user);
+                                                       free(tried_pass);
+                                                       user->Shrink("oper_user");
+                                                       user->Shrink("oper_pass");
+                                               }
+                                       }
+                               }
+                               else
+                               {
+                                       /* This one shouldn't happen, the query failed for some reason.
+                                        * We have to fail the /oper request and give them the same error
+                                        * as above.
+                                        */
+                                       if (tried_user && tried_pass)
+                                       {
+                                               LoginFail(user, tried_user, tried_pass);
+                                               free(tried_user);
+                                               free(tried_pass);
+                                               user->Shrink("oper_user");
+                                               user->Shrink("oper_pass");
+                                       }
+
+                               }
+                       }
+               
+                       return SQLSUCCESS;
+               }
+
+               return NULL;
+       }
+
+       void LoginFail(userrec* user, const std::string &username, const std::string &pass)
+       {
+               command_t* oper_command = ServerInstance->Parser->GetHandler("OPER");
+
+               if (oper_command)
+               {
+                       const char* params[] = { username.c_str(), pass.c_str() };
+                       oper_command->Handle(params, 2, user);
+               }
+               else
+               {
+                       ServerInstance->Log(DEBUG, "BUG: WHAT?! Why do we have no OPER command?!");
+               }
+       }
+
+       bool OperUser(userrec* user, const std::string &username, const std::string &password, const std::string &pattern, const std::string &type)
+       {
+               ConfigReader Conf(ServerInstance);
+               
+               for (int j = 0; j < Conf.Enumerate("type"); j++)
+               {
+                       std::string tname = Conf.ReadValue("type","name",j);
+                       std::string hostname(user->ident);
+
+                       hostname.append("@").append(user->host);
+                                                       
+                       if ((tname == type) && OneOfMatches(hostname.c_str(), user->GetIPString(), pattern.c_str()))
+                       {
+                               /* Opertype and host match, looks like this is it. */
+                               std::string operhost = Conf.ReadValue("type", "host", j);
+
+                               if (operhost.size())
+                                       user->ChangeDisplayedHost(operhost.c_str());
+
+                               ServerInstance->SNO->WriteToSnoMask('o',"%s (%s@%s) is now an IRC operator of type %s", user->nick, user->ident, user->host, type.c_str());
+                               user->WriteServ("381 %s :You are now an IRC operator of type %s", user->nick, type.c_str());
+
+                               if (!user->modes[UM_OPERATOR])
+                                       user->Oper(type);
+
+                               return true;
+                       }
+               }
+               
+               return false;
+       }
+
+       virtual Version GetVersion()
+       {
+               return Version(1,1,1,0,VF_VENDOR,API_VERSION);
+       }
+       
+};
+
+MODULE_INIT(ModuleSQLOper);
+
index 6cd09252b2a19e55e9b8d2dbaf375686208864b3..b470f99af3bffe41d8465204fc6ceaef91961192 100644 (file)
@@ -1 +1,238 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include <sstream>\r#include <list>\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r#include "configreader.h"\r#include "m_sqlutils.h"\r\r/* $ModDesc: Provides some utilities to SQL client modules, such as mapping queries to users and channels */\r/* $ModDep: m_sqlutils.h */\r\rtypedef std::map<unsigned long, userrec*> IdUserMap;\rtypedef std::map<unsigned long, chanrec*> IdChanMap;\rtypedef std::list<unsigned long> AssocIdList;\r\rclass ModuleSQLutils : public Module\r{\rprivate:\r      IdUserMap iduser;\r      IdChanMap idchan;\r\rpublic:\r     ModuleSQLutils(InspIRCd* Me)\r   : Module::Module(Me)\r   {\r              ServerInstance->PublishInterface("SQLutils", this);\r    }\r\r     virtual ~ModuleSQLutils()\r      {\r              ServerInstance->UnpublishInterface("SQLutils", this);\r  }       \r\r      void Implements(char* List)\r    {\r              List[I_OnChannelDelete] = List[I_OnUnloadModule] = List[I_OnRequest] =  List[I_OnUserDisconnect] = 1;\r  }\r\r     virtual char* OnRequest(Request* request)\r      {\r              if(strcmp(SQLUTILAU, request->GetId()) == 0)\r           {\r                      AssociateUser* req = (AssociateUser*)request;\r                  \r                       iduser.insert(std::make_pair(req->id, req->user));\r                     \r                       AttachList(req->user, req->id);\r                }\r              else if(strcmp(SQLUTILAC, request->GetId()) == 0)\r              {\r                      AssociateChan* req = (AssociateChan*)request;\r                  \r                       idchan.insert(std::make_pair(req->id, req->chan));                      \r                       \r                       AttachList(req->chan, req->id);\r                }\r              else if(strcmp(SQLUTILUA, request->GetId()) == 0)\r              {\r                      UnAssociate* req = (UnAssociate*)request;\r                      \r                       /* Unassociate a given query ID with all users and channels\r                     * it is associated with.\r                       */\r                    \r                       DoUnAssociate(iduser, req->id);\r                        DoUnAssociate(idchan, req->id);\r                }\r              else if(strcmp(SQLUTILGU, request->GetId()) == 0)\r              {\r                      GetAssocUser* req = (GetAssocUser*)request;\r                    \r                       IdUserMap::iterator iter = iduser.find(req->id);\r                       \r                       if(iter != iduser.end())\r                       {\r                              req->user = iter->second;\r                      }\r              }\r              else if(strcmp(SQLUTILGC, request->GetId()) == 0)\r              {\r                      GetAssocChan* req = (GetAssocChan*)request;                     \r                       \r                       IdChanMap::iterator iter = idchan.find(req->id);\r                       \r                       if(iter != idchan.end())\r                       {\r                              req->chan = iter->second;\r                      }\r              }\r              \r               return SQLUTILSUCCESS;\r }\r      \r       virtual void OnUserDisconnect(userrec* user)\r   {\r              /* A user is disconnecting, first we need to check if they have a list of queries associated with them.\r                 * Then, if they do, we need to erase each of them from our IdUserMap (iduser) so when the module that\r          * associated them asks to look them up then it gets a NULL result and knows to discard the query.\r              */\r            AssocIdList* il;\r               \r               if(user->GetExt("sqlutils_queryids", il))\r              {\r                      for(AssocIdList::iterator listiter = il->begin(); listiter != il->end(); listiter++)\r                   {\r                              IdUserMap::iterator iter;\r                      \r                               iter = iduser.find(*listiter);\r                 \r                               if(iter != iduser.end())\r                               {\r                                      if(iter->second != user)\r                                       {\r                                              ServerInstance->Log(DEBUG, "BUG: ID associated with user %s doesn't have the same userrec* associated with it in the map (erasing anyway)", user->nick);\r                                       }\r\r                                     iduser.erase(iter);\r                            }\r                              else\r                           {\r                                      ServerInstance->Log(DEBUG, "BUG: user %s was extended with sqlutils_queryids but there was nothing matching in the map", user->nick);\r                          }\r                      }\r                      \r                       user->Shrink("sqlutils_queryids");\r                     delete il;\r             }\r      }\r      \r       void AttachList(Extensible* obj, unsigned long id)\r     {\r              AssocIdList* il;\r               \r               if(!obj->GetExt("sqlutils_queryids", il))\r              {\r                      /* Doesn't already exist, create a new list and attach it. */\r                  il = new AssocIdList;\r                  obj->Extend("sqlutils_queryids", il);\r          }\r              \r               /* Now either way we have a valid list in il, attached. */\r             il->push_back(id);\r     }\r      \r       void RemoveFromList(Extensible* obj, unsigned long id)\r {\r              AssocIdList* il;\r               \r               if(obj->GetExt("sqlutils_queryids", il))\r               {\r                      /* Only do anything if the list exists... (which it ought to) */\r                       il->remove(id);\r                        \r                       if(il->empty())\r                        {\r                              /* If we just emptied it.. */\r                          delete il;\r                             obj->Shrink("sqlutils_queryids");\r                      }\r              }\r      }\r      \r       template <class T> void DoUnAssociate(T &map, unsigned long id)\r        {\r              /* For each occurence of 'id' (well, only one..it's not a multimap) in 'map'\r            * remove it from the map, take an Extensible* value from the map and remove\r            * 'id' from the list of query IDs attached to it.\r              */\r            typename T::iterator iter = map.find(id);\r              \r               if(iter != map.end())\r          {\r                      /* Found a value indexed by 'id', call RemoveFromList()\r                         * on it with 'id' to remove 'id' from the list attached\r                        * to the value.\r                        */\r                    RemoveFromList(iter->second, id);\r              }\r      }\r      \r       virtual void OnChannelDelete(chanrec* chan)\r    {\r              /* A channel is being destroyed, first we need to check if it has a list of queries associated with it.\r                 * Then, if it does, we need to erase each of them from our IdChanMap (idchan) so when the module that\r          * associated them asks to look them up then it gets a NULL result and knows to discard the query.\r              */\r            AssocIdList* il;\r               \r               if(chan->GetExt("sqlutils_queryids", il))\r              {\r                      for(AssocIdList::iterator listiter = il->begin(); listiter != il->end(); listiter++)\r                   {\r                              IdChanMap::iterator iter;\r                      \r                               iter = idchan.find(*listiter);\r                 \r                               if(iter != idchan.end())\r                               {\r                                      if(iter->second != chan)\r                                       {\r                                              ServerInstance->Log(DEBUG, "BUG: ID associated with channel %s doesn't have the same chanrec* associated with it in the map (erasing anyway)", chan->name);\r                                    }\r                                      idchan.erase(iter);                                     \r                               }\r                              else\r                           {\r                                      ServerInstance->Log(DEBUG, "BUG: channel %s was extended with sqlutils_queryids but there was nothing matching in the map", chan->name);\r                               }\r                      }\r                      \r                       chan->Shrink("sqlutils_queryids");\r                     delete il;\r             }\r      }\r                      \r       virtual Version GetVersion()\r   {\r              return Version(1, 1, 0, 0, VF_VENDOR|VF_SERVICEPROVIDER, API_VERSION);\r }\r      \r};\r\rMODULE_INIT(ModuleSQLutils);\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include <sstream>
+#include <list>
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+#include "configreader.h"
+#include "m_sqlutils.h"
+
+/* $ModDesc: Provides some utilities to SQL client modules, such as mapping queries to users and channels */
+/* $ModDep: m_sqlutils.h */
+
+typedef std::map<unsigned long, userrec*> IdUserMap;
+typedef std::map<unsigned long, chanrec*> IdChanMap;
+typedef std::list<unsigned long> AssocIdList;
+
+class ModuleSQLutils : public Module
+{
+private:
+       IdUserMap iduser;
+       IdChanMap idchan;
+
+public:
+       ModuleSQLutils(InspIRCd* Me)
+       : Module::Module(Me)
+       {
+               ServerInstance->PublishInterface("SQLutils", this);
+       }
+
+       virtual ~ModuleSQLutils()
+       {
+               ServerInstance->UnpublishInterface("SQLutils", this);
+       }       
+
+       void Implements(char* List)
+       {
+               List[I_OnChannelDelete] = List[I_OnUnloadModule] = List[I_OnRequest] =  List[I_OnUserDisconnect] = 1;
+       }
+
+       virtual char* OnRequest(Request* request)
+       {
+               if(strcmp(SQLUTILAU, request->GetId()) == 0)
+               {
+                       AssociateUser* req = (AssociateUser*)request;
+                       
+                       iduser.insert(std::make_pair(req->id, req->user));
+                       
+                       AttachList(req->user, req->id);
+               }
+               else if(strcmp(SQLUTILAC, request->GetId()) == 0)
+               {
+                       AssociateChan* req = (AssociateChan*)request;
+                       
+                       idchan.insert(std::make_pair(req->id, req->chan));                      
+                       
+                       AttachList(req->chan, req->id);
+               }
+               else if(strcmp(SQLUTILUA, request->GetId()) == 0)
+               {
+                       UnAssociate* req = (UnAssociate*)request;
+                       
+                       /* Unassociate a given query ID with all users and channels
+                        * it is associated with.
+                        */
+                       
+                       DoUnAssociate(iduser, req->id);
+                       DoUnAssociate(idchan, req->id);
+               }
+               else if(strcmp(SQLUTILGU, request->GetId()) == 0)
+               {
+                       GetAssocUser* req = (GetAssocUser*)request;
+                       
+                       IdUserMap::iterator iter = iduser.find(req->id);
+                       
+                       if(iter != iduser.end())
+                       {
+                               req->user = iter->second;
+                       }
+               }
+               else if(strcmp(SQLUTILGC, request->GetId()) == 0)
+               {
+                       GetAssocChan* req = (GetAssocChan*)request;                     
+                       
+                       IdChanMap::iterator iter = idchan.find(req->id);
+                       
+                       if(iter != idchan.end())
+                       {
+                               req->chan = iter->second;
+                       }
+               }
+               
+               return SQLUTILSUCCESS;
+       }
+       
+       virtual void OnUserDisconnect(userrec* user)
+       {
+               /* A user is disconnecting, first we need to check if they have a list of queries associated with them.
+                * Then, if they do, we need to erase each of them from our IdUserMap (iduser) so when the module that
+                * associated them asks to look them up then it gets a NULL result and knows to discard the query.
+                */
+               AssocIdList* il;
+               
+               if(user->GetExt("sqlutils_queryids", il))
+               {
+                       for(AssocIdList::iterator listiter = il->begin(); listiter != il->end(); listiter++)
+                       {
+                               IdUserMap::iterator iter;
+                       
+                               iter = iduser.find(*listiter);
+                       
+                               if(iter != iduser.end())
+                               {
+                                       if(iter->second != user)
+                                       {
+                                               ServerInstance->Log(DEBUG, "BUG: ID associated with user %s doesn't have the same userrec* associated with it in the map (erasing anyway)", user->nick);
+                                       }
+
+                                       iduser.erase(iter);
+                               }
+                               else
+                               {
+                                       ServerInstance->Log(DEBUG, "BUG: user %s was extended with sqlutils_queryids but there was nothing matching in the map", user->nick);
+                               }
+                       }
+                       
+                       user->Shrink("sqlutils_queryids");
+                       delete il;
+               }
+       }
+       
+       void AttachList(Extensible* obj, unsigned long id)
+       {
+               AssocIdList* il;
+               
+               if(!obj->GetExt("sqlutils_queryids", il))
+               {
+                       /* Doesn't already exist, create a new list and attach it. */
+                       il = new AssocIdList;
+                       obj->Extend("sqlutils_queryids", il);
+               }
+               
+               /* Now either way we have a valid list in il, attached. */
+               il->push_back(id);
+       }
+       
+       void RemoveFromList(Extensible* obj, unsigned long id)
+       {
+               AssocIdList* il;
+               
+               if(obj->GetExt("sqlutils_queryids", il))
+               {
+                       /* Only do anything if the list exists... (which it ought to) */
+                       il->remove(id);
+                       
+                       if(il->empty())
+                       {
+                               /* If we just emptied it.. */
+                               delete il;
+                               obj->Shrink("sqlutils_queryids");
+                       }
+               }
+       }
+       
+       template <class T> void DoUnAssociate(T &map, unsigned long id)
+       {
+               /* For each occurence of 'id' (well, only one..it's not a multimap) in 'map'
+                * remove it from the map, take an Extensible* value from the map and remove
+                * 'id' from the list of query IDs attached to it.
+                */
+               typename T::iterator iter = map.find(id);
+               
+               if(iter != map.end())
+               {
+                       /* Found a value indexed by 'id', call RemoveFromList()
+                        * on it with 'id' to remove 'id' from the list attached
+                        * to the value.
+                        */
+                       RemoveFromList(iter->second, id);
+               }
+       }
+       
+       virtual void OnChannelDelete(chanrec* chan)
+       {
+               /* A channel is being destroyed, first we need to check if it has a list of queries associated with it.
+                * Then, if it does, we need to erase each of them from our IdChanMap (idchan) so when the module that
+                * associated them asks to look them up then it gets a NULL result and knows to discard the query.
+                */
+               AssocIdList* il;
+               
+               if(chan->GetExt("sqlutils_queryids", il))
+               {
+                       for(AssocIdList::iterator listiter = il->begin(); listiter != il->end(); listiter++)
+                       {
+                               IdChanMap::iterator iter;
+                       
+                               iter = idchan.find(*listiter);
+                       
+                               if(iter != idchan.end())
+                               {
+                                       if(iter->second != chan)
+                                       {
+                                               ServerInstance->Log(DEBUG, "BUG: ID associated with channel %s doesn't have the same chanrec* associated with it in the map (erasing anyway)", chan->name);
+                                       }
+                                       idchan.erase(iter);                                     
+                               }
+                               else
+                               {
+                                       ServerInstance->Log(DEBUG, "BUG: channel %s was extended with sqlutils_queryids but there was nothing matching in the map", chan->name);
+                               }
+                       }
+                       
+                       chan->Shrink("sqlutils_queryids");
+                       delete il;
+               }
+       }
+                       
+       virtual Version GetVersion()
+       {
+               return Version(1, 1, 0, 0, VF_VENDOR|VF_SERVICEPROVIDER, API_VERSION);
+       }
+       
+};
+
+MODULE_INIT(ModuleSQLutils);
+
index cdde51f6771e174992b8b205e577b460809c7b0a..92fbdf5c7607b4686c8641bd69b27f43355a555d 100644 (file)
@@ -1 +1,143 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef INSPIRCD_SQLUTILS\r#define INSPIRCD_SQLUTILS\r\r#include "modules.h"\r\r#define SQLUTILAU "SQLutil AssociateUser"\r#define SQLUTILAC "SQLutil AssociateChan"\r#define SQLUTILUA "SQLutil UnAssociate"\r#define SQLUTILGU "SQLutil GetAssocUser"\r#define SQLUTILGC "SQLutil GetAssocChan"\r#define SQLUTILSUCCESS "You shouldn't be reading this (success)"\r\r/** Used to associate an SQL query with a user\r */\rclass AssociateUser : public Request\r{\rpublic:\r      /** Query ID\r    */\r    unsigned long id;\r      /** User\r        */\r    userrec* user;\r \r       AssociateUser(Module* s, Module* d, unsigned long i, userrec* u)\r       : Request(s, d, SQLUTILAU), id(i), user(u)\r     {\r      }\r      \r       AssociateUser& S()\r     {\r              Send();\r                return *this;\r  }\r};\r\r/** Used to associate an SQL query with a channel\r */\rclass AssociateChan : public Request\r{\rpublic:\r     /** Query ID\r    */\r    unsigned long id;\r      /** Channel\r     */\r    chanrec* chan;\r \r       AssociateChan(Module* s, Module* d, unsigned long i, chanrec* u)\r       : Request(s, d, SQLUTILAC), id(i), chan(u)\r     {\r      }\r      \r       AssociateChan& S()\r     {\r              Send();\r                return *this;\r  }\r};\r\r/** Unassociate a user or  class from an SQL query\r */\rclass UnAssociate : public Request\r{\rpublic:\r      /** The query ID\r        */\r    unsigned long id;\r\r     UnAssociate(Module* s, Module* d, unsigned long i)\r     : Request(s, d, SQLUTILUA), id(i)\r      {\r      }\r      \r       UnAssociate& S()\r       {\r              Send();\r                return *this;\r  }\r};\r\r/** Get the user associated with an SQL query ID\r */\rclass GetAssocUser : public Request\r{\rpublic:\r       /** The query id\r        */\r    unsigned long id;\r      /** The user\r    */\r    userrec* user;\r\r        GetAssocUser(Module* s, Module* d, unsigned long i)\r    : Request(s, d, SQLUTILGU), id(i), user(NULL)\r  {\r      }\r      \r       GetAssocUser& S()\r      {\r              Send();\r                return *this;\r  }\r};\r\r/** Get the channel associated with an SQL query ID\r */\rclass GetAssocChan : public Request\r{\rpublic:\r    /** The query id\r        */\r    unsigned long id;\r      /** The channel\r         */\r    chanrec* chan;\r\r        GetAssocChan(Module* s, Module* d, unsigned long i)\r    : Request(s, d, SQLUTILGC), id(i), chan(NULL)\r  {\r      }\r      \r       GetAssocChan& S()\r      {\r              Send();\r                return *this;\r  }\r};\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef INSPIRCD_SQLUTILS
+#define INSPIRCD_SQLUTILS
+
+#include "modules.h"
+
+#define SQLUTILAU "SQLutil AssociateUser"
+#define SQLUTILAC "SQLutil AssociateChan"
+#define SQLUTILUA "SQLutil UnAssociate"
+#define SQLUTILGU "SQLutil GetAssocUser"
+#define SQLUTILGC "SQLutil GetAssocChan"
+#define SQLUTILSUCCESS "You shouldn't be reading this (success)"
+
+/** Used to associate an SQL query with a user
+ */
+class AssociateUser : public Request
+{
+public:
+       /** Query ID
+        */
+       unsigned long id;
+       /** User
+        */
+       userrec* user;
+       
+       AssociateUser(Module* s, Module* d, unsigned long i, userrec* u)
+       : Request(s, d, SQLUTILAU), id(i), user(u)
+       {
+       }
+       
+       AssociateUser& S()
+       {
+               Send();
+               return *this;
+       }
+};
+
+/** Used to associate an SQL query with a channel
+ */
+class AssociateChan : public Request
+{
+public:
+       /** Query ID
+        */
+       unsigned long id;
+       /** Channel
+        */
+       chanrec* chan;
+       
+       AssociateChan(Module* s, Module* d, unsigned long i, chanrec* u)
+       : Request(s, d, SQLUTILAC), id(i), chan(u)
+       {
+       }
+       
+       AssociateChan& S()
+       {
+               Send();
+               return *this;
+       }
+};
+
+/** Unassociate a user or  class from an SQL query
+ */
+class UnAssociate : public Request
+{
+public:
+       /** The query ID
+        */
+       unsigned long id;
+
+       UnAssociate(Module* s, Module* d, unsigned long i)
+       : Request(s, d, SQLUTILUA), id(i)
+       {
+       }
+       
+       UnAssociate& S()
+       {
+               Send();
+               return *this;
+       }
+};
+
+/** Get the user associated with an SQL query ID
+ */
+class GetAssocUser : public Request
+{
+public:
+       /** The query id
+        */
+       unsigned long id;
+       /** The user
+        */
+       userrec* user;
+
+       GetAssocUser(Module* s, Module* d, unsigned long i)
+       : Request(s, d, SQLUTILGU), id(i), user(NULL)
+       {
+       }
+       
+       GetAssocUser& S()
+       {
+               Send();
+               return *this;
+       }
+};
+
+/** Get the channel associated with an SQL query ID
+ */
+class GetAssocChan : public Request
+{
+public:
+       /** The query id
+        */
+       unsigned long id;
+       /** The channel
+        */
+       chanrec* chan;
+
+       GetAssocChan(Module* s, Module* d, unsigned long i)
+       : Request(s, d, SQLUTILGC), id(i), chan(NULL)
+       {
+       }
+       
+       GetAssocChan& S()
+       {
+               Send();
+               return *this;
+       }
+};
+
+#endif
index decac4b57d878a1b334886ecdda0d78b4160c5ef..c7f6edbb97b51b64f295809fc01a1b388e94ffb3 100644 (file)
@@ -1 +1,605 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *          the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef INSPIRCD_SQLAPI_2\r#define INSPIRCD_SQLAPI_2\r\r#include <string>\r#include <deque>\r#include <map>\r#include "modules.h"\r\r/** SQLreq define.\r * This is the voodoo magic which lets us pass multiple\r * parameters to the SQLrequest constructor... voodoo...\r */\r#define SQLreq(a, b, c, d, e...) SQLrequest(a, b, c, (SQLquery(d), ##e))\r\r/** Identifiers used to identify Request types\r */\r#define SQLREQID "SQLv2 Request"\r#define SQLRESID "SQLv2 Result"\r#define SQLSUCCESS "You shouldn't be reading this (success)"\r\r/** Defines the error types which SQLerror may be set to\r */\renum SQLerrorNum { NO_ERROR, BAD_DBID, BAD_CONN, QSEND_FAIL, QREPLY_FAIL };\r\r/** A list of format parameters for an SQLquery object.\r */\rtypedef std::deque<std::string> ParamL;\r\r/** The base class of SQL exceptions\r */\rclass SQLexception : public ModuleException\r{\r public:\r     SQLexception(const std::string &reason) : ModuleException(reason)\r      {\r      }\r\r     SQLexception() : ModuleException("SQLv2: Undefined exception")\r {\r      }\r};\r\r/** An exception thrown when a bad column or row name or id is requested\r */\rclass SQLbadColName : public SQLexception\r{\rpublic:\r SQLbadColName() : SQLexception("SQLv2: Bad column name")\r       {\r      }\r};\r\r/** SQLerror holds the error state of any SQLrequest or SQLresult.\r * The error string varies from database software to database software\r * and should be used to display informational error messages to users.\r */\rclass SQLerror : public classbase\r{\r        /** The error id\r        */\r    SQLerrorNum id;\r        /** The error string\r    */\r    std::string str;\rpublic:\r       /** Initialize an SQLerror\r      * @param i The error ID to set\r         * @param s The (optional) error string to set\r  */\r    SQLerror(SQLerrorNum i = NO_ERROR, const std::string &s = "")\r  : id(i), str(s)\r        {\r      }\r\r     /** Return the ID of the error\r  */\r    SQLerrorNum Id()\r       {\r              return id;\r     }\r\r     /** Set the ID of an error\r      * @param i The new error ID to set\r     * @return the ID which was set\r         */\r    SQLerrorNum Id(SQLerrorNum i)\r  {\r              id = i;\r                return id;\r     }\r\r     /** Set the error string for an error\r   * @param s The new error string to set\r         */\r    void Str(const std::string &s)\r {\r              str = s;\r       }\r\r     /** Return the error string for an error\r        */\r    const char* Str()\r      {\r              if(str.length())\r                       return str.c_str();\r\r           switch(id)\r             {\r                      case NO_ERROR:\r                         return "No error";\r                     case BAD_DBID:\r                         return "Invalid database ID";\r                  case BAD_CONN:\r                         return "Invalid connection";\r                   case QSEND_FAIL:\r                               return "Sending query failed";\r                 case QREPLY_FAIL:\r                              return "Getting query result failed";\r                  default:\r                               return "Unknown error";\r                }\r      }\r};\r\r/** SQLquery provides a way to represent a query string, and its parameters in a type-safe way.\r * C++ has no native type-safe way of having a variable number of arguments to a function,\r * the workaround for this isn't easy to describe simply, but in a nutshell what's really\r * happening when - from the above example - you do this:\r *\r * SQLrequest foo = SQLreq(this, target, "databaseid", "SELECT (foo, bar) FROM rawr WHERE foo = '?' AND bar = ?", "Hello", "42");\r *\r * what's actually happening is functionally this:\r *\r * SQLrequest foo = SQLreq(this, target, "databaseid", query("SELECT (foo, bar) FROM rawr WHERE foo = '?' AND bar = ?").addparam("Hello").addparam("42"));\r *\r * with 'query()' returning a reference to an object with a 'addparam()' member function which\r * in turn returns a reference to that object. There are actually four ways you can create a\r * SQLrequest..all have their disadvantages and advantages. In the real implementations the\r * 'query()' function is replaced by the constructor of another class 'SQLquery' which holds\r * the query string and a ParamL (std::deque<std::string>) of query parameters.\r * This is essentially the same as the above example except 'addparam()' is replaced by operator,(). The full syntax for this method is:\r *\r * SQLrequest foo = SQLrequest(this, target, "databaseid", (SQLquery("SELECT.. ?"), parameter, parameter));\r */\rclass SQLquery : public classbase\r{\rpublic:\r  /** The query 'format string'\r   */\r    std::string q;\r /** The query parameter list\r    * There should be one parameter for every ? character\r  * within the format string shown above.\r        */\r    ParamL p;\r\r     /** Initialize an SQLquery with a given format string only\r      */\r    SQLquery(const std::string &query)\r     : q(query)\r     {\r      }\r\r     /** Initialize an SQLquery with a format string and parameters.\r         * If you provide parameters, you must initialize the list yourself\r     * if you choose to do it via this method, using std::deque::push_back().\r       */\r    SQLquery(const std::string &query, const ParamL &params)\r       : q(query), p(params)\r  {\r      }\r\r     /** An overloaded operator for pushing parameters onto the parameter list\r       */\r    template<typename T> SQLquery& operator,(const T &foo)\r {\r              p.push_back(ConvToStr(foo));\r           return *this;\r  }\r\r     /** An overloaded operator for pushing parameters onto the parameter list.\r      * This has higher precedence than 'operator,' and can save on parenthesis.\r     */\r    template<typename T> SQLquery& operator%(const T &foo)\r {\r              p.push_back(ConvToStr(foo));\r           return *this;\r  }\r};\r\r/** SQLrequest is sent to the SQL API to command it to run a query and return the result.\r * You must instantiate this object with a valid SQLquery object and its parameters, then\r * send it using its Send() method to the module providing the 'SQL' feature. To find this\r * module, use Server::FindFeature().\r */\rclass SQLrequest : public Request\r{\rpublic:\r     /** The fully parsed and expanded query string\r  * This is initialized from the SQLquery parameter given in the constructor.\r    */\r    SQLquery query;\r        /** The database ID to apply the request to\r     */\r    std::string dbid;\r      /** True if this is a priority query.\r   * Priority queries may 'queue jump' in the request queue.\r      */\r    bool pri;\r      /** The query ID, assigned by the SQL api.\r      * After your request is processed, this will\r   * be initialized for you by the API to a valid request ID,\r     * except in the case of an error.\r      */\r    unsigned long id;\r      /** If an error occured, error.id will be any other value than NO_ERROR.\r        */\r    SQLerror error;\r\r       /** Initialize an SQLrequest.\r   * For example:\r         *\r      * SQLrequest req = SQLreq(MyMod, SQLModule, dbid, "INSERT INTO ircd_log_actors VALUES('','?')", nick);\r         *\r      * @param s A pointer to the sending module, where the result should be routed\r  * @param d A pointer to the receiving module, identified as implementing the 'SQL' feature\r     * @param databaseid The database ID to perform the query on. This must match a valid\r   * database ID from the configuration of the SQL module.\r        * @param q A properly initialized SQLquery object.\r     */\r    SQLrequest(Module* s, Module* d, const std::string &databaseid, const SQLquery &q)\r     : Request(s, d, SQLREQID), query(q), dbid(databaseid), pri(false), id(0)\r       {\r      }\r\r     /** Set the priority of a request.\r      */\r    void Priority(bool p = true)\r   {\r              pri = p;\r       }\r\r     /** Set the source of a request. You should not need to use this method.\r        */\r    void SetSource(Module* mod)\r    {\r              source = mod;\r  }\r};\r\r/**\r * This class contains a field's data plus a way to determine if the field\r * is NULL or not without having to mess around with NULL pointers.\r */\rclass SQLfield\r{\rpublic:\r  /**\r     * The data itself\r      */\r    std::string d;\r\r        /**\r     * If the field was null\r        */\r    bool null;\r\r    /** Initialize an SQLfield\r      */\r    SQLfield(const std::string &data = "", bool n = false)\r : d(data), null(n)\r     {\r\r     }\r};\r\r/** A list of items which make up a row of a result or table (tuple)\r * This does not include field names.\r */\rtypedef std::vector<SQLfield> SQLfieldList;\r/** A list of items which make up a row of a result or table (tuple)\r * This also includes the field names.\r */\rtypedef std::map<std::string, SQLfield> SQLfieldMap;\r\r/** SQLresult is a reply to a previous query.\r * If you send a query to the SQL api, the response will arrive at your\r * OnRequest method of your module at some later time, depending on the\r * congestion of the SQL server and complexity of the query. The ID of\r * this result will match the ID assigned to your original request.\r * SQLresult contains its own internal cursor (row counter) which is\r * incremented with each method call which retrieves a single row.\r */\rclass SQLresult : public Request\r{\rpublic:\r /** The original query string passed initially to the SQL API\r   */\r    std::string query;\r     /** The database ID the query was executed on\r   */\r    std::string dbid;\r      /**\r     * The error (if any) which occured.\r    * If an error occured the value of error.id will be any\r        * other value than NO_ERROR.\r   */\r    SQLerror error;\r        /**\r     * This will match  query ID you were given when sending\r        * the request at an earlier time.\r      */\r    unsigned long id;\r\r     /** Used by the SQL API to instantiate an SQLrequest\r    */\r    SQLresult(Module* s, Module* d, unsigned long i)\r       : Request(s, d, SQLRESID), id(i)\r       {\r      }\r\r     /**\r     * Return the number of rows in the result\r      * Note that if you have perfomed an INSERT\r     * or UPDATE query or other query which will\r    * not return rows, this will return the\r        * number of affected rows, and SQLresult::Cols()\r       * will contain 0. In this case you SHOULD NEVER\r        * access any of the result set rows, as there arent any!\r       * @returns Number of rows in the result set.\r   */\r    virtual int Rows() = 0;\r\r       /**\r     * Return the number of columns in the result.\r  * If you performed an UPDATE or INSERT which\r   * does not return a dataset, this value will\r   * be 0.\r        * @returns Number of columns in the result set.\r        */\r    virtual int Cols() = 0;\r\r       /**\r     * Get a string name of the column by an index number\r   * @param column The id number of a column\r      * @returns The column name associated with the given ID\r        */\r    virtual std::string ColName(int column) = 0;\r\r  /**\r     * Get an index number for a column from a string name.\r         * An exception of type SQLbadColName will be thrown if\r         * the name given is invalid.\r   * @param column The column name to get the ID of\r       * @returns The ID number of the column provided\r        */\r    virtual int ColNum(const std::string &column) = 0;\r\r    /**\r     * Get a string value in a given row and column\r         * This does not effect the internal cursor.\r    * @returns The value stored at [row,column] in the table\r       */\r    virtual SQLfield GetValue(int row, int column) = 0;\r\r   /**\r     * Return a list of values in a row, this should\r        * increment an internal counter so you can repeatedly\r  * call it until it returns an empty vector.\r    * This returns a reference to an internal object,\r      * the same object is used for all calls to this function\r       * and therefore the return value is only valid until\r   * you call this function again. It is also invalid if\r  * the SQLresult object is destroyed.\r   * The internal cursor (row counter) is incremented by one.\r     * @returns A reference to the current row's SQLfieldList\r       */\r    virtual SQLfieldList& GetRow() = 0;\r\r   /**\r     * As above, but return a map indexed by key name.\r      * The internal cursor (row counter) is incremented by one.\r     * @returns A reference to the current row's SQLfieldMap\r        */\r    virtual SQLfieldMap& GetRowMap() = 0;\r\r /**\r     * Like GetRow(), but returns a pointer to a dynamically\r        * allocated object which must be explicitly freed. For\r         * portability reasons this must be freed with SQLresult::Free()\r        * The internal cursor (row counter) is incremented by one.\r     * @returns A newly-allocated SQLfieldList\r      */\r    virtual SQLfieldList* GetRowPtr() = 0;\r\r        /**\r     * As above, but return a map indexed by key name\r       * The internal cursor (row counter) is incremented by one.\r     * @returns A newly-allocated SQLfieldMap\r       */\r    virtual SQLfieldMap* GetRowMapPtr() = 0;\r\r      /**\r     * Overloaded function for freeing the lists and maps\r   * returned by GetRowPtr or GetRowMapPtr.\r       * @param fm The SQLfieldMap to free\r    */\r    virtual void Free(SQLfieldMap* fm) = 0;\r\r       /**\r     * Overloaded function for freeing the lists and maps\r   * returned by GetRowPtr or GetRowMapPtr.\r       * @param fl The SQLfieldList to free\r   */\r    virtual void Free(SQLfieldList* fl) = 0;\r};\r\r\r/** SQLHost represents a <database> config line and is useful\r * for storing in a map and iterating on rehash to see which\r * <database> tags was added/removed/unchanged.\r */\rclass SQLhost\r{\r public:\r  std::string             id;             /* Database handle id */\r       std::string             host;   /* Database server hostname */\r std::string             ip;             /* resolved IP, needed for at least pgsql.so */\r        unsigned int    port;   /* Database server port */\r     std::string             name;   /* Database name */\r    std::string             user;   /* Database username */\r        std::string             pass;   /* Database password */\r        bool                    ssl;    /* If we should require SSL */\r\r        SQLhost()\r      {\r      }\r\r     SQLhost(const std::string& i, const std::string& h, unsigned int p, const std::string& n, const std::string& u, const std::string& pa, bool s)\r : id(i), host(h), port(p), name(n), user(u), pass(pa), ssl(s)\r  {\r      }\r\r     /** Overload this to return a correct Data source Name (DSN) for\r        * the current SQL module.\r      */\r    std::string GetDSN();\r};\r\r/** Overload operator== for two SQLhost objects for easy comparison.\r */\rbool operator== (const SQLhost& l, const SQLhost& r)\r{\r      return (l.id == r.id && l.host == r.host && l.port == r.port && l.name == r.name && l.user == l.user && l.pass == r.pass && l.ssl == r.ssl);\r}\r\r\r/** QueryQueue, a queue of queries waiting to be executed.\r * This maintains two queues internally, one for 'priority'\r * queries and one for less important ones. Each queue has\r * new queries appended to it and ones to execute are popped\r * off the front. This keeps them flowing round nicely and no\r * query should ever get 'stuck' for too long. If there are\r * queries in the priority queue they will be executed first,\r * 'unimportant' queries will only be executed when the\r * priority queue is empty.\r *\r * We store lists of SQLrequest's here, by value as we want to avoid storing\r * any data allocated inside the client module (in case that module is unloaded\r * while the query is in progress).\r *\r * Because we want to work on the current SQLrequest in-situ, we need a way\r * of accessing the request we are currently processing, QueryQueue::front(),\r * but that call needs to always return the same request until that request\r * is removed from the queue, this is what the 'which' variable is. New queries are\r * always added to the back of one of the two queues, but if when front()\r * is first called then the priority queue is empty then front() will return\r * a query from the normal queue, but if a query is then added to the priority\r * queue then front() must continue to return the front of the *normal* queue\r * until pop() is called.\r */\r\rclass QueryQueue : public classbase\r{\rprivate:\r typedef std::deque<SQLrequest> ReqDeque;\r\r      ReqDeque priority;      /* The priority queue */\r       ReqDeque normal;        /* The 'normal' queue */\r       enum { PRI, NOR, NON } which;   /* Which queue the currently active element is at the front of */\r\rpublic:\r     QueryQueue()\r   : which(NON)\r   {\r      }\r\r     void push(const SQLrequest &q)\r {\r              if(q.pri)\r                      priority.push_back(q);\r         else\r                   normal.push_back(q);\r   }\r\r     void pop()\r     {\r              if((which == PRI) && priority.size())\r          {\r                      priority.pop_front();\r          }\r              else if((which == NOR) && normal.size())\r               {\r                      normal.pop_front();\r            }\r\r             /* Reset this */\r               which = NON;\r\r          /* Silently do nothing if there was no element to pop() */\r     }\r\r     SQLrequest& front()\r    {\r              switch(which)\r          {\r                      case PRI:\r                              return priority.front();\r                       case NOR:\r                              return normal.front();\r                 default:\r                               if(priority.size())\r                            {\r                                      which = PRI;\r                                   return priority.front();\r                               }\r\r                             if(normal.size())\r                              {\r                                      which = NOR;\r                                   return normal.front();\r                         }\r\r                             /* This will probably result in a segfault,\r                             * but the caller should have checked totalsize()\r                               * first so..meh - moron :p\r                             */\r\r                           return priority.front();\r               }\r      }\r\r     std::pair<int, int> size()\r     {\r              return std::make_pair(priority.size(), normal.size());\r }\r\r     int totalsize()\r        {\r              return priority.size() + normal.size();\r        }\r\r     void PurgeModule(Module* mod)\r  {\r              DoPurgeModule(mod, priority);\r          DoPurgeModule(mod, normal);\r    }\r\rprivate:\r    void DoPurgeModule(Module* mod, ReqDeque& q)\r   {\r              for(ReqDeque::iterator iter = q.begin(); iter != q.end(); iter++)\r              {\r                      if(iter->GetSource() == mod)\r                   {\r                              if(iter->id == front().id)\r                             {\r                                      /* It's the currently active query.. :x */\r                                     iter->SetSource(NULL);\r                         }\r                              else\r                           {\r                                      /* It hasn't been executed yet..just remove it */\r                                      iter = q.erase(iter);\r                          }\r                      }\r              }\r      }\r};\r\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *          the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef INSPIRCD_SQLAPI_2
+#define INSPIRCD_SQLAPI_2
+
+#include <string>
+#include <deque>
+#include <map>
+#include "modules.h"
+
+/** SQLreq define.
+ * This is the voodoo magic which lets us pass multiple
+ * parameters to the SQLrequest constructor... voodoo...
+ */
+#define SQLreq(a, b, c, d, e...) SQLrequest(a, b, c, (SQLquery(d), ##e))
+
+/** Identifiers used to identify Request types
+ */
+#define SQLREQID "SQLv2 Request"
+#define SQLRESID "SQLv2 Result"
+#define SQLSUCCESS "You shouldn't be reading this (success)"
+
+/** Defines the error types which SQLerror may be set to
+ */
+enum SQLerrorNum { NO_ERROR, BAD_DBID, BAD_CONN, QSEND_FAIL, QREPLY_FAIL };
+
+/** A list of format parameters for an SQLquery object.
+ */
+typedef std::deque<std::string> ParamL;
+
+/** The base class of SQL exceptions
+ */
+class SQLexception : public ModuleException
+{
+ public:
+       SQLexception(const std::string &reason) : ModuleException(reason)
+       {
+       }
+
+       SQLexception() : ModuleException("SQLv2: Undefined exception")
+       {
+       }
+};
+
+/** An exception thrown when a bad column or row name or id is requested
+ */
+class SQLbadColName : public SQLexception
+{
+public:
+       SQLbadColName() : SQLexception("SQLv2: Bad column name")
+       {
+       }
+};
+
+/** SQLerror holds the error state of any SQLrequest or SQLresult.
+ * The error string varies from database software to database software
+ * and should be used to display informational error messages to users.
+ */
+class SQLerror : public classbase
+{
+       /** The error id
+        */
+       SQLerrorNum id;
+       /** The error string
+        */
+       std::string str;
+public:
+       /** Initialize an SQLerror
+        * @param i The error ID to set
+        * @param s The (optional) error string to set
+        */
+       SQLerror(SQLerrorNum i = NO_ERROR, const std::string &s = "")
+       : id(i), str(s)
+       {
+       }
+
+       /** Return the ID of the error
+        */
+       SQLerrorNum Id()
+       {
+               return id;
+       }
+
+       /** Set the ID of an error
+        * @param i The new error ID to set
+        * @return the ID which was set
+        */
+       SQLerrorNum Id(SQLerrorNum i)
+       {
+               id = i;
+               return id;
+       }
+
+       /** Set the error string for an error
+        * @param s The new error string to set
+        */
+       void Str(const std::string &s)
+       {
+               str = s;
+       }
+
+       /** Return the error string for an error
+        */
+       const char* Str()
+       {
+               if(str.length())
+                       return str.c_str();
+
+               switch(id)
+               {
+                       case NO_ERROR:
+                               return "No error";
+                       case BAD_DBID:
+                               return "Invalid database ID";
+                       case BAD_CONN:
+                               return "Invalid connection";
+                       case QSEND_FAIL:
+                               return "Sending query failed";
+                       case QREPLY_FAIL:
+                               return "Getting query result failed";
+                       default:
+                               return "Unknown error";
+               }
+       }
+};
+
+/** SQLquery provides a way to represent a query string, and its parameters in a type-safe way.
+ * C++ has no native type-safe way of having a variable number of arguments to a function,
+ * the workaround for this isn't easy to describe simply, but in a nutshell what's really
+ * happening when - from the above example - you do this:
+ *
+ * SQLrequest foo = SQLreq(this, target, "databaseid", "SELECT (foo, bar) FROM rawr WHERE foo = '?' AND bar = ?", "Hello", "42");
+ *
+ * what's actually happening is functionally this:
+ *
+ * SQLrequest foo = SQLreq(this, target, "databaseid", query("SELECT (foo, bar) FROM rawr WHERE foo = '?' AND bar = ?").addparam("Hello").addparam("42"));
+ *
+ * with 'query()' returning a reference to an object with a 'addparam()' member function which
+ * in turn returns a reference to that object. There are actually four ways you can create a
+ * SQLrequest..all have their disadvantages and advantages. In the real implementations the
+ * 'query()' function is replaced by the constructor of another class 'SQLquery' which holds
+ * the query string and a ParamL (std::deque<std::string>) of query parameters.
+ * This is essentially the same as the above example except 'addparam()' is replaced by operator,(). The full syntax for this method is:
+ *
+ * SQLrequest foo = SQLrequest(this, target, "databaseid", (SQLquery("SELECT.. ?"), parameter, parameter));
+ */
+class SQLquery : public classbase
+{
+public:
+       /** The query 'format string'
+        */
+       std::string q;
+       /** The query parameter list
+        * There should be one parameter for every ? character
+        * within the format string shown above.
+        */
+       ParamL p;
+
+       /** Initialize an SQLquery with a given format string only
+        */
+       SQLquery(const std::string &query)
+       : q(query)
+       {
+       }
+
+       /** Initialize an SQLquery with a format string and parameters.
+        * If you provide parameters, you must initialize the list yourself
+        * if you choose to do it via this method, using std::deque::push_back().
+        */
+       SQLquery(const std::string &query, const ParamL &params)
+       : q(query), p(params)
+       {
+       }
+
+       /** An overloaded operator for pushing parameters onto the parameter list
+        */
+       template<typename T> SQLquery& operator,(const T &foo)
+       {
+               p.push_back(ConvToStr(foo));
+               return *this;
+       }
+
+       /** An overloaded operator for pushing parameters onto the parameter list.
+        * This has higher precedence than 'operator,' and can save on parenthesis.
+        */
+       template<typename T> SQLquery& operator%(const T &foo)
+       {
+               p.push_back(ConvToStr(foo));
+               return *this;
+       }
+};
+
+/** SQLrequest is sent to the SQL API to command it to run a query and return the result.
+ * You must instantiate this object with a valid SQLquery object and its parameters, then
+ * send it using its Send() method to the module providing the 'SQL' feature. To find this
+ * module, use Server::FindFeature().
+ */
+class SQLrequest : public Request
+{
+public:
+       /** The fully parsed and expanded query string
+        * This is initialized from the SQLquery parameter given in the constructor.
+        */
+       SQLquery query;
+       /** The database ID to apply the request to
+        */
+       std::string dbid;
+       /** True if this is a priority query.
+        * Priority queries may 'queue jump' in the request queue.
+        */
+       bool pri;
+       /** The query ID, assigned by the SQL api.
+        * After your request is processed, this will
+        * be initialized for you by the API to a valid request ID,
+        * except in the case of an error.
+        */
+       unsigned long id;
+       /** If an error occured, error.id will be any other value than NO_ERROR.
+        */
+       SQLerror error;
+
+       /** Initialize an SQLrequest.
+        * For example:
+        *
+        * SQLrequest req = SQLreq(MyMod, SQLModule, dbid, "INSERT INTO ircd_log_actors VALUES('','?')", nick);
+        *
+        * @param s A pointer to the sending module, where the result should be routed
+        * @param d A pointer to the receiving module, identified as implementing the 'SQL' feature
+        * @param databaseid The database ID to perform the query on. This must match a valid
+        * database ID from the configuration of the SQL module.
+        * @param q A properly initialized SQLquery object.
+        */
+       SQLrequest(Module* s, Module* d, const std::string &databaseid, const SQLquery &q)
+       : Request(s, d, SQLREQID), query(q), dbid(databaseid), pri(false), id(0)
+       {
+       }
+
+       /** Set the priority of a request.
+        */
+       void Priority(bool p = true)
+       {
+               pri = p;
+       }
+
+       /** Set the source of a request. You should not need to use this method.
+        */
+       void SetSource(Module* mod)
+       {
+               source = mod;
+       }
+};
+
+/**
+ * This class contains a field's data plus a way to determine if the field
+ * is NULL or not without having to mess around with NULL pointers.
+ */
+class SQLfield
+{
+public:
+       /**
+        * The data itself
+        */
+       std::string d;
+
+       /**
+        * If the field was null
+        */
+       bool null;
+
+       /** Initialize an SQLfield
+        */
+       SQLfield(const std::string &data = "", bool n = false)
+       : d(data), null(n)
+       {
+
+       }
+};
+
+/** A list of items which make up a row of a result or table (tuple)
+ * This does not include field names.
+ */
+typedef std::vector<SQLfield> SQLfieldList;
+/** A list of items which make up a row of a result or table (tuple)
+ * This also includes the field names.
+ */
+typedef std::map<std::string, SQLfield> SQLfieldMap;
+
+/** SQLresult is a reply to a previous query.
+ * If you send a query to the SQL api, the response will arrive at your
+ * OnRequest method of your module at some later time, depending on the
+ * congestion of the SQL server and complexity of the query. The ID of
+ * this result will match the ID assigned to your original request.
+ * SQLresult contains its own internal cursor (row counter) which is
+ * incremented with each method call which retrieves a single row.
+ */
+class SQLresult : public Request
+{
+public:
+       /** The original query string passed initially to the SQL API
+        */
+       std::string query;
+       /** The database ID the query was executed on
+        */
+       std::string dbid;
+       /**
+        * The error (if any) which occured.
+        * If an error occured the value of error.id will be any
+        * other value than NO_ERROR.
+        */
+       SQLerror error;
+       /**
+        * This will match  query ID you were given when sending
+        * the request at an earlier time.
+        */
+       unsigned long id;
+
+       /** Used by the SQL API to instantiate an SQLrequest
+        */
+       SQLresult(Module* s, Module* d, unsigned long i)
+       : Request(s, d, SQLRESID), id(i)
+       {
+       }
+
+       /**
+        * Return the number of rows in the result
+        * Note that if you have perfomed an INSERT
+        * or UPDATE query or other query which will
+        * not return rows, this will return the
+        * number of affected rows, and SQLresult::Cols()
+        * will contain 0. In this case you SHOULD NEVER
+        * access any of the result set rows, as there arent any!
+        * @returns Number of rows in the result set.
+        */
+       virtual int Rows() = 0;
+
+       /**
+        * Return the number of columns in the result.
+        * If you performed an UPDATE or INSERT which
+        * does not return a dataset, this value will
+        * be 0.
+        * @returns Number of columns in the result set.
+        */
+       virtual int Cols() = 0;
+
+       /**
+        * Get a string name of the column by an index number
+        * @param column The id number of a column
+        * @returns The column name associated with the given ID
+        */
+       virtual std::string ColName(int column) = 0;
+
+       /**
+        * Get an index number for a column from a string name.
+        * An exception of type SQLbadColName will be thrown if
+        * the name given is invalid.
+        * @param column The column name to get the ID of
+        * @returns The ID number of the column provided
+        */
+       virtual int ColNum(const std::string &column) = 0;
+
+       /**
+        * Get a string value in a given row and column
+        * This does not effect the internal cursor.
+        * @returns The value stored at [row,column] in the table
+        */
+       virtual SQLfield GetValue(int row, int column) = 0;
+
+       /**
+        * Return a list of values in a row, this should
+        * increment an internal counter so you can repeatedly
+        * call it until it returns an empty vector.
+        * This returns a reference to an internal object,
+        * the same object is used for all calls to this function
+        * and therefore the return value is only valid until
+        * you call this function again. It is also invalid if
+        * the SQLresult object is destroyed.
+        * The internal cursor (row counter) is incremented by one.
+        * @returns A reference to the current row's SQLfieldList
+        */
+       virtual SQLfieldList& GetRow() = 0;
+
+       /**
+        * As above, but return a map indexed by key name.
+        * The internal cursor (row counter) is incremented by one.
+        * @returns A reference to the current row's SQLfieldMap
+        */
+       virtual SQLfieldMap& GetRowMap() = 0;
+
+       /**
+        * Like GetRow(), but returns a pointer to a dynamically
+        * allocated object which must be explicitly freed. For
+        * portability reasons this must be freed with SQLresult::Free()
+        * The internal cursor (row counter) is incremented by one.
+        * @returns A newly-allocated SQLfieldList
+        */
+       virtual SQLfieldList* GetRowPtr() = 0;
+
+       /**
+        * As above, but return a map indexed by key name
+        * The internal cursor (row counter) is incremented by one.
+        * @returns A newly-allocated SQLfieldMap
+        */
+       virtual SQLfieldMap* GetRowMapPtr() = 0;
+
+       /**
+        * Overloaded function for freeing the lists and maps
+        * returned by GetRowPtr or GetRowMapPtr.
+        * @param fm The SQLfieldMap to free
+        */
+       virtual void Free(SQLfieldMap* fm) = 0;
+
+       /**
+        * Overloaded function for freeing the lists and maps
+        * returned by GetRowPtr or GetRowMapPtr.
+        * @param fl The SQLfieldList to free
+        */
+       virtual void Free(SQLfieldList* fl) = 0;
+};
+
+
+/** SQLHost represents a <database> config line and is useful
+ * for storing in a map and iterating on rehash to see which
+ * <database> tags was added/removed/unchanged.
+ */
+class SQLhost
+{
+ public:
+       std::string             id;             /* Database handle id */
+       std::string             host;   /* Database server hostname */
+       std::string             ip;             /* resolved IP, needed for at least pgsql.so */
+       unsigned int    port;   /* Database server port */
+       std::string             name;   /* Database name */
+       std::string             user;   /* Database username */
+       std::string             pass;   /* Database password */
+       bool                    ssl;    /* If we should require SSL */
+
+       SQLhost()
+       {
+       }
+
+       SQLhost(const std::string& i, const std::string& h, unsigned int p, const std::string& n, const std::string& u, const std::string& pa, bool s)
+       : id(i), host(h), port(p), name(n), user(u), pass(pa), ssl(s)
+       {
+       }
+
+       /** Overload this to return a correct Data source Name (DSN) for
+        * the current SQL module.
+        */
+       std::string GetDSN();
+};
+
+/** Overload operator== for two SQLhost objects for easy comparison.
+ */
+bool operator== (const SQLhost& l, const SQLhost& r)
+{
+       return (l.id == r.id && l.host == r.host && l.port == r.port && l.name == r.name && l.user == l.user && l.pass == r.pass && l.ssl == r.ssl);
+}
+
+
+/** QueryQueue, a queue of queries waiting to be executed.
+ * This maintains two queues internally, one for 'priority'
+ * queries and one for less important ones. Each queue has
+ * new queries appended to it and ones to execute are popped
+ * off the front. This keeps them flowing round nicely and no
+ * query should ever get 'stuck' for too long. If there are
+ * queries in the priority queue they will be executed first,
+ * 'unimportant' queries will only be executed when the
+ * priority queue is empty.
+ *
+ * We store lists of SQLrequest's here, by value as we want to avoid storing
+ * any data allocated inside the client module (in case that module is unloaded
+ * while the query is in progress).
+ *
+ * Because we want to work on the current SQLrequest in-situ, we need a way
+ * of accessing the request we are currently processing, QueryQueue::front(),
+ * but that call needs to always return the same request until that request
+ * is removed from the queue, this is what the 'which' variable is. New queries are
+ * always added to the back of one of the two queues, but if when front()
+ * is first called then the priority queue is empty then front() will return
+ * a query from the normal queue, but if a query is then added to the priority
+ * queue then front() must continue to return the front of the *normal* queue
+ * until pop() is called.
+ */
+
+class QueryQueue : public classbase
+{
+private:
+       typedef std::deque<SQLrequest> ReqDeque;
+
+       ReqDeque priority;      /* The priority queue */
+       ReqDeque normal;        /* The 'normal' queue */
+       enum { PRI, NOR, NON } which;   /* Which queue the currently active element is at the front of */
+
+public:
+       QueryQueue()
+       : which(NON)
+       {
+       }
+
+       void push(const SQLrequest &q)
+       {
+               if(q.pri)
+                       priority.push_back(q);
+               else
+                       normal.push_back(q);
+       }
+
+       void pop()
+       {
+               if((which == PRI) && priority.size())
+               {
+                       priority.pop_front();
+               }
+               else if((which == NOR) && normal.size())
+               {
+                       normal.pop_front();
+               }
+
+               /* Reset this */
+               which = NON;
+
+               /* Silently do nothing if there was no element to pop() */
+       }
+
+       SQLrequest& front()
+       {
+               switch(which)
+               {
+                       case PRI:
+                               return priority.front();
+                       case NOR:
+                               return normal.front();
+                       default:
+                               if(priority.size())
+                               {
+                                       which = PRI;
+                                       return priority.front();
+                               }
+
+                               if(normal.size())
+                               {
+                                       which = NOR;
+                                       return normal.front();
+                               }
+
+                               /* This will probably result in a segfault,
+                                * but the caller should have checked totalsize()
+                                * first so..meh - moron :p
+                                */
+
+                               return priority.front();
+               }
+       }
+
+       std::pair<int, int> size()
+       {
+               return std::make_pair(priority.size(), normal.size());
+       }
+
+       int totalsize()
+       {
+               return priority.size() + normal.size();
+       }
+
+       void PurgeModule(Module* mod)
+       {
+               DoPurgeModule(mod, priority);
+               DoPurgeModule(mod, normal);
+       }
+
+private:
+       void DoPurgeModule(Module* mod, ReqDeque& q)
+       {
+               for(ReqDeque::iterator iter = q.begin(); iter != q.end(); iter++)
+               {
+                       if(iter->GetSource() == mod)
+                       {
+                               if(iter->id == front().id)
+                               {
+                                       /* It's the currently active query.. :x */
+                                       iter->SetSource(NULL);
+                               }
+                               else
+                               {
+                                       /* It hasn't been executed yet..just remove it */
+                                       iter = q.erase(iter);
+                               }
+                       }
+               }
+       }
+};
+
+
+#endif
index 037d2cf72b0360b2698d47407366a814dab8c6e4..fd8b12d322abe678efe2ced3e5f70f0dd1185221 100644 (file)
@@ -1 +1,843 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r\r#include <gnutls/gnutls.h>\r#include <gnutls/x509.h>\r\r#include "inspircd_config.h"\r#include "configreader.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r#include "socket.h"\r#include "hashcomp.h"\r#include "transport.h"\r\r#ifdef WINDOWS\r#pragma comment(lib, "libgnutls-13.lib")\r#undef MAX_DESCRIPTORS\r#define MAX_DESCRIPTORS 10000\r#endif\r\r/* $ModDesc: Provides SSL support for clients */\r/* $CompileFlags: exec("libgnutls-config --cflags") */\r/* $LinkerFlags: rpath("libgnutls-config --libs") exec("libgnutls-config --libs") */\r/* $ModDep: transport.h */\r\r\renum issl_status { ISSL_NONE, ISSL_HANDSHAKING_READ, ISSL_HANDSHAKING_WRITE, ISSL_HANDSHAKEN, ISSL_CLOSING, ISSL_CLOSED };\r\rbool isin(int port, const std::vector<int> &portlist)\r{\r     for(unsigned int i = 0; i < portlist.size(); i++)\r              if(portlist[i] == port)\r                        return true;\r\r  return false;\r}\r\r/** Represents an SSL user's extra data\r */\rclass issl_session : public classbase\r{\rpublic:\r   gnutls_session_t sess;\r issl_status status;\r    std::string outbuf;\r    int inbufoffset;\r       char* inbuf;\r   int fd;\r};\r\rclass ModuleSSLGnuTLS : public Module\r{\r\r   ConfigReader* Conf;\r\r   char* dummy;\r\r  std::vector<int> listenports;\r\r int inbufsize;\r issl_session sessions[MAX_DESCRIPTORS];\r\r       gnutls_certificate_credentials x509_cred;\r      gnutls_dh_params dh_params;\r\r   std::string keyfile;\r   std::string certfile;\r  std::string cafile;\r    std::string crlfile;\r   std::string sslports;\r  int dh_bits;\r\r  int clientactive;\r\r public:\r\r   ModuleSSLGnuTLS(InspIRCd* Me)\r          : Module(Me)\r   {\r              ServerInstance->PublishInterface("InspSocketHook", this);\r\r             // Not rehashable...because I cba to reduce all the sizes of existing buffers.\r         inbufsize = ServerInstance->Config->NetBufferSize;\r\r            gnutls_global_init(); // This must be called once in the program\r\r              if(gnutls_certificate_allocate_credentials(&x509_cred) != 0)\r                   ServerInstance->Log(DEFAULT, "m_ssl_gnutls.so: Failed to allocate certificate credentials");\r\r          // Guessing return meaning\r             if(gnutls_dh_params_init(&dh_params) < 0)\r                      ServerInstance->Log(DEFAULT, "m_ssl_gnutls.so: Failed to initialise DH parameters");\r\r          // Needs the flag as it ignores a plain /rehash\r                OnRehash(NULL,"ssl");\r\r         // Void return, guess we assume success\r                gnutls_certificate_set_dh_params(x509_cred, dh_params);\r        }\r\r     virtual void OnRehash(userrec* user, const std::string &param)\r {\r              if(param != "ssl")\r                     return;\r\r               Conf = new ConfigReader(ServerInstance);\r\r              for(unsigned int i = 0; i < listenports.size(); i++)\r           {\r                      ServerInstance->Config->DelIOHook(listenports[i]);\r             }\r\r             listenports.clear();\r           clientactive = 0;\r              sslports.clear();\r\r             for(int i = 0; i < Conf->Enumerate("bind"); i++)\r               {\r                      // For each <bind> tag\r                 std::string x = Conf->ReadValue("bind", "type", i);\r                    if(((x.empty()) || (x == "clients")) && (Conf->ReadValue("bind", "ssl", i) == "gnutls"))\r                       {\r                              // Get the port we're meant to be listening on with SSL\r                                std::string port = Conf->ReadValue("bind", "port", i);\r                         irc::portparser portrange(port, false);\r                                long portno = -1;\r                              while ((portno = portrange.GetToken()))\r                                {\r                                      clientactive++;\r                                        try\r                                    {\r                                              if (ServerInstance->Config->AddIOHook(portno, this))\r                                           {\r                                                      listenports.push_back(portno);\r                                                 for (size_t i = 0; i < ServerInstance->Config->ports.size(); i++)\r                                                              if (ServerInstance->Config->ports[i]->GetPort() == portno)\r                                                                     ServerInstance->Config->ports[i]->SetDescription("ssl");\r                                                       ServerInstance->Log(DEFAULT, "m_ssl_gnutls.so: Enabling SSL for port %d", portno);\r                                                     sslports.append("*:").append(ConvToStr(portno)).append(";");\r                                           }\r                                              else\r                                           {\r                                                      ServerInstance->Log(DEFAULT, "m_ssl_gnutls.so: FAILED to enable SSL on port %d, maybe you have another ssl or similar module loaded?", portno);\r                                                }\r                                      }\r                                      catch (ModuleException &e)\r                                     {\r                                              ServerInstance->Log(DEFAULT, "m_ssl_gnutls.so: FAILED to enable SSL on port %d: %s. Maybe it's already hooked by the same port on a different IP, or you have an other SSL or similar module loaded?", portno, e.GetReason());\r                                 }\r                              }\r                      }\r              }\r\r             std::string confdir(ServerInstance->ConfigFileName);\r           // +1 so we the path ends with a /\r             confdir = confdir.substr(0, confdir.find_last_of('/') + 1);\r\r           cafile  = Conf->ReadValue("gnutls", "cafile", 0);\r              crlfile = Conf->ReadValue("gnutls", "crlfile", 0);\r             certfile        = Conf->ReadValue("gnutls", "certfile", 0);\r            keyfile = Conf->ReadValue("gnutls", "keyfile", 0);\r             dh_bits = Conf->ReadInteger("gnutls", "dhbits", 0, false);\r\r            // Set all the default values needed.\r          if (cafile.empty())\r                    cafile = "ca.pem";\r\r            if (crlfile.empty())\r                   crlfile = "crl.pem";\r\r          if (certfile.empty())\r                  certfile = "cert.pem";\r\r                if (keyfile.empty())\r                   keyfile = "key.pem";\r\r          if((dh_bits != 768) && (dh_bits != 1024) && (dh_bits != 2048) && (dh_bits != 3072) && (dh_bits != 4096))\r                       dh_bits = 1024;\r\r               // Prepend relative paths with the path to the config directory.\r               if(cafile[0] != '/')\r                   cafile = confdir + cafile;\r\r            if(crlfile[0] != '/')\r                  crlfile = confdir + crlfile;\r\r          if(certfile[0] != '/')\r                 certfile = confdir + certfile;\r\r                if(keyfile[0] != '/')\r                  keyfile = confdir + keyfile;\r\r          int ret;\r\r              if((ret =gnutls_certificate_set_x509_trust_file(x509_cred, cafile.c_str(), GNUTLS_X509_FMT_PEM)) < 0)\r                  ServerInstance->Log(DEFAULT, "m_ssl_gnutls.so: Failed to set X.509 trust file '%s': %s", cafile.c_str(), gnutls_strerror(ret));\r\r               if((ret = gnutls_certificate_set_x509_crl_file (x509_cred, crlfile.c_str(), GNUTLS_X509_FMT_PEM)) < 0)\r                 ServerInstance->Log(DEFAULT, "m_ssl_gnutls.so: Failed to set X.509 CRL file '%s': %s", crlfile.c_str(), gnutls_strerror(ret));\r\r                if((ret = gnutls_certificate_set_x509_key_file (x509_cred, certfile.c_str(), keyfile.c_str(), GNUTLS_X509_FMT_PEM)) < 0)\r               {\r                      // If this fails, no SSL port will work. At all. So, do the smart thing - throw a ModuleException\r                      throw ModuleException("Unable to load GnuTLS server certificate: " + std::string(gnutls_strerror(ret)));\r               }\r\r             // This may be on a large (once a day or week) timer eventually.\r               GenerateDHParams();\r\r           DELETE(Conf);\r  }\r\r     void GenerateDHParams()\r        {\r              // Generate Diffie Hellman parameters - for use with DHE\r               // kx algorithms. These should be discarded and regenerated\r            // once a day, once a week or once a month. Depending on the\r           // security requirements.\r\r             int ret;\r\r              if((ret = gnutls_dh_params_generate2(dh_params, dh_bits)) < 0)\r                 ServerInstance->Log(DEFAULT, "m_ssl_gnutls.so: Failed to generate DH parameters (%d bits): %s", dh_bits, gnutls_strerror(ret));\r        }\r\r     virtual ~ModuleSSLGnuTLS()\r     {\r              gnutls_dh_params_deinit(dh_params);\r            gnutls_certificate_free_credentials(x509_cred);\r                gnutls_global_deinit();\r        }\r\r     virtual void OnCleanup(int target_type, void* item)\r    {\r              if(target_type == TYPE_USER)\r           {\r                      userrec* user = (userrec*)item;\r\r                       if(user->GetExt("ssl", dummy) && isin(user->GetPort(), listenports))\r                   {\r                              // User is using SSL, they're a local user, and they're using one of *our* SSL ports.\r                          // Potentially there could be multiple SSL modules loaded at once on different ports.\r                          ServerInstance->GlobalCulls.AddItem(user, "SSL module unloading");\r                     }\r                      if (user->GetExt("ssl_cert", dummy) && isin(user->GetPort(), listenports))\r                     {\r                              ssl_cert* tofree;\r                              user->GetExt("ssl_cert", tofree);\r                              delete tofree;\r                         user->Shrink("ssl_cert");\r                      }\r              }\r      }\r\r     virtual void OnUnloadModule(Module* mod, const std::string &name)\r      {\r              if(mod == this)\r                {\r                      for(unsigned int i = 0; i < listenports.size(); i++)\r                   {\r                              ServerInstance->Config->DelIOHook(listenports[i]);\r                             for (size_t j = 0; j < ServerInstance->Config->ports.size(); j++)\r                                      if (ServerInstance->Config->ports[j]->GetPort() == listenports[i])\r                                             ServerInstance->Config->ports[j]->SetDescription("plaintext");\r                 }\r              }\r      }\r\r     virtual Version GetVersion()\r   {\r              return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION);\r    }\r\r     void Implements(char* List)\r    {\r              List[I_On005Numeric] = List[I_OnRawSocketConnect] = List[I_OnRawSocketAccept] = List[I_OnRawSocketClose] = List[I_OnRawSocketRead] = List[I_OnRawSocketWrite] = List[I_OnCleanup] = 1;\r         List[I_OnRequest] = List[I_OnSyncUserMetaData] = List[I_OnDecodeMetaData] = List[I_OnUnloadModule] = List[I_OnRehash] = List[I_OnWhois] = List[I_OnPostConnect] = 1;\r   }\r\r     virtual void On005Numeric(std::string &output)\r {\r              output.append(" SSL=" + sslports);\r     }\r\r     virtual char* OnRequest(Request* request)\r      {\r              ISHRequest* ISR = (ISHRequest*)request;\r                if (strcmp("IS_NAME", request->GetId()) == 0)\r          {\r                      return "gnutls";\r               }\r              else if (strcmp("IS_HOOK", request->GetId()) == 0)\r             {\r                      char* ret = "OK";\r                      try\r                    {\r                              ret = ServerInstance->Config->AddIOHook((Module*)this, (InspSocket*)ISR->Sock) ? (char*)"OK" : NULL;\r                   }\r                      catch (ModuleException &e)\r                     {\r                              return NULL;\r                   }\r                      return ret;\r            }\r              else if (strcmp("IS_UNHOOK", request->GetId()) == 0)\r           {\r                      return ServerInstance->Config->DelIOHook((InspSocket*)ISR->Sock) ? (char*)"OK" : NULL;\r         }\r              else if (strcmp("IS_HSDONE", request->GetId()) == 0)\r           {\r                      if (ISR->Sock->GetFd() < 0)\r                            return (char*)"OK";\r\r                   issl_session* session = &sessions[ISR->Sock->GetFd()];\r                 return (session->status == ISSL_HANDSHAKING_READ || session->status == ISSL_HANDSHAKING_WRITE) ? NULL : (char*)"OK";\r           }\r              else if (strcmp("IS_ATTACH", request->GetId()) == 0)\r           {\r                      if (ISR->Sock->GetFd() > -1)\r                   {\r                              issl_session* session = &sessions[ISR->Sock->GetFd()];\r                         if (session->sess)\r                             {\r                                      if ((Extensible*)ServerInstance->FindDescriptor(ISR->Sock->GetFd()) == (Extensible*)(ISR->Sock))\r                                       {\r                                              VerifyCertificate(session, (InspSocket*)ISR->Sock);\r                                            return "OK";\r                                   }\r                              }\r                      }\r              }\r              return NULL;\r   }\r\r\r    virtual void OnRawSocketAccept(int fd, const std::string &ip, int localport)\r   {\r              issl_session* session = &sessions[fd];\r\r                session->fd = fd;\r              session->inbuf = new char[inbufsize];\r          session->inbufoffset = 0;\r\r             gnutls_init(&session->sess, GNUTLS_SERVER);\r\r           gnutls_set_default_priority(session->sess); // Avoid calling all the priority functions, defaults are adequate.\r                gnutls_credentials_set(session->sess, GNUTLS_CRD_CERTIFICATE, x509_cred);\r              gnutls_dh_set_prime_bits(session->sess, dh_bits);\r\r             /* This is an experimental change to avoid a warning on 64bit systems about casting between integer and pointer of different sizes\r              * This needs testing, but it's easy enough to rollback if need be\r              * Old: gnutls_transport_set_ptr(session->sess, (gnutls_transport_ptr_t) fd); // Give gnutls the fd for the socket.\r             * New: gnutls_transport_set_ptr(session->sess, &fd); // Give gnutls the fd for the socket.\r             *\r              * With testing this seems to...not work :/\r             */\r\r           gnutls_transport_set_ptr(session->sess, (gnutls_transport_ptr_t) fd); // Give gnutls the fd for the socket.\r\r           gnutls_certificate_server_set_request(session->sess, GNUTLS_CERT_REQUEST); // Request client certificate if any.\r\r              Handshake(session);\r    }\r\r     virtual void OnRawSocketConnect(int fd)\r        {\r              issl_session* session = &sessions[fd];\r\r                session->fd = fd;\r              session->inbuf = new char[inbufsize];\r          session->inbufoffset = 0;\r\r             gnutls_init(&session->sess, GNUTLS_CLIENT);\r\r           gnutls_set_default_priority(session->sess); // Avoid calling all the priority functions, defaults are adequate.\r                gnutls_credentials_set(session->sess, GNUTLS_CRD_CERTIFICATE, x509_cred);\r              gnutls_dh_set_prime_bits(session->sess, dh_bits);\r              gnutls_transport_set_ptr(session->sess, (gnutls_transport_ptr_t) fd); // Give gnutls the fd for the socket.\r\r           Handshake(session);\r    }\r\r     virtual void OnRawSocketClose(int fd)\r  {\r              CloseSession(&sessions[fd]);\r\r          EventHandler* user = ServerInstance->SE->GetRef(fd);\r\r          if ((user) && (user->GetExt("ssl_cert", dummy)))\r               {\r                      ssl_cert* tofree;\r                      user->GetExt("ssl_cert", tofree);\r                      delete tofree;\r                 user->Shrink("ssl_cert");\r              }\r      }\r\r     virtual int OnRawSocketRead(int fd, char* buffer, unsigned int count, int &readresult)\r {\r              issl_session* session = &sessions[fd];\r\r                if (!session->sess)\r            {\r                      readresult = 0;\r                        CloseSession(session);\r                 return 1;\r              }\r\r             if (session->status == ISSL_HANDSHAKING_READ)\r          {\r                      // The handshake isn't finished, try to finish it.\r\r                    if(!Handshake(session))\r                        {\r                              // Couldn't resume handshake.\r                          return -1;\r                     }\r              }\r              else if (session->status == ISSL_HANDSHAKING_WRITE)\r            {\r                      errno = EAGAIN;\r                        return -1;\r             }\r\r             // If we resumed the handshake then session->status will be ISSL_HANDSHAKEN.\r\r          if (session->status == ISSL_HANDSHAKEN)\r                {\r                      // Is this right? Not sure if the unencrypted data is garaunteed to be the same length.\r                        // Read into the inbuffer, offset from the beginning by the amount of data we have that insp hasn't taken yet.\r                 int ret = gnutls_record_recv(session->sess, session->inbuf + session->inbufoffset, inbufsize - session->inbufoffset);\r\r                 if (ret == 0)\r                  {\r                              // Client closed connection.\r                           readresult = 0;\r                                CloseSession(session);\r                         return 1;\r                      }\r                      else if (ret < 0)\r                      {\r                              if (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED)\r                              {\r                                      errno = EAGAIN;\r                                        return -1;\r                             }\r                              else\r                           {\r                                      readresult = 0;\r                                        CloseSession(session);\r                         }\r                      }\r                      else\r                   {\r                              // Read successfully 'ret' bytes into inbuf + inbufoffset\r                              // There are 'ret' + 'inbufoffset' bytes of data in 'inbuf'\r                            // 'buffer' is 'count' long\r\r                           unsigned int length = ret + session->inbufoffset;\r\r                             if(count <= length)\r                            {\r                                      memcpy(buffer, session->inbuf, count);\r                                 // Move the stuff left in inbuf to the beginning of it\r                                 memcpy(session->inbuf, session->inbuf + count, (length - count));\r                                      // Now we need to set session->inbufoffset to the amount of data still waiting to be handed to insp.\r                                   session->inbufoffset = length - count;\r                                 // Insp uses readresult as the count of how much data there is in buffer, so:\r                                  readresult = count;\r                            }\r                              else\r                           {\r                                      // There's not as much in the inbuf as there is space in the buffer, so just copy the whole thing.\r                                     memcpy(buffer, session->inbuf, length);\r                                        // Zero the offset, as there's nothing there..\r                                 session->inbufoffset = 0;\r                                      // As above\r                                    readresult = length;\r                           }\r                      }\r              }\r              else if(session->status == ISSL_CLOSING)\r                       readresult = 0;\r\r               return 1;\r      }\r\r     virtual int OnRawSocketWrite(int fd, const char* buffer, int count)\r    {\r              if (!count)\r                    return 0;\r\r             issl_session* session = &sessions[fd];\r         const char* sendbuffer = buffer;\r\r              if (!session->sess)\r            {\r                      ServerInstance->Log(DEBUG,"No session");\r                       CloseSession(session);\r                 return 1;\r              }\r\r             session->outbuf.append(sendbuffer, count);\r             sendbuffer = session->outbuf.c_str();\r          count = session->outbuf.size();\r\r               if (session->status == ISSL_HANDSHAKING_WRITE)\r         {\r                      // The handshake isn't finished, try to finish it.\r                     ServerInstance->Log(DEBUG,"Finishing handshake");\r                      Handshake(session);\r                    errno = EAGAIN;\r                        return -1;\r             }\r\r             int ret = 0;\r\r          if (session->status == ISSL_HANDSHAKEN)\r                {\r                      ServerInstance->Log(DEBUG,"Send record");\r                      ret = gnutls_record_send(session->sess, sendbuffer, count);\r                    ServerInstance->Log(DEBUG,"Return: %d", ret);\r\r                 if (ret == 0)\r                  {\r                              CloseSession(session);\r                 }\r                      else if (ret < 0)\r                      {\r                              if(ret != GNUTLS_E_AGAIN && ret != GNUTLS_E_INTERRUPTED)\r                               {\r                                      ServerInstance->Log(DEBUG,"Not egain or interrupt, close session");\r                                    CloseSession(session);\r                         }\r                              else\r                           {\r                                      ServerInstance->Log(DEBUG,"Again please");\r                                     errno = EAGAIN;\r                                        return -1;\r                             }\r                      }\r                      else\r                   {\r                              ServerInstance->Log(DEBUG,"Trim buffer");\r                              session->outbuf = session->outbuf.substr(ret);\r                 }\r              }\r\r             /* Who's smart idea was it to return 1 when we havent written anything?\r                 * This fucks the buffer up in InspSocket :p\r            */\r            return ret < 1 ? 0 : ret;\r      }\r\r     // :kenny.chatspike.net 320 Om Epy|AFK :is a Secure Connection\r virtual void OnWhois(userrec* source, userrec* dest)\r   {\r              if (!clientactive)\r                     return;\r\r               // Bugfix, only send this numeric for *our* SSL users\r          if(dest->GetExt("ssl", dummy) || (IS_LOCAL(dest) &&  isin(dest->GetPort(), listenports)))\r              {\r                      ServerInstance->SendWhoisLine(source, dest, 320, "%s %s :is using a secure connection", source->nick, dest->nick);\r             }\r      }\r\r     virtual void OnSyncUserMetaData(userrec* user, Module* proto, void* opaque, const std::string &extname, bool displayable)\r      {\r              // check if the linking module wants to know about OUR metadata\r                if(extname == "ssl")\r           {\r                      // check if this user has an swhois field to send\r                      if(user->GetExt(extname, dummy))\r                       {\r                              // call this function in the linking module, let it format the data how it\r                             // sees fit, and send it on its way. We dont need or want to know how.\r                         proto->ProtoSendMetaData(opaque, TYPE_USER, user, extname, displayable ? "Enabled" : "ON");\r                    }\r              }\r      }\r\r     virtual void OnDecodeMetaData(int target_type, void* target, const std::string &extname, const std::string &extdata)\r   {\r              // check if its our metadata key, and its associated with a user\r               if ((target_type == TYPE_USER) && (extname == "ssl"))\r          {\r                      userrec* dest = (userrec*)target;\r                      // if they dont already have an ssl flag, accept the remote server's\r                   if (!dest->GetExt(extname, dummy))\r                     {\r                              dest->Extend(extname, "ON");\r                   }\r              }\r      }\r\r     bool Handshake(issl_session* session)\r  {\r              int ret = gnutls_handshake(session->sess);\r\r            if (ret < 0)\r           {\r                      if(ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED)\r                       {\r                              // Handshake needs resuming later, read() or write() would have blocked.\r\r                              if(gnutls_record_get_direction(session->sess) == 0)\r                            {\r                                      // gnutls_handshake() wants to read() again.\r                                   session->status = ISSL_HANDSHAKING_READ;\r                               }\r                              else\r                           {\r                                      // gnutls_handshake() wants to write() again.\r                                  session->status = ISSL_HANDSHAKING_WRITE;\r                                      MakePollWrite(session);\r                                }\r                      }\r                      else\r                   {\r                              // Handshake failed.\r                           CloseSession(session);\r                         session->status = ISSL_CLOSING;\r                        }\r\r                     return false;\r          }\r              else\r           {\r                      // Handshake complete.\r                 // This will do for setting the ssl flag...it could be done earlier if it's needed. But this seems neater.\r                     userrec* extendme = ServerInstance->FindDescriptor(session->fd);\r                       if (extendme)\r                  {\r                              if (!extendme->GetExt("ssl", dummy))\r                                   extendme->Extend("ssl", "ON");\r                 }\r\r                     // Change the seesion state\r                    session->status = ISSL_HANDSHAKEN;\r\r                    // Finish writing, if any left\r                 MakePollWrite(session);\r\r                       return true;\r           }\r      }\r\r     virtual void OnPostConnect(userrec* user)\r      {\r              // This occurs AFTER OnUserConnect so we can be sure the\r               // protocol module has propogated the NICK message.\r            if ((user->GetExt("ssl", dummy)) && (IS_LOCAL(user)))\r          {\r                      // Tell whatever protocol module we're using that we need to inform other servers of this metadata NOW.\r                        std::deque<std::string>* metadata = new std::deque<std::string>;\r                       metadata->push_back(user->nick);\r                       metadata->push_back("ssl");             // The metadata id\r                     metadata->push_back("ON");              // The value to send\r                   Event* event = new Event((char*)metadata,(Module*)this,"send_metadata");\r                       event->Send(ServerInstance);            // Trigger the event. We don't care what module picks it up.\r                   DELETE(event);\r                 DELETE(metadata);\r\r                     VerifyCertificate(&sessions[user->GetFd()],user);\r                      if (sessions[user->GetFd()].sess)\r                      {\r                              std::string cipher = gnutls_kx_get_name(gnutls_kx_get(sessions[user->GetFd()].sess));\r                          cipher.append("-").append(gnutls_cipher_get_name(gnutls_cipher_get(sessions[user->GetFd()].sess))).append("-");\r                                cipher.append(gnutls_mac_get_name(gnutls_mac_get(sessions[user->GetFd()].sess)));\r                              user->WriteServ("NOTICE %s :*** You are connected using SSL cipher \"%s\"", user->nick, cipher.c_str());\r                       }\r              }\r      }\r\r     void MakePollWrite(issl_session* session)\r      {\r              OnRawSocketWrite(session->fd, NULL, 0);\r        }\r\r     void CloseSession(issl_session* session)\r       {\r              if(session->sess)\r              {\r                      gnutls_bye(session->sess, GNUTLS_SHUT_WR);\r                     gnutls_deinit(session->sess);\r          }\r\r             if(session->inbuf)\r             {\r                      delete[] session->inbuf;\r               }\r\r             session->outbuf.clear();\r               session->inbuf = NULL;\r         session->sess = NULL;\r          session->status = ISSL_NONE;\r   }\r\r     void VerifyCertificate(issl_session* session, Extensible* user)\r        {\r              if (!session->sess || !user)\r                   return;\r\r               unsigned int status;\r           const gnutls_datum_t* cert_list;\r               int ret;\r               unsigned int cert_list_size;\r           gnutls_x509_crt_t cert;\r                char name[MAXBUF];\r             unsigned char digest[MAXBUF];\r          size_t digest_size = sizeof(digest);\r           size_t name_size = sizeof(name);\r               ssl_cert* certinfo = new ssl_cert;\r\r            user->Extend("ssl_cert",certinfo);\r\r            /* This verification function uses the trusted CAs in the credentials\r           * structure. So you must have installed one or more CA certificates.\r           */\r            ret = gnutls_certificate_verify_peers2(session->sess, &status);\r\r               if (ret < 0)\r           {\r                      certinfo->data.insert(std::make_pair("error",std::string(gnutls_strerror(ret))));\r                      return;\r                }\r\r             if (status & GNUTLS_CERT_INVALID)\r              {\r                      certinfo->data.insert(std::make_pair("invalid",ConvToStr(1)));\r         }\r              else\r           {\r                      certinfo->data.insert(std::make_pair("invalid",ConvToStr(0)));\r         }\r              if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)\r             {\r                      certinfo->data.insert(std::make_pair("unknownsigner",ConvToStr(1)));\r           }\r              else\r           {\r                      certinfo->data.insert(std::make_pair("unknownsigner",ConvToStr(0)));\r           }\r              if (status & GNUTLS_CERT_REVOKED)\r              {\r                      certinfo->data.insert(std::make_pair("revoked",ConvToStr(1)));\r         }\r              else\r           {\r                      certinfo->data.insert(std::make_pair("revoked",ConvToStr(0)));\r         }\r              if (status & GNUTLS_CERT_SIGNER_NOT_CA)\r                {\r                      certinfo->data.insert(std::make_pair("trusted",ConvToStr(0)));\r         }\r              else\r           {\r                      certinfo->data.insert(std::make_pair("trusted",ConvToStr(1)));\r         }\r\r             /* Up to here the process is the same for X.509 certificates and\r                * OpenPGP keys. From now on X.509 certificates are assumed. This can\r           * be easily extended to work with openpgp keys as well.\r                */\r            if (gnutls_certificate_type_get(session->sess) != GNUTLS_CRT_X509)\r             {\r                      certinfo->data.insert(std::make_pair("error","No X509 keys sent"));\r                    return;\r                }\r\r             ret = gnutls_x509_crt_init(&cert);\r             if (ret < 0)\r           {\r                      certinfo->data.insert(std::make_pair("error",gnutls_strerror(ret)));\r                   return;\r                }\r\r             cert_list_size = 0;\r            cert_list = gnutls_certificate_get_peers(session->sess, &cert_list_size);\r              if (cert_list == NULL)\r         {\r                      certinfo->data.insert(std::make_pair("error","No certificate was found"));\r                     return;\r                }\r\r             /* This is not a real world example, since we only check the first\r              * certificate in the given chain.\r              */\r\r           ret = gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER);\r                if (ret < 0)\r           {\r                      certinfo->data.insert(std::make_pair("error",gnutls_strerror(ret)));\r                   return;\r                }\r\r             gnutls_x509_crt_get_dn(cert, name, &name_size);\r\r               certinfo->data.insert(std::make_pair("dn",name));\r\r             gnutls_x509_crt_get_issuer_dn(cert, name, &name_size);\r\r                certinfo->data.insert(std::make_pair("issuer",name));\r\r         if ((ret = gnutls_x509_crt_get_fingerprint(cert, GNUTLS_DIG_MD5, digest, &digest_size)) < 0)\r           {\r                      certinfo->data.insert(std::make_pair("error",gnutls_strerror(ret)));\r           }\r              else\r           {\r                      certinfo->data.insert(std::make_pair("fingerprint",irc::hex(digest, digest_size)));\r            }\r\r             /* Beware here we do not check for errors.\r              */\r            if ((gnutls_x509_crt_get_expiration_time(cert) < time(0)) || (gnutls_x509_crt_get_activation_time(cert) > time(0)))\r            {\r                      certinfo->data.insert(std::make_pair("error","Not activated, or expired certificate"));\r                }\r\r             gnutls_x509_crt_deinit(cert);\r\r         return;\r        }\r\r};\r\rMODULE_INIT(ModuleSSLGnuTLS);\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+
+#include <gnutls/gnutls.h>
+#include <gnutls/x509.h>
+
+#include "inspircd_config.h"
+#include "configreader.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+#include "socket.h"
+#include "hashcomp.h"
+#include "transport.h"
+
+#ifdef WINDOWS
+#pragma comment(lib, "libgnutls-13.lib")
+#undef MAX_DESCRIPTORS
+#define MAX_DESCRIPTORS 10000
+#endif
+
+/* $ModDesc: Provides SSL support for clients */
+/* $CompileFlags: exec("libgnutls-config --cflags") */
+/* $LinkerFlags: rpath("libgnutls-config --libs") exec("libgnutls-config --libs") */
+/* $ModDep: transport.h */
+
+
+enum issl_status { ISSL_NONE, ISSL_HANDSHAKING_READ, ISSL_HANDSHAKING_WRITE, ISSL_HANDSHAKEN, ISSL_CLOSING, ISSL_CLOSED };
+
+bool isin(int port, const std::vector<int> &portlist)
+{
+       for(unsigned int i = 0; i < portlist.size(); i++)
+               if(portlist[i] == port)
+                       return true;
+
+       return false;
+}
+
+/** Represents an SSL user's extra data
+ */
+class issl_session : public classbase
+{
+public:
+       gnutls_session_t sess;
+       issl_status status;
+       std::string outbuf;
+       int inbufoffset;
+       char* inbuf;
+       int fd;
+};
+
+class ModuleSSLGnuTLS : public Module
+{
+
+       ConfigReader* Conf;
+
+       char* dummy;
+
+       std::vector<int> listenports;
+
+       int inbufsize;
+       issl_session sessions[MAX_DESCRIPTORS];
+
+       gnutls_certificate_credentials x509_cred;
+       gnutls_dh_params dh_params;
+
+       std::string keyfile;
+       std::string certfile;
+       std::string cafile;
+       std::string crlfile;
+       std::string sslports;
+       int dh_bits;
+
+       int clientactive;
+
+ public:
+
+       ModuleSSLGnuTLS(InspIRCd* Me)
+               : Module(Me)
+       {
+               ServerInstance->PublishInterface("InspSocketHook", this);
+
+               // Not rehashable...because I cba to reduce all the sizes of existing buffers.
+               inbufsize = ServerInstance->Config->NetBufferSize;
+
+               gnutls_global_init(); // This must be called once in the program
+
+               if(gnutls_certificate_allocate_credentials(&x509_cred) != 0)
+                       ServerInstance->Log(DEFAULT, "m_ssl_gnutls.so: Failed to allocate certificate credentials");
+
+               // Guessing return meaning
+               if(gnutls_dh_params_init(&dh_params) < 0)
+                       ServerInstance->Log(DEFAULT, "m_ssl_gnutls.so: Failed to initialise DH parameters");
+
+               // Needs the flag as it ignores a plain /rehash
+               OnRehash(NULL,"ssl");
+
+               // Void return, guess we assume success
+               gnutls_certificate_set_dh_params(x509_cred, dh_params);
+       }
+
+       virtual void OnRehash(userrec* user, const std::string &param)
+       {
+               if(param != "ssl")
+                       return;
+
+               Conf = new ConfigReader(ServerInstance);
+
+               for(unsigned int i = 0; i < listenports.size(); i++)
+               {
+                       ServerInstance->Config->DelIOHook(listenports[i]);
+               }
+
+               listenports.clear();
+               clientactive = 0;
+               sslports.clear();
+
+               for(int i = 0; i < Conf->Enumerate("bind"); i++)
+               {
+                       // For each <bind> tag
+                       std::string x = Conf->ReadValue("bind", "type", i);
+                       if(((x.empty()) || (x == "clients")) && (Conf->ReadValue("bind", "ssl", i) == "gnutls"))
+                       {
+                               // Get the port we're meant to be listening on with SSL
+                               std::string port = Conf->ReadValue("bind", "port", i);
+                               irc::portparser portrange(port, false);
+                               long portno = -1;
+                               while ((portno = portrange.GetToken()))
+                               {
+                                       clientactive++;
+                                       try
+                                       {
+                                               if (ServerInstance->Config->AddIOHook(portno, this))
+                                               {
+                                                       listenports.push_back(portno);
+                                                       for (size_t i = 0; i < ServerInstance->Config->ports.size(); i++)
+                                                               if (ServerInstance->Config->ports[i]->GetPort() == portno)
+                                                                       ServerInstance->Config->ports[i]->SetDescription("ssl");
+                                                       ServerInstance->Log(DEFAULT, "m_ssl_gnutls.so: Enabling SSL for port %d", portno);
+                                                       sslports.append("*:").append(ConvToStr(portno)).append(";");
+                                               }
+                                               else
+                                               {
+                                                       ServerInstance->Log(DEFAULT, "m_ssl_gnutls.so: FAILED to enable SSL on port %d, maybe you have another ssl or similar module loaded?", portno);
+                                               }
+                                       }
+                                       catch (ModuleException &e)
+                                       {
+                                               ServerInstance->Log(DEFAULT, "m_ssl_gnutls.so: FAILED to enable SSL on port %d: %s. Maybe it's already hooked by the same port on a different IP, or you have an other SSL or similar module loaded?", portno, e.GetReason());
+                                       }
+                               }
+                       }
+               }
+
+               std::string confdir(ServerInstance->ConfigFileName);
+               // +1 so we the path ends with a /
+               confdir = confdir.substr(0, confdir.find_last_of('/') + 1);
+
+               cafile  = Conf->ReadValue("gnutls", "cafile", 0);
+               crlfile = Conf->ReadValue("gnutls", "crlfile", 0);
+               certfile        = Conf->ReadValue("gnutls", "certfile", 0);
+               keyfile = Conf->ReadValue("gnutls", "keyfile", 0);
+               dh_bits = Conf->ReadInteger("gnutls", "dhbits", 0, false);
+
+               // Set all the default values needed.
+               if (cafile.empty())
+                       cafile = "ca.pem";
+
+               if (crlfile.empty())
+                       crlfile = "crl.pem";
+
+               if (certfile.empty())
+                       certfile = "cert.pem";
+
+               if (keyfile.empty())
+                       keyfile = "key.pem";
+
+               if((dh_bits != 768) && (dh_bits != 1024) && (dh_bits != 2048) && (dh_bits != 3072) && (dh_bits != 4096))
+                       dh_bits = 1024;
+
+               // Prepend relative paths with the path to the config directory.
+               if(cafile[0] != '/')
+                       cafile = confdir + cafile;
+
+               if(crlfile[0] != '/')
+                       crlfile = confdir + crlfile;
+
+               if(certfile[0] != '/')
+                       certfile = confdir + certfile;
+
+               if(keyfile[0] != '/')
+                       keyfile = confdir + keyfile;
+
+               int ret;
+
+               if((ret =gnutls_certificate_set_x509_trust_file(x509_cred, cafile.c_str(), GNUTLS_X509_FMT_PEM)) < 0)
+                       ServerInstance->Log(DEFAULT, "m_ssl_gnutls.so: Failed to set X.509 trust file '%s': %s", cafile.c_str(), gnutls_strerror(ret));
+
+               if((ret = gnutls_certificate_set_x509_crl_file (x509_cred, crlfile.c_str(), GNUTLS_X509_FMT_PEM)) < 0)
+                       ServerInstance->Log(DEFAULT, "m_ssl_gnutls.so: Failed to set X.509 CRL file '%s': %s", crlfile.c_str(), gnutls_strerror(ret));
+
+               if((ret = gnutls_certificate_set_x509_key_file (x509_cred, certfile.c_str(), keyfile.c_str(), GNUTLS_X509_FMT_PEM)) < 0)
+               {
+                       // If this fails, no SSL port will work. At all. So, do the smart thing - throw a ModuleException
+                       throw ModuleException("Unable to load GnuTLS server certificate: " + std::string(gnutls_strerror(ret)));
+               }
+
+               // This may be on a large (once a day or week) timer eventually.
+               GenerateDHParams();
+
+               DELETE(Conf);
+       }
+
+       void GenerateDHParams()
+       {
+               // Generate Diffie Hellman parameters - for use with DHE
+               // kx algorithms. These should be discarded and regenerated
+               // once a day, once a week or once a month. Depending on the
+               // security requirements.
+
+               int ret;
+
+               if((ret = gnutls_dh_params_generate2(dh_params, dh_bits)) < 0)
+                       ServerInstance->Log(DEFAULT, "m_ssl_gnutls.so: Failed to generate DH parameters (%d bits): %s", dh_bits, gnutls_strerror(ret));
+       }
+
+       virtual ~ModuleSSLGnuTLS()
+       {
+               gnutls_dh_params_deinit(dh_params);
+               gnutls_certificate_free_credentials(x509_cred);
+               gnutls_global_deinit();
+       }
+
+       virtual void OnCleanup(int target_type, void* item)
+       {
+               if(target_type == TYPE_USER)
+               {
+                       userrec* user = (userrec*)item;
+
+                       if(user->GetExt("ssl", dummy) && isin(user->GetPort(), listenports))
+                       {
+                               // User is using SSL, they're a local user, and they're using one of *our* SSL ports.
+                               // Potentially there could be multiple SSL modules loaded at once on different ports.
+                               ServerInstance->GlobalCulls.AddItem(user, "SSL module unloading");
+                       }
+                       if (user->GetExt("ssl_cert", dummy) && isin(user->GetPort(), listenports))
+                       {
+                               ssl_cert* tofree;
+                               user->GetExt("ssl_cert", tofree);
+                               delete tofree;
+                               user->Shrink("ssl_cert");
+                       }
+               }
+       }
+
+       virtual void OnUnloadModule(Module* mod, const std::string &name)
+       {
+               if(mod == this)
+               {
+                       for(unsigned int i = 0; i < listenports.size(); i++)
+                       {
+                               ServerInstance->Config->DelIOHook(listenports[i]);
+                               for (size_t j = 0; j < ServerInstance->Config->ports.size(); j++)
+                                       if (ServerInstance->Config->ports[j]->GetPort() == listenports[i])
+                                               ServerInstance->Config->ports[j]->SetDescription("plaintext");
+                       }
+               }
+       }
+
+       virtual Version GetVersion()
+       {
+               return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION);
+       }
+
+       void Implements(char* List)
+       {
+               List[I_On005Numeric] = List[I_OnRawSocketConnect] = List[I_OnRawSocketAccept] = List[I_OnRawSocketClose] = List[I_OnRawSocketRead] = List[I_OnRawSocketWrite] = List[I_OnCleanup] = 1;
+               List[I_OnRequest] = List[I_OnSyncUserMetaData] = List[I_OnDecodeMetaData] = List[I_OnUnloadModule] = List[I_OnRehash] = List[I_OnWhois] = List[I_OnPostConnect] = 1;
+       }
+
+       virtual void On005Numeric(std::string &output)
+       {
+               output.append(" SSL=" + sslports);
+       }
+
+       virtual char* OnRequest(Request* request)
+       {
+               ISHRequest* ISR = (ISHRequest*)request;
+               if (strcmp("IS_NAME", request->GetId()) == 0)
+               {
+                       return "gnutls";
+               }
+               else if (strcmp("IS_HOOK", request->GetId()) == 0)
+               {
+                       char* ret = "OK";
+                       try
+                       {
+                               ret = ServerInstance->Config->AddIOHook((Module*)this, (InspSocket*)ISR->Sock) ? (char*)"OK" : NULL;
+                       }
+                       catch (ModuleException &e)
+                       {
+                               return NULL;
+                       }
+                       return ret;
+               }
+               else if (strcmp("IS_UNHOOK", request->GetId()) == 0)
+               {
+                       return ServerInstance->Config->DelIOHook((InspSocket*)ISR->Sock) ? (char*)"OK" : NULL;
+               }
+               else if (strcmp("IS_HSDONE", request->GetId()) == 0)
+               {
+                       if (ISR->Sock->GetFd() < 0)
+                               return (char*)"OK";
+
+                       issl_session* session = &sessions[ISR->Sock->GetFd()];
+                       return (session->status == ISSL_HANDSHAKING_READ || session->status == ISSL_HANDSHAKING_WRITE) ? NULL : (char*)"OK";
+               }
+               else if (strcmp("IS_ATTACH", request->GetId()) == 0)
+               {
+                       if (ISR->Sock->GetFd() > -1)
+                       {
+                               issl_session* session = &sessions[ISR->Sock->GetFd()];
+                               if (session->sess)
+                               {
+                                       if ((Extensible*)ServerInstance->FindDescriptor(ISR->Sock->GetFd()) == (Extensible*)(ISR->Sock))
+                                       {
+                                               VerifyCertificate(session, (InspSocket*)ISR->Sock);
+                                               return "OK";
+                                       }
+                               }
+                       }
+               }
+               return NULL;
+       }
+
+
+       virtual void OnRawSocketAccept(int fd, const std::string &ip, int localport)
+       {
+               issl_session* session = &sessions[fd];
+
+               session->fd = fd;
+               session->inbuf = new char[inbufsize];
+               session->inbufoffset = 0;
+
+               gnutls_init(&session->sess, GNUTLS_SERVER);
+
+               gnutls_set_default_priority(session->sess); // Avoid calling all the priority functions, defaults are adequate.
+               gnutls_credentials_set(session->sess, GNUTLS_CRD_CERTIFICATE, x509_cred);
+               gnutls_dh_set_prime_bits(session->sess, dh_bits);
+
+               /* This is an experimental change to avoid a warning on 64bit systems about casting between integer and pointer of different sizes
+                * This needs testing, but it's easy enough to rollback if need be
+                * Old: gnutls_transport_set_ptr(session->sess, (gnutls_transport_ptr_t) fd); // Give gnutls the fd for the socket.
+                * New: gnutls_transport_set_ptr(session->sess, &fd); // Give gnutls the fd for the socket.
+                *
+                * With testing this seems to...not work :/
+                */
+
+               gnutls_transport_set_ptr(session->sess, (gnutls_transport_ptr_t) fd); // Give gnutls the fd for the socket.
+
+               gnutls_certificate_server_set_request(session->sess, GNUTLS_CERT_REQUEST); // Request client certificate if any.
+
+               Handshake(session);
+       }
+
+       virtual void OnRawSocketConnect(int fd)
+       {
+               issl_session* session = &sessions[fd];
+
+               session->fd = fd;
+               session->inbuf = new char[inbufsize];
+               session->inbufoffset = 0;
+
+               gnutls_init(&session->sess, GNUTLS_CLIENT);
+
+               gnutls_set_default_priority(session->sess); // Avoid calling all the priority functions, defaults are adequate.
+               gnutls_credentials_set(session->sess, GNUTLS_CRD_CERTIFICATE, x509_cred);
+               gnutls_dh_set_prime_bits(session->sess, dh_bits);
+               gnutls_transport_set_ptr(session->sess, (gnutls_transport_ptr_t) fd); // Give gnutls the fd for the socket.
+
+               Handshake(session);
+       }
+
+       virtual void OnRawSocketClose(int fd)
+       {
+               CloseSession(&sessions[fd]);
+
+               EventHandler* user = ServerInstance->SE->GetRef(fd);
+
+               if ((user) && (user->GetExt("ssl_cert", dummy)))
+               {
+                       ssl_cert* tofree;
+                       user->GetExt("ssl_cert", tofree);
+                       delete tofree;
+                       user->Shrink("ssl_cert");
+               }
+       }
+
+       virtual int OnRawSocketRead(int fd, char* buffer, unsigned int count, int &readresult)
+       {
+               issl_session* session = &sessions[fd];
+
+               if (!session->sess)
+               {
+                       readresult = 0;
+                       CloseSession(session);
+                       return 1;
+               }
+
+               if (session->status == ISSL_HANDSHAKING_READ)
+               {
+                       // The handshake isn't finished, try to finish it.
+
+                       if(!Handshake(session))
+                       {
+                               // Couldn't resume handshake.
+                               return -1;
+                       }
+               }
+               else if (session->status == ISSL_HANDSHAKING_WRITE)
+               {
+                       errno = EAGAIN;
+                       return -1;
+               }
+
+               // If we resumed the handshake then session->status will be ISSL_HANDSHAKEN.
+
+               if (session->status == ISSL_HANDSHAKEN)
+               {
+                       // Is this right? Not sure if the unencrypted data is garaunteed to be the same length.
+                       // Read into the inbuffer, offset from the beginning by the amount of data we have that insp hasn't taken yet.
+                       int ret = gnutls_record_recv(session->sess, session->inbuf + session->inbufoffset, inbufsize - session->inbufoffset);
+
+                       if (ret == 0)
+                       {
+                               // Client closed connection.
+                               readresult = 0;
+                               CloseSession(session);
+                               return 1;
+                       }
+                       else if (ret < 0)
+                       {
+                               if (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED)
+                               {
+                                       errno = EAGAIN;
+                                       return -1;
+                               }
+                               else
+                               {
+                                       readresult = 0;
+                                       CloseSession(session);
+                               }
+                       }
+                       else
+                       {
+                               // Read successfully 'ret' bytes into inbuf + inbufoffset
+                               // There are 'ret' + 'inbufoffset' bytes of data in 'inbuf'
+                               // 'buffer' is 'count' long
+
+                               unsigned int length = ret + session->inbufoffset;
+
+                               if(count <= length)
+                               {
+                                       memcpy(buffer, session->inbuf, count);
+                                       // Move the stuff left in inbuf to the beginning of it
+                                       memcpy(session->inbuf, session->inbuf + count, (length - count));
+                                       // Now we need to set session->inbufoffset to the amount of data still waiting to be handed to insp.
+                                       session->inbufoffset = length - count;
+                                       // Insp uses readresult as the count of how much data there is in buffer, so:
+                                       readresult = count;
+                               }
+                               else
+                               {
+                                       // There's not as much in the inbuf as there is space in the buffer, so just copy the whole thing.
+                                       memcpy(buffer, session->inbuf, length);
+                                       // Zero the offset, as there's nothing there..
+                                       session->inbufoffset = 0;
+                                       // As above
+                                       readresult = length;
+                               }
+                       }
+               }
+               else if(session->status == ISSL_CLOSING)
+                       readresult = 0;
+
+               return 1;
+       }
+
+       virtual int OnRawSocketWrite(int fd, const char* buffer, int count)
+       {
+               if (!count)
+                       return 0;
+
+               issl_session* session = &sessions[fd];
+               const char* sendbuffer = buffer;
+
+               if (!session->sess)
+               {
+                       ServerInstance->Log(DEBUG,"No session");
+                       CloseSession(session);
+                       return 1;
+               }
+
+               session->outbuf.append(sendbuffer, count);
+               sendbuffer = session->outbuf.c_str();
+               count = session->outbuf.size();
+
+               if (session->status == ISSL_HANDSHAKING_WRITE)
+               {
+                       // The handshake isn't finished, try to finish it.
+                       ServerInstance->Log(DEBUG,"Finishing handshake");
+                       Handshake(session);
+                       errno = EAGAIN;
+                       return -1;
+               }
+
+               int ret = 0;
+
+               if (session->status == ISSL_HANDSHAKEN)
+               {
+                       ServerInstance->Log(DEBUG,"Send record");
+                       ret = gnutls_record_send(session->sess, sendbuffer, count);
+                       ServerInstance->Log(DEBUG,"Return: %d", ret);
+
+                       if (ret == 0)
+                       {
+                               CloseSession(session);
+                       }
+                       else if (ret < 0)
+                       {
+                               if(ret != GNUTLS_E_AGAIN && ret != GNUTLS_E_INTERRUPTED)
+                               {
+                                       ServerInstance->Log(DEBUG,"Not egain or interrupt, close session");
+                                       CloseSession(session);
+                               }
+                               else
+                               {
+                                       ServerInstance->Log(DEBUG,"Again please");
+                                       errno = EAGAIN;
+                                       return -1;
+                               }
+                       }
+                       else
+                       {
+                               ServerInstance->Log(DEBUG,"Trim buffer");
+                               session->outbuf = session->outbuf.substr(ret);
+                       }
+               }
+
+               /* Who's smart idea was it to return 1 when we havent written anything?
+                * This fucks the buffer up in InspSocket :p
+                */
+               return ret < 1 ? 0 : ret;
+       }
+
+       // :kenny.chatspike.net 320 Om Epy|AFK :is a Secure Connection
+       virtual void OnWhois(userrec* source, userrec* dest)
+       {
+               if (!clientactive)
+                       return;
+
+               // Bugfix, only send this numeric for *our* SSL users
+               if(dest->GetExt("ssl", dummy) || (IS_LOCAL(dest) &&  isin(dest->GetPort(), listenports)))
+               {
+                       ServerInstance->SendWhoisLine(source, dest, 320, "%s %s :is using a secure connection", source->nick, dest->nick);
+               }
+       }
+
+       virtual void OnSyncUserMetaData(userrec* user, Module* proto, void* opaque, const std::string &extname, bool displayable)
+       {
+               // check if the linking module wants to know about OUR metadata
+               if(extname == "ssl")
+               {
+                       // check if this user has an swhois field to send
+                       if(user->GetExt(extname, dummy))
+                       {
+                               // call this function in the linking module, let it format the data how it
+                               // sees fit, and send it on its way. We dont need or want to know how.
+                               proto->ProtoSendMetaData(opaque, TYPE_USER, user, extname, displayable ? "Enabled" : "ON");
+                       }
+               }
+       }
+
+       virtual void OnDecodeMetaData(int target_type, void* target, const std::string &extname, const std::string &extdata)
+       {
+               // check if its our metadata key, and its associated with a user
+               if ((target_type == TYPE_USER) && (extname == "ssl"))
+               {
+                       userrec* dest = (userrec*)target;
+                       // if they dont already have an ssl flag, accept the remote server's
+                       if (!dest->GetExt(extname, dummy))
+                       {
+                               dest->Extend(extname, "ON");
+                       }
+               }
+       }
+
+       bool Handshake(issl_session* session)
+       {
+               int ret = gnutls_handshake(session->sess);
+
+               if (ret < 0)
+               {
+                       if(ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED)
+                       {
+                               // Handshake needs resuming later, read() or write() would have blocked.
+
+                               if(gnutls_record_get_direction(session->sess) == 0)
+                               {
+                                       // gnutls_handshake() wants to read() again.
+                                       session->status = ISSL_HANDSHAKING_READ;
+                               }
+                               else
+                               {
+                                       // gnutls_handshake() wants to write() again.
+                                       session->status = ISSL_HANDSHAKING_WRITE;
+                                       MakePollWrite(session);
+                               }
+                       }
+                       else
+                       {
+                               // Handshake failed.
+                               CloseSession(session);
+                               session->status = ISSL_CLOSING;
+                       }
+
+                       return false;
+               }
+               else
+               {
+                       // Handshake complete.
+                       // This will do for setting the ssl flag...it could be done earlier if it's needed. But this seems neater.
+                       userrec* extendme = ServerInstance->FindDescriptor(session->fd);
+                       if (extendme)
+                       {
+                               if (!extendme->GetExt("ssl", dummy))
+                                       extendme->Extend("ssl", "ON");
+                       }
+
+                       // Change the seesion state
+                       session->status = ISSL_HANDSHAKEN;
+
+                       // Finish writing, if any left
+                       MakePollWrite(session);
+
+                       return true;
+               }
+       }
+
+       virtual void OnPostConnect(userrec* user)
+       {
+               // This occurs AFTER OnUserConnect so we can be sure the
+               // protocol module has propogated the NICK message.
+               if ((user->GetExt("ssl", dummy)) && (IS_LOCAL(user)))
+               {
+                       // Tell whatever protocol module we're using that we need to inform other servers of this metadata NOW.
+                       std::deque<std::string>* metadata = new std::deque<std::string>;
+                       metadata->push_back(user->nick);
+                       metadata->push_back("ssl");             // The metadata id
+                       metadata->push_back("ON");              // The value to send
+                       Event* event = new Event((char*)metadata,(Module*)this,"send_metadata");
+                       event->Send(ServerInstance);            // Trigger the event. We don't care what module picks it up.
+                       DELETE(event);
+                       DELETE(metadata);
+
+                       VerifyCertificate(&sessions[user->GetFd()],user);
+                       if (sessions[user->GetFd()].sess)
+                       {
+                               std::string cipher = gnutls_kx_get_name(gnutls_kx_get(sessions[user->GetFd()].sess));
+                               cipher.append("-").append(gnutls_cipher_get_name(gnutls_cipher_get(sessions[user->GetFd()].sess))).append("-");
+                               cipher.append(gnutls_mac_get_name(gnutls_mac_get(sessions[user->GetFd()].sess)));
+                               user->WriteServ("NOTICE %s :*** You are connected using SSL cipher \"%s\"", user->nick, cipher.c_str());
+                       }
+               }
+       }
+
+       void MakePollWrite(issl_session* session)
+       {
+               OnRawSocketWrite(session->fd, NULL, 0);
+       }
+
+       void CloseSession(issl_session* session)
+       {
+               if(session->sess)
+               {
+                       gnutls_bye(session->sess, GNUTLS_SHUT_WR);
+                       gnutls_deinit(session->sess);
+               }
+
+               if(session->inbuf)
+               {
+                       delete[] session->inbuf;
+               }
+
+               session->outbuf.clear();
+               session->inbuf = NULL;
+               session->sess = NULL;
+               session->status = ISSL_NONE;
+       }
+
+       void VerifyCertificate(issl_session* session, Extensible* user)
+       {
+               if (!session->sess || !user)
+                       return;
+
+               unsigned int status;
+               const gnutls_datum_t* cert_list;
+               int ret;
+               unsigned int cert_list_size;
+               gnutls_x509_crt_t cert;
+               char name[MAXBUF];
+               unsigned char digest[MAXBUF];
+               size_t digest_size = sizeof(digest);
+               size_t name_size = sizeof(name);
+               ssl_cert* certinfo = new ssl_cert;
+
+               user->Extend("ssl_cert",certinfo);
+
+               /* This verification function uses the trusted CAs in the credentials
+                * structure. So you must have installed one or more CA certificates.
+                */
+               ret = gnutls_certificate_verify_peers2(session->sess, &status);
+
+               if (ret < 0)
+               {
+                       certinfo->data.insert(std::make_pair("error",std::string(gnutls_strerror(ret))));
+                       return;
+               }
+
+               if (status & GNUTLS_CERT_INVALID)
+               {
+                       certinfo->data.insert(std::make_pair("invalid",ConvToStr(1)));
+               }
+               else
+               {
+                       certinfo->data.insert(std::make_pair("invalid",ConvToStr(0)));
+               }
+               if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
+               {
+                       certinfo->data.insert(std::make_pair("unknownsigner",ConvToStr(1)));
+               }
+               else
+               {
+                       certinfo->data.insert(std::make_pair("unknownsigner",ConvToStr(0)));
+               }
+               if (status & GNUTLS_CERT_REVOKED)
+               {
+                       certinfo->data.insert(std::make_pair("revoked",ConvToStr(1)));
+               }
+               else
+               {
+                       certinfo->data.insert(std::make_pair("revoked",ConvToStr(0)));
+               }
+               if (status & GNUTLS_CERT_SIGNER_NOT_CA)
+               {
+                       certinfo->data.insert(std::make_pair("trusted",ConvToStr(0)));
+               }
+               else
+               {
+                       certinfo->data.insert(std::make_pair("trusted",ConvToStr(1)));
+               }
+
+               /* Up to here the process is the same for X.509 certificates and
+                * OpenPGP keys. From now on X.509 certificates are assumed. This can
+                * be easily extended to work with openpgp keys as well.
+                */
+               if (gnutls_certificate_type_get(session->sess) != GNUTLS_CRT_X509)
+               {
+                       certinfo->data.insert(std::make_pair("error","No X509 keys sent"));
+                       return;
+               }
+
+               ret = gnutls_x509_crt_init(&cert);
+               if (ret < 0)
+               {
+                       certinfo->data.insert(std::make_pair("error",gnutls_strerror(ret)));
+                       return;
+               }
+
+               cert_list_size = 0;
+               cert_list = gnutls_certificate_get_peers(session->sess, &cert_list_size);
+               if (cert_list == NULL)
+               {
+                       certinfo->data.insert(std::make_pair("error","No certificate was found"));
+                       return;
+               }
+
+               /* This is not a real world example, since we only check the first
+                * certificate in the given chain.
+                */
+
+               ret = gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER);
+               if (ret < 0)
+               {
+                       certinfo->data.insert(std::make_pair("error",gnutls_strerror(ret)));
+                       return;
+               }
+
+               gnutls_x509_crt_get_dn(cert, name, &name_size);
+
+               certinfo->data.insert(std::make_pair("dn",name));
+
+               gnutls_x509_crt_get_issuer_dn(cert, name, &name_size);
+
+               certinfo->data.insert(std::make_pair("issuer",name));
+
+               if ((ret = gnutls_x509_crt_get_fingerprint(cert, GNUTLS_DIG_MD5, digest, &digest_size)) < 0)
+               {
+                       certinfo->data.insert(std::make_pair("error",gnutls_strerror(ret)));
+               }
+               else
+               {
+                       certinfo->data.insert(std::make_pair("fingerprint",irc::hex(digest, digest_size)));
+               }
+
+               /* Beware here we do not check for errors.
+                */
+               if ((gnutls_x509_crt_get_expiration_time(cert) < time(0)) || (gnutls_x509_crt_get_activation_time(cert) > time(0)))
+               {
+                       certinfo->data.insert(std::make_pair("error","Not activated, or expired certificate"));
+               }
+
+               gnutls_x509_crt_deinit(cert);
+
+               return;
+       }
+
+};
+
+MODULE_INIT(ModuleSSLGnuTLS);
+
index 43dc43aeabc188274f99c3f5452bc1f136f45b58..ffd9d40321d407c445f58b304ecea20da8a44070 100644 (file)
@@ -1 +1,901 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r\r#include <openssl/ssl.h>\r#include <openssl/err.h>\r\r#ifdef WINDOWS\r#include <openssl/applink.c>\r#endif\r\r#include "configreader.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r\r#include "socket.h"\r#include "hashcomp.h"\r\r#include "transport.h"\r\r#ifdef WINDOWS\r#pragma comment(lib, "libeay32MTd")\r#pragma comment(lib, "ssleay32MTd")\r#undef MAX_DESCRIPTORS\r#define MAX_DESCRIPTORS 10000\r#endif\r\r/* $ModDesc: Provides SSL support for clients */\r/* $CompileFlags: pkgconfversion("openssl","0.9.7") pkgconfincludes("openssl","/openssl/ssl.h","") */\r/* $LinkerFlags: rpath("pkg-config --libs openssl") pkgconflibs("openssl","/libssl.so","-lssl -lcrypto -ldl") */\r/* $ModDep: transport.h */\r\renum issl_status { ISSL_NONE, ISSL_HANDSHAKING, ISSL_OPEN };\renum issl_io_status { ISSL_WRITE, ISSL_READ };\r\rstatic bool SelfSigned = false;\r\rbool isin(int port, const std::vector<int> &portlist)\r{\r   for(unsigned int i = 0; i < portlist.size(); i++)\r              if(portlist[i] == port)\r                        return true;\r\r  return false;\r}\r\rchar* get_error()\r{\r   return ERR_error_string(ERR_get_error(), NULL);\r}\r\rstatic int error_callback(const char *str, size_t len, void *u);\r\r/** Represents an SSL user's extra data\r */\rclass issl_session : public classbase\r{\rpublic:\r       SSL* sess;\r     issl_status status;\r    issl_io_status rstat;\r  issl_io_status wstat;\r\r unsigned int inbufoffset;\r      char* inbuf;                    // Buffer OpenSSL reads into.\r  std::string outbuf;     // Buffer for outgoing data that OpenSSL will not take.\r        int fd;\r        bool outbound;\r\r        issl_session()\r {\r              outbound = false;\r              rstat = ISSL_READ;\r             wstat = ISSL_WRITE;\r    }\r};\r\rstatic int OnVerify(int preverify_ok, X509_STORE_CTX *ctx)\r{\r     /* XXX: This will allow self signed certificates.\r       * In the future if we want an option to not allow this,\r        * we can just return preverify_ok here, and openssl\r    * will boot off self-signed and invalid peer certs.\r    */\r    int ve = X509_STORE_CTX_get_error(ctx);\r\r       SelfSigned = (ve == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT);\r\r  return 1;\r}\r\rclass ModuleSSLOpenSSL : public Module\r{\r\r ConfigReader* Conf;\r\r   std::vector<int> listenports;\r\r int inbufsize;\r issl_session sessions[MAX_DESCRIPTORS];\r\r       SSL_CTX* ctx;\r  SSL_CTX* clictx;\r\r      char* dummy;\r   char cipher[MAXBUF];\r\r  std::string keyfile;\r   std::string certfile;\r  std::string cafile;\r    // std::string crlfile;\r        std::string dhfile;\r    std::string sslports;\r\r int clientactive;\r\r public:\r\r   InspIRCd* PublicInstance;\r\r     ModuleSSLOpenSSL(InspIRCd* Me)\r         : Module(Me), PublicInstance(Me)\r       {\r              ServerInstance->PublishInterface("InspSocketHook", this);\r\r             // Not rehashable...because I cba to reduce all the sizes of existing buffers.\r         inbufsize = ServerInstance->Config->NetBufferSize;\r\r            /* Global SSL library initialization*/\r         SSL_library_init();\r            SSL_load_error_strings();\r\r             /* Build our SSL contexts:\r              * NOTE: OpenSSL makes us have two contexts, one for servers and one for clients. ICK.\r          */\r            ctx = SSL_CTX_new( SSLv23_server_method() );\r           clictx = SSL_CTX_new( SSLv23_client_method() );\r\r               SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, OnVerify);\r           SSL_CTX_set_verify(clictx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, OnVerify);\r\r               // Needs the flag as it ignores a plain /rehash\r                OnRehash(NULL,"ssl");\r  }\r\r     virtual void OnRehash(userrec* user, const std::string &param)\r {\r              if (param != "ssl")\r                    return;\r\r               Conf = new ConfigReader(ServerInstance);\r\r              for (unsigned int i = 0; i < listenports.size(); i++)\r          {\r                      ServerInstance->Config->DelIOHook(listenports[i]);\r             }\r\r             listenports.clear();\r           clientactive = 0;\r              sslports.clear();\r\r             for (int i = 0; i < Conf->Enumerate("bind"); i++)\r              {\r                      // For each <bind> tag\r                 std::string x = Conf->ReadValue("bind", "type", i);\r                    if (((x.empty()) || (x == "clients")) && (Conf->ReadValue("bind", "ssl", i) == "openssl"))\r                     {\r                              // Get the port we're meant to be listening on with SSL\r                                std::string port = Conf->ReadValue("bind", "port", i);\r                         irc::portparser portrange(port, false);\r                                long portno = -1;\r                              while ((portno = portrange.GetToken()))\r                                {\r                                      clientactive++;\r                                        try\r                                    {\r                                              if (ServerInstance->Config->AddIOHook(portno, this))\r                                           {\r                                                      listenports.push_back(portno);\r                                                         for (size_t i = 0; i < ServerInstance->Config->ports.size(); i++)\r                                                              if (ServerInstance->Config->ports[i]->GetPort() == portno)\r                                                                     ServerInstance->Config->ports[i]->SetDescription("ssl");\r                                                       ServerInstance->Log(DEFAULT, "m_ssl_openssl.so: Enabling SSL for port %d", portno);\r                                                    sslports.append("*:").append(ConvToStr(portno)).append(";");\r                                           }\r                                              else\r                                           {\r                                                      ServerInstance->Log(DEFAULT, "m_ssl_openssl.so: FAILED to enable SSL on port %d, maybe you have another ssl or similar module loaded?", portno);\r                                               }\r                                      }\r                                      catch (ModuleException &e)\r                                     {\r                                              ServerInstance->Log(DEFAULT, "m_ssl_openssl.so: FAILED to enable SSL on port %d: %s. Maybe it's already hooked by the same port on a different IP, or you have another SSL or similar module loaded?", portno, e.GetReason());\r                                 }\r                              }\r                      }\r              }\r\r             if (!sslports.empty())\r                 sslports.erase(sslports.end() - 1);\r\r           std::string confdir(ServerInstance->ConfigFileName);\r           // +1 so we the path ends with a /\r             confdir = confdir.substr(0, confdir.find_last_of('/') + 1);\r\r           cafile   = Conf->ReadValue("openssl", "cafile", 0);\r            certfile = Conf->ReadValue("openssl", "certfile", 0);\r          keyfile  = Conf->ReadValue("openssl", "keyfile", 0);\r           dhfile   = Conf->ReadValue("openssl", "dhfile", 0);\r\r           // Set all the default values needed.\r          if (cafile.empty())\r                    cafile = "ca.pem";\r\r            if (certfile.empty())\r                  certfile = "cert.pem";\r\r                if (keyfile.empty())\r                   keyfile = "key.pem";\r\r          if (dhfile.empty())\r                    dhfile = "dhparams.pem";\r\r              // Prepend relative paths with the path to the config directory.\r               if (cafile[0] != '/')\r                  cafile = confdir + cafile;\r\r            if (certfile[0] != '/')\r                        certfile = confdir + certfile;\r\r                if (keyfile[0] != '/')\r                 keyfile = confdir + keyfile;\r\r          if (dhfile[0] != '/')\r                  dhfile = confdir + dhfile;\r\r            /* Load our keys and certificates\r               * NOTE: OpenSSL's error logging API sucks, don't blame us for this clusterfuck.\r                */\r            if ((!SSL_CTX_use_certificate_chain_file(ctx, certfile.c_str())) || (!SSL_CTX_use_certificate_chain_file(clictx, certfile.c_str())))\r           {\r                      ServerInstance->Log(DEFAULT, "m_ssl_openssl.so: Can't read certificate file %s. %s", certfile.c_str(), strerror(errno));\r                       ERR_print_errors_cb(error_callback, this);\r             }\r\r             if (((!SSL_CTX_use_PrivateKey_file(ctx, keyfile.c_str(), SSL_FILETYPE_PEM))) || (!SSL_CTX_use_PrivateKey_file(clictx, keyfile.c_str(), SSL_FILETYPE_PEM)))\r             {\r                      ServerInstance->Log(DEFAULT, "m_ssl_openssl.so: Can't read key file %s. %s", keyfile.c_str(), strerror(errno));\r                        ERR_print_errors_cb(error_callback, this);\r             }\r\r             /* Load the CAs we trust*/\r             if (((!SSL_CTX_load_verify_locations(ctx, cafile.c_str(), 0))) || (!SSL_CTX_load_verify_locations(clictx, cafile.c_str(), 0)))\r         {\r                      ServerInstance->Log(DEFAULT, "m_ssl_openssl.so: Can't read CA list from %s. %s", cafile.c_str(), strerror(errno));\r                     ERR_print_errors_cb(error_callback, this);\r             }\r\r             FILE* dhpfile = fopen(dhfile.c_str(), "r");\r            DH* ret;\r\r              if (dhpfile == NULL)\r           {\r                      ServerInstance->Log(DEFAULT, "m_ssl_openssl.so Couldn't open DH file %s: %s", dhfile.c_str(), strerror(errno));\r                        throw ModuleException("Couldn't open DH file " + dhfile + ": " + strerror(errno));\r             }\r              else\r           {\r                      ret = PEM_read_DHparams(dhpfile, NULL, NULL, NULL);\r                    if ((SSL_CTX_set_tmp_dh(ctx, ret) < 0) || (SSL_CTX_set_tmp_dh(clictx, ret) < 0))\r                       {\r                              ServerInstance->Log(DEFAULT, "m_ssl_openssl.so: Couldn't set DH parameters %s. SSL errors follow:", dhfile.c_str());\r                           ERR_print_errors_cb(error_callback, this);\r                     }\r              }\r\r             fclose(dhpfile);\r\r              DELETE(Conf);\r  }\r\r     virtual void On005Numeric(std::string &output)\r {\r              output.append(" SSL=" + sslports);\r     }\r\r     virtual ~ModuleSSLOpenSSL()\r    {\r              SSL_CTX_free(ctx);\r             SSL_CTX_free(clictx);\r  }\r\r     virtual void OnCleanup(int target_type, void* item)\r    {\r              if (target_type == TYPE_USER)\r          {\r                      userrec* user = (userrec*)item;\r\r                       if (user->GetExt("ssl", dummy) && IS_LOCAL(user) && isin(user->GetPort(), listenports))\r                        {\r                              // User is using SSL, they're a local user, and they're using one of *our* SSL ports.\r                          // Potentially there could be multiple SSL modules loaded at once on different ports.\r                          ServerInstance->GlobalCulls.AddItem(user, "SSL module unloading");\r                     }\r                      if (user->GetExt("ssl_cert", dummy) && isin(user->GetPort(), listenports))\r                     {\r                              ssl_cert* tofree;\r                              user->GetExt("ssl_cert", tofree);\r                              delete tofree;\r                         user->Shrink("ssl_cert");\r                      }\r              }\r      }\r\r     virtual void OnUnloadModule(Module* mod, const std::string &name)\r      {\r              if (mod == this)\r               {\r                      for(unsigned int i = 0; i < listenports.size(); i++)\r                   {\r                              ServerInstance->Config->DelIOHook(listenports[i]);\r                             for (size_t j = 0; j < ServerInstance->Config->ports.size(); j++)\r                                      if (ServerInstance->Config->ports[j]->GetPort() == listenports[i])\r                                             ServerInstance->Config->ports[j]->SetDescription("plaintext");\r                 }\r              }\r      }\r\r     virtual Version GetVersion()\r   {\r              return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION);\r    }\r\r     void Implements(char* List)\r    {\r              List[I_OnRawSocketConnect] = List[I_OnRawSocketAccept] = List[I_OnRawSocketClose] = List[I_OnRawSocketRead] = List[I_OnRawSocketWrite] = List[I_OnCleanup] = List[I_On005Numeric] = 1;\r         List[I_OnRequest] = List[I_OnSyncUserMetaData] = List[I_OnDecodeMetaData] = List[I_OnUnloadModule] = List[I_OnRehash] = List[I_OnWhois] = List[I_OnPostConnect] = 1;\r   }\r\r     virtual char* OnRequest(Request* request)\r      {\r              ISHRequest* ISR = (ISHRequest*)request;\r                if (strcmp("IS_NAME", request->GetId()) == 0)\r          {\r                      return "openssl";\r              }\r              else if (strcmp("IS_HOOK", request->GetId()) == 0)\r             {\r                      char* ret = "OK";\r                      try\r                    {\r                              ret = ServerInstance->Config->AddIOHook((Module*)this, (InspSocket*)ISR->Sock) ? (char*)"OK" : NULL;\r                   }\r                      catch (ModuleException &e)\r                     {\r                              return NULL;\r                   }\r\r                     return ret;\r            }\r              else if (strcmp("IS_UNHOOK", request->GetId()) == 0)\r           {\r                      return ServerInstance->Config->DelIOHook((InspSocket*)ISR->Sock) ? (char*)"OK" : NULL;\r         }\r              else if (strcmp("IS_HSDONE", request->GetId()) == 0)\r           {\r                      ServerInstance->Log(DEBUG,"Module checking if handshake is done");\r                     if (ISR->Sock->GetFd() < 0)\r                            return (char*)"OK";\r\r                   issl_session* session = &sessions[ISR->Sock->GetFd()];\r                 return (session->status == ISSL_HANDSHAKING) ? NULL : (char*)"OK";\r             }\r              else if (strcmp("IS_ATTACH", request->GetId()) == 0)\r           {\r                      issl_session* session = &sessions[ISR->Sock->GetFd()];\r                 if (session->sess)\r                     {\r                              VerifyCertificate(session, (InspSocket*)ISR->Sock);\r                            return "OK";\r                   }\r              }\r              return NULL;\r   }\r\r\r    virtual void OnRawSocketAccept(int fd, const std::string &ip, int localport)\r   {\r              issl_session* session = &sessions[fd];\r\r                session->fd = fd;\r              session->inbuf = new char[inbufsize];\r          session->inbufoffset = 0;\r              session->sess = SSL_new(ctx);\r          session->status = ISSL_NONE;\r           session->outbound = false;\r\r            if (session->sess == NULL)\r                     return;\r\r               if (SSL_set_fd(session->sess, fd) == 0)\r                {\r                      ServerInstance->Log(DEBUG,"BUG: Can't set fd with SSL_set_fd: %d", fd);\r                        return;\r                }\r\r             Handshake(session);\r    }\r\r     virtual void OnRawSocketConnect(int fd)\r        {\r              ServerInstance->Log(DEBUG,"OnRawSocketConnect connecting");\r            issl_session* session = &sessions[fd];\r\r                session->fd = fd;\r              session->inbuf = new char[inbufsize];\r          session->inbufoffset = 0;\r              session->sess = SSL_new(clictx);\r               session->status = ISSL_NONE;\r           session->outbound = true;\r\r             if (session->sess == NULL)\r                     return;\r\r               if (SSL_set_fd(session->sess, fd) == 0)\r                {\r                      ServerInstance->Log(DEBUG,"BUG: Can't set fd with SSL_set_fd: %d", fd);\r                        return;\r                }\r\r             Handshake(session);\r            ServerInstance->Log(DEBUG,"Exiting OnRawSocketConnect");\r       }\r\r     virtual void OnRawSocketClose(int fd)\r  {\r              CloseSession(&sessions[fd]);\r\r          EventHandler* user = ServerInstance->SE->GetRef(fd);\r\r          if ((user) && (user->GetExt("ssl_cert", dummy)))\r               {\r                      ssl_cert* tofree;\r                      user->GetExt("ssl_cert", tofree);\r                      delete tofree;\r                 user->Shrink("ssl_cert");\r              }\r      }\r\r     virtual int OnRawSocketRead(int fd, char* buffer, unsigned int count, int &readresult)\r {\r              issl_session* session = &sessions[fd];\r\r                ServerInstance->Log(DEBUG,"OnRawSocketRead");\r\r         if (!session->sess)\r            {\r                      ServerInstance->Log(DEBUG,"OnRawSocketRead has no session");\r                   readresult = 0;\r                        CloseSession(session);\r                 return 1;\r              }\r\r             if (session->status == ISSL_HANDSHAKING)\r               {\r                      if (session->rstat == ISSL_READ || session->wstat == ISSL_READ)\r                        {\r                              ServerInstance->Log(DEBUG,"Resume handshake in read");\r                         // The handshake isn't finished and it wants to read, try to finish it.\r                                if (!Handshake(session))\r                               {\r                                      ServerInstance->Log(DEBUG,"Cant resume handshake in read");\r                                    // Couldn't resume handshake.\r                                  return -1;\r                             }\r                      }\r                      else\r                   {\r                              errno = EAGAIN;\r                                return -1;\r                     }\r              }\r\r             // If we resumed the handshake then session->status will be ISSL_OPEN\r\r         if (session->status == ISSL_OPEN)\r              {\r                      if (session->wstat == ISSL_READ)\r                       {\r                              if(DoWrite(session) == 0)\r                                      return 0;\r                      }\r\r                     if (session->rstat == ISSL_READ)\r                       {\r                              int ret = DoRead(session);\r\r                            if (ret > 0)\r                           {\r                                      if (count <= session->inbufoffset)\r                                     {\r                                              memcpy(buffer, session->inbuf, count);\r                                         // Move the stuff left in inbuf to the beginning of it\r                                         memcpy(session->inbuf, session->inbuf + count, (session->inbufoffset - count));\r                                                // Now we need to set session->inbufoffset to the amount of data still waiting to be handed to insp.\r                                           session->inbufoffset -= count;\r                                         // Insp uses readresult as the count of how much data there is in buffer, so:\r                                          readresult = count;\r                                    }\r                                      else\r                                   {\r                                              // There's not as much in the inbuf as there is space in the buffer, so just copy the whole thing.\r                                             memcpy(buffer, session->inbuf, session->inbufoffset);\r\r                                         readresult = session->inbufoffset;\r                                             // Zero the offset, as there's nothing there..\r                                         session->inbufoffset = 0;\r                                      }\r\r                                     return 1;\r                              }\r                              else\r                           {\r                                      return ret;\r                            }\r                      }\r              }\r\r             return -1;\r     }\r\r     virtual int OnRawSocketWrite(int fd, const char* buffer, int count)\r    {\r              issl_session* session = &sessions[fd];\r\r                if (!session->sess)\r            {\r                      ServerInstance->Log(DEBUG,"Close session missing sess");\r                       CloseSession(session);\r                 return -1;\r             }\r\r             session->outbuf.append(buffer, count);\r\r                if (session->status == ISSL_HANDSHAKING)\r               {\r                      // The handshake isn't finished, try to finish it.\r                     if (session->rstat == ISSL_WRITE || session->wstat == ISSL_WRITE)\r                      {\r                              ServerInstance->Log(DEBUG,"Handshake resume");\r                         Handshake(session);\r                    }\r              }\r\r             if (session->status == ISSL_OPEN)\r              {\r                      if (session->rstat == ISSL_WRITE)\r                      {\r                              ServerInstance->Log(DEBUG,"DoRead");\r                           DoRead(session);\r                       }\r\r                     if (session->wstat == ISSL_WRITE)\r                      {\r                              ServerInstance->Log(DEBUG,"DoWrite");\r                          return DoWrite(session);\r                       }\r              }\r\r             return 1;\r      }\r\r     int DoWrite(issl_session* session)\r     {\r              if (!session->outbuf.size())\r                   return -1;\r\r            int ret = SSL_write(session->sess, session->outbuf.data(), session->outbuf.size());\r\r           if (ret == 0)\r          {\r                      ServerInstance->Log(DEBUG,"Oops, got 0 from SSL_write");\r                       CloseSession(session);\r                 return 0;\r              }\r              else if (ret < 0)\r              {\r                      int err = SSL_get_error(session->sess, ret);\r\r                  if (err == SSL_ERROR_WANT_WRITE)\r                       {\r                              session->wstat = ISSL_WRITE;\r                           return -1;\r                     }\r                      else if (err == SSL_ERROR_WANT_READ)\r                   {\r                              session->wstat = ISSL_READ;\r                            return -1;\r                     }\r                      else\r                   {\r                              ServerInstance->Log(DEBUG,"Close due to returned -1 in SSL_Write");\r                            CloseSession(session);\r                         return 0;\r                      }\r              }\r              else\r           {\r                      session->outbuf = session->outbuf.substr(ret);\r                 return ret;\r            }\r      }\r\r     int DoRead(issl_session* session)\r      {\r              // Is this right? Not sure if the unencrypted data is garaunteed to be the same length.\r                // Read into the inbuffer, offset from the beginning by the amount of data we have that insp hasn't taken yet.\r         \r               ServerInstance->Log(DEBUG,"DoRead");\r\r          int ret = SSL_read(session->sess, session->inbuf + session->inbufoffset, inbufsize - session->inbufoffset);\r\r           if (ret == 0)\r          {\r                      // Client closed connection.\r                   ServerInstance->Log(DEBUG,"Oops, got 0 from SSL_read");\r                        CloseSession(session);\r                 return 0;\r              }\r              else if (ret < 0)\r              {\r                      int err = SSL_get_error(session->sess, ret);\r\r                  if (err == SSL_ERROR_WANT_READ)\r                        {\r                              session->rstat = ISSL_READ;\r                            ServerInstance->Log(DEBUG,"Setting want_read");\r                                return -1;\r                     }\r                      else if (err == SSL_ERROR_WANT_WRITE)\r                  {\r                              session->rstat = ISSL_WRITE;\r                           ServerInstance->Log(DEBUG,"Setting want_write");\r                               return -1;\r                     }\r                      else\r                   {\r                              ServerInstance->Log(DEBUG,"Closed due to returned -1 in SSL_Read");\r                            CloseSession(session);\r                         return 0;\r                      }\r              }\r              else\r           {\r                      // Read successfully 'ret' bytes into inbuf + inbufoffset\r                      // There are 'ret' + 'inbufoffset' bytes of data in 'inbuf'\r                    // 'buffer' is 'count' long\r\r                   session->inbufoffset += ret;\r\r                  return ret;\r            }\r      }\r\r     // :kenny.chatspike.net 320 Om Epy|AFK :is a Secure Connection\r virtual void OnWhois(userrec* source, userrec* dest)\r   {\r              if (!clientactive)\r                     return;\r\r               // Bugfix, only send this numeric for *our* SSL users\r          if (dest->GetExt("ssl", dummy) || (IS_LOCAL(dest) &&  isin(dest->GetPort(), listenports)))\r             {\r                      ServerInstance->SendWhoisLine(source, dest, 320, "%s %s :is using a secure connection", source->nick, dest->nick);\r             }\r      }\r\r     virtual void OnSyncUserMetaData(userrec* user, Module* proto, void* opaque, const std::string &extname, bool displayable)\r      {\r              // check if the linking module wants to know about OUR metadata\r                if (extname == "ssl")\r          {\r                      // check if this user has an swhois field to send\r                      if(user->GetExt(extname, dummy))\r                       {\r                              // call this function in the linking module, let it format the data how it\r                             // sees fit, and send it on its way. We dont need or want to know how.\r                         proto->ProtoSendMetaData(opaque, TYPE_USER, user, extname, displayable ? "Enabled" : "ON");\r                    }\r              }\r      }\r\r     virtual void OnDecodeMetaData(int target_type, void* target, const std::string &extname, const std::string &extdata)\r   {\r              // check if its our metadata key, and its associated with a user\r               if ((target_type == TYPE_USER) && (extname == "ssl"))\r          {\r                      userrec* dest = (userrec*)target;\r                      // if they dont already have an ssl flag, accept the remote server's\r                   if (!dest->GetExt(extname, dummy))\r                     {\r                              dest->Extend(extname, "ON");\r                   }\r              }\r      }\r\r     bool Handshake(issl_session* session)\r  {\r              ServerInstance->Log(DEBUG,"Handshake");\r                int ret;\r\r              if (session->outbound)\r         {\r                      ServerInstance->Log(DEBUG,"SSL_connect");\r                      ret = SSL_connect(session->sess);\r              }\r              else\r                   ret = SSL_accept(session->sess);\r\r              if (ret < 0)\r           {\r                      int err = SSL_get_error(session->sess, ret);\r\r                  if (err == SSL_ERROR_WANT_READ)\r                        {\r                              ServerInstance->Log(DEBUG,"Want read, handshaking");\r                           session->rstat = ISSL_READ;\r                            session->status = ISSL_HANDSHAKING;\r                            return true;\r                   }\r                      else if (err == SSL_ERROR_WANT_WRITE)\r                  {\r                              ServerInstance->Log(DEBUG,"Want write, handshaking");\r                          session->wstat = ISSL_WRITE;\r                           session->status = ISSL_HANDSHAKING;\r                            MakePollWrite(session);\r                                return true;\r                   }\r                      else\r                   {\r                              ServerInstance->Log(DEBUG,"Handshake failed");\r                         CloseSession(session);\r                 }\r\r                     return false;\r          }\r              else if (ret > 0)\r              {\r                      // Handshake complete.\r                 // This will do for setting the ssl flag...it could be done earlier if it's needed. But this seems neater.\r                     userrec* u = ServerInstance->FindDescriptor(session->fd);\r                      if (u)\r                 {\r                              if (!u->GetExt("ssl", dummy))\r                                  u->Extend("ssl", "ON");\r                        }\r\r                     session->status = ISSL_OPEN;\r\r                  MakePollWrite(session);\r\r                       return true;\r           }\r              else if (ret == 0)\r             {\r                      int ssl_err = SSL_get_error(session->sess, ret);\r                       char buf[1024];\r                        ERR_print_errors_fp(stderr);\r                   ServerInstance->Log(DEBUG,"Handshake fail 2: %d: %s", ssl_err, ERR_error_string(ssl_err,buf));\r                 CloseSession(session);\r                 return true;\r           }\r\r             return true;\r   }\r\r     virtual void OnPostConnect(userrec* user)\r      {\r              // This occurs AFTER OnUserConnect so we can be sure the\r               // protocol module has propogated the NICK message.\r            if ((user->GetExt("ssl", dummy)) && (IS_LOCAL(user)))\r          {\r                      // Tell whatever protocol module we're using that we need to inform other servers of this metadata NOW.\r                        std::deque<std::string>* metadata = new std::deque<std::string>;\r                       metadata->push_back(user->nick);\r                       metadata->push_back("ssl");             // The metadata id\r                     metadata->push_back("ON");              // The value to send\r                   Event* event = new Event((char*)metadata,(Module*)this,"send_metadata");\r                       event->Send(ServerInstance);            // Trigger the event. We don't care what module picks it up.\r                   DELETE(event);\r                 DELETE(metadata);\r\r                     VerifyCertificate(&sessions[user->GetFd()], user);\r                     if (sessions[user->GetFd()].sess)\r                              user->WriteServ("NOTICE %s :*** You are connected using SSL cipher \"%s\"", user->nick, SSL_get_cipher(sessions[user->GetFd()].sess));\r         }\r      }\r\r     void MakePollWrite(issl_session* session)\r      {\r              OnRawSocketWrite(session->fd, NULL, 0);\r                //EventHandler* eh = ServerInstance->FindDescriptor(session->fd);\r              //if (eh)\r              //      ServerInstance->SE->WantWrite(eh);\r     }\r\r     void CloseSession(issl_session* session)\r       {\r              if (session->sess)\r             {\r                      SSL_shutdown(session->sess);\r                   SSL_free(session->sess);\r               }\r\r             if (session->inbuf)\r            {\r                      delete[] session->inbuf;\r               }\r\r             session->outbuf.clear();\r               session->inbuf = NULL;\r         session->sess = NULL;\r          session->status = ISSL_NONE;\r   }\r\r     void VerifyCertificate(issl_session* session, Extensible* user)\r        {\r              if (!session->sess || !user)\r                   return;\r\r               X509* cert;\r            ssl_cert* certinfo = new ssl_cert;\r             unsigned int n;\r                unsigned char md[EVP_MAX_MD_SIZE];\r             const EVP_MD *digest = EVP_md5();\r\r             user->Extend("ssl_cert",certinfo);\r\r            cert = SSL_get_peer_certificate((SSL*)session->sess);\r\r         if (!cert)\r             {\r                      certinfo->data.insert(std::make_pair("error","Could not get peer certificate: "+std::string(get_error())));\r                    return;\r                }\r\r             certinfo->data.insert(std::make_pair("invalid", SSL_get_verify_result(session->sess) != X509_V_OK ? ConvToStr(1) : ConvToStr(0)));\r\r            if (SelfSigned)\r                {\r                      certinfo->data.insert(std::make_pair("unknownsigner",ConvToStr(0)));\r                   certinfo->data.insert(std::make_pair("trusted",ConvToStr(1)));\r         }\r              else\r           {\r                      certinfo->data.insert(std::make_pair("unknownsigner",ConvToStr(1)));\r                   certinfo->data.insert(std::make_pair("trusted",ConvToStr(0)));\r         }\r\r             certinfo->data.insert(std::make_pair("dn",std::string(X509_NAME_oneline(X509_get_subject_name(cert),0,0))));\r           certinfo->data.insert(std::make_pair("issuer",std::string(X509_NAME_oneline(X509_get_issuer_name(cert),0,0))));\r\r               if (!X509_digest(cert, digest, md, &n))\r                {\r                      certinfo->data.insert(std::make_pair("error","Out of memory generating fingerprint"));\r         }\r              else\r           {\r                      certinfo->data.insert(std::make_pair("fingerprint",irc::hex(md, n)));\r          }\r\r             if ((ASN1_UTCTIME_cmp_time_t(X509_get_notAfter(cert), time(NULL)) == -1) || (ASN1_UTCTIME_cmp_time_t(X509_get_notBefore(cert), time(NULL)) == 0))\r              {\r                      certinfo->data.insert(std::make_pair("error","Not activated, or expired certificate"));\r                }\r\r             X509_free(cert);\r       }\r};\r\rstatic int error_callback(const char *str, size_t len, void *u)\r{\r        ModuleSSLOpenSSL* mssl = (ModuleSSLOpenSSL*)u;\r mssl->PublicInstance->Log(DEFAULT, "SSL error: " + std::string(str, len - 1));\r return 0;\r}\r\rMODULE_INIT(ModuleSSLOpenSSL);\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+
+#ifdef WINDOWS
+#include <openssl/applink.c>
+#endif
+
+#include "configreader.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+
+#include "socket.h"
+#include "hashcomp.h"
+
+#include "transport.h"
+
+#ifdef WINDOWS
+#pragma comment(lib, "libeay32MTd")
+#pragma comment(lib, "ssleay32MTd")
+#undef MAX_DESCRIPTORS
+#define MAX_DESCRIPTORS 10000
+#endif
+
+/* $ModDesc: Provides SSL support for clients */
+/* $CompileFlags: pkgconfversion("openssl","0.9.7") pkgconfincludes("openssl","/openssl/ssl.h","") */
+/* $LinkerFlags: rpath("pkg-config --libs openssl") pkgconflibs("openssl","/libssl.so","-lssl -lcrypto -ldl") */
+/* $ModDep: transport.h */
+
+enum issl_status { ISSL_NONE, ISSL_HANDSHAKING, ISSL_OPEN };
+enum issl_io_status { ISSL_WRITE, ISSL_READ };
+
+static bool SelfSigned = false;
+
+bool isin(int port, const std::vector<int> &portlist)
+{
+       for(unsigned int i = 0; i < portlist.size(); i++)
+               if(portlist[i] == port)
+                       return true;
+
+       return false;
+}
+
+char* get_error()
+{
+       return ERR_error_string(ERR_get_error(), NULL);
+}
+
+static int error_callback(const char *str, size_t len, void *u);
+
+/** Represents an SSL user's extra data
+ */
+class issl_session : public classbase
+{
+public:
+       SSL* sess;
+       issl_status status;
+       issl_io_status rstat;
+       issl_io_status wstat;
+
+       unsigned int inbufoffset;
+       char* inbuf;                    // Buffer OpenSSL reads into.
+       std::string outbuf;     // Buffer for outgoing data that OpenSSL will not take.
+       int fd;
+       bool outbound;
+
+       issl_session()
+       {
+               outbound = false;
+               rstat = ISSL_READ;
+               wstat = ISSL_WRITE;
+       }
+};
+
+static int OnVerify(int preverify_ok, X509_STORE_CTX *ctx)
+{
+       /* XXX: This will allow self signed certificates.
+        * In the future if we want an option to not allow this,
+        * we can just return preverify_ok here, and openssl
+        * will boot off self-signed and invalid peer certs.
+        */
+       int ve = X509_STORE_CTX_get_error(ctx);
+
+       SelfSigned = (ve == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT);
+
+       return 1;
+}
+
+class ModuleSSLOpenSSL : public Module
+{
+
+       ConfigReader* Conf;
+
+       std::vector<int> listenports;
+
+       int inbufsize;
+       issl_session sessions[MAX_DESCRIPTORS];
+
+       SSL_CTX* ctx;
+       SSL_CTX* clictx;
+
+       char* dummy;
+       char cipher[MAXBUF];
+
+       std::string keyfile;
+       std::string certfile;
+       std::string cafile;
+       // std::string crlfile;
+       std::string dhfile;
+       std::string sslports;
+
+       int clientactive;
+
+ public:
+
+       InspIRCd* PublicInstance;
+
+       ModuleSSLOpenSSL(InspIRCd* Me)
+               : Module(Me), PublicInstance(Me)
+       {
+               ServerInstance->PublishInterface("InspSocketHook", this);
+
+               // Not rehashable...because I cba to reduce all the sizes of existing buffers.
+               inbufsize = ServerInstance->Config->NetBufferSize;
+
+               /* Global SSL library initialization*/
+               SSL_library_init();
+               SSL_load_error_strings();
+
+               /* Build our SSL contexts:
+                * NOTE: OpenSSL makes us have two contexts, one for servers and one for clients. ICK.
+                */
+               ctx = SSL_CTX_new( SSLv23_server_method() );
+               clictx = SSL_CTX_new( SSLv23_client_method() );
+
+               SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, OnVerify);
+               SSL_CTX_set_verify(clictx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, OnVerify);
+
+               // Needs the flag as it ignores a plain /rehash
+               OnRehash(NULL,"ssl");
+       }
+
+       virtual void OnRehash(userrec* user, const std::string &param)
+       {
+               if (param != "ssl")
+                       return;
+
+               Conf = new ConfigReader(ServerInstance);
+
+               for (unsigned int i = 0; i < listenports.size(); i++)
+               {
+                       ServerInstance->Config->DelIOHook(listenports[i]);
+               }
+
+               listenports.clear();
+               clientactive = 0;
+               sslports.clear();
+
+               for (int i = 0; i < Conf->Enumerate("bind"); i++)
+               {
+                       // For each <bind> tag
+                       std::string x = Conf->ReadValue("bind", "type", i);
+                       if (((x.empty()) || (x == "clients")) && (Conf->ReadValue("bind", "ssl", i) == "openssl"))
+                       {
+                               // Get the port we're meant to be listening on with SSL
+                               std::string port = Conf->ReadValue("bind", "port", i);
+                               irc::portparser portrange(port, false);
+                               long portno = -1;
+                               while ((portno = portrange.GetToken()))
+                               {
+                                       clientactive++;
+                                       try
+                                       {
+                                               if (ServerInstance->Config->AddIOHook(portno, this))
+                                               {
+                                                       listenports.push_back(portno);
+                                                               for (size_t i = 0; i < ServerInstance->Config->ports.size(); i++)
+                                                               if (ServerInstance->Config->ports[i]->GetPort() == portno)
+                                                                       ServerInstance->Config->ports[i]->SetDescription("ssl");
+                                                       ServerInstance->Log(DEFAULT, "m_ssl_openssl.so: Enabling SSL for port %d", portno);
+                                                       sslports.append("*:").append(ConvToStr(portno)).append(";");
+                                               }
+                                               else
+                                               {
+                                                       ServerInstance->Log(DEFAULT, "m_ssl_openssl.so: FAILED to enable SSL on port %d, maybe you have another ssl or similar module loaded?", portno);
+                                               }
+                                       }
+                                       catch (ModuleException &e)
+                                       {
+                                               ServerInstance->Log(DEFAULT, "m_ssl_openssl.so: FAILED to enable SSL on port %d: %s. Maybe it's already hooked by the same port on a different IP, or you have another SSL or similar module loaded?", portno, e.GetReason());
+                                       }
+                               }
+                       }
+               }
+
+               if (!sslports.empty())
+                       sslports.erase(sslports.end() - 1);
+
+               std::string confdir(ServerInstance->ConfigFileName);
+               // +1 so we the path ends with a /
+               confdir = confdir.substr(0, confdir.find_last_of('/') + 1);
+
+               cafile   = Conf->ReadValue("openssl", "cafile", 0);
+               certfile = Conf->ReadValue("openssl", "certfile", 0);
+               keyfile  = Conf->ReadValue("openssl", "keyfile", 0);
+               dhfile   = Conf->ReadValue("openssl", "dhfile", 0);
+
+               // Set all the default values needed.
+               if (cafile.empty())
+                       cafile = "ca.pem";
+
+               if (certfile.empty())
+                       certfile = "cert.pem";
+
+               if (keyfile.empty())
+                       keyfile = "key.pem";
+
+               if (dhfile.empty())
+                       dhfile = "dhparams.pem";
+
+               // Prepend relative paths with the path to the config directory.
+               if (cafile[0] != '/')
+                       cafile = confdir + cafile;
+
+               if (certfile[0] != '/')
+                       certfile = confdir + certfile;
+
+               if (keyfile[0] != '/')
+                       keyfile = confdir + keyfile;
+
+               if (dhfile[0] != '/')
+                       dhfile = confdir + dhfile;
+
+               /* Load our keys and certificates
+                * NOTE: OpenSSL's error logging API sucks, don't blame us for this clusterfuck.
+                */
+               if ((!SSL_CTX_use_certificate_chain_file(ctx, certfile.c_str())) || (!SSL_CTX_use_certificate_chain_file(clictx, certfile.c_str())))
+               {
+                       ServerInstance->Log(DEFAULT, "m_ssl_openssl.so: Can't read certificate file %s. %s", certfile.c_str(), strerror(errno));
+                       ERR_print_errors_cb(error_callback, this);
+               }
+
+               if (((!SSL_CTX_use_PrivateKey_file(ctx, keyfile.c_str(), SSL_FILETYPE_PEM))) || (!SSL_CTX_use_PrivateKey_file(clictx, keyfile.c_str(), SSL_FILETYPE_PEM)))
+               {
+                       ServerInstance->Log(DEFAULT, "m_ssl_openssl.so: Can't read key file %s. %s", keyfile.c_str(), strerror(errno));
+                       ERR_print_errors_cb(error_callback, this);
+               }
+
+               /* Load the CAs we trust*/
+               if (((!SSL_CTX_load_verify_locations(ctx, cafile.c_str(), 0))) || (!SSL_CTX_load_verify_locations(clictx, cafile.c_str(), 0)))
+               {
+                       ServerInstance->Log(DEFAULT, "m_ssl_openssl.so: Can't read CA list from %s. %s", cafile.c_str(), strerror(errno));
+                       ERR_print_errors_cb(error_callback, this);
+               }
+
+               FILE* dhpfile = fopen(dhfile.c_str(), "r");
+               DH* ret;
+
+               if (dhpfile == NULL)
+               {
+                       ServerInstance->Log(DEFAULT, "m_ssl_openssl.so Couldn't open DH file %s: %s", dhfile.c_str(), strerror(errno));
+                       throw ModuleException("Couldn't open DH file " + dhfile + ": " + strerror(errno));
+               }
+               else
+               {
+                       ret = PEM_read_DHparams(dhpfile, NULL, NULL, NULL);
+                       if ((SSL_CTX_set_tmp_dh(ctx, ret) < 0) || (SSL_CTX_set_tmp_dh(clictx, ret) < 0))
+                       {
+                               ServerInstance->Log(DEFAULT, "m_ssl_openssl.so: Couldn't set DH parameters %s. SSL errors follow:", dhfile.c_str());
+                               ERR_print_errors_cb(error_callback, this);
+                       }
+               }
+
+               fclose(dhpfile);
+
+               DELETE(Conf);
+       }
+
+       virtual void On005Numeric(std::string &output)
+       {
+               output.append(" SSL=" + sslports);
+       }
+
+       virtual ~ModuleSSLOpenSSL()
+       {
+               SSL_CTX_free(ctx);
+               SSL_CTX_free(clictx);
+       }
+
+       virtual void OnCleanup(int target_type, void* item)
+       {
+               if (target_type == TYPE_USER)
+               {
+                       userrec* user = (userrec*)item;
+
+                       if (user->GetExt("ssl", dummy) && IS_LOCAL(user) && isin(user->GetPort(), listenports))
+                       {
+                               // User is using SSL, they're a local user, and they're using one of *our* SSL ports.
+                               // Potentially there could be multiple SSL modules loaded at once on different ports.
+                               ServerInstance->GlobalCulls.AddItem(user, "SSL module unloading");
+                       }
+                       if (user->GetExt("ssl_cert", dummy) && isin(user->GetPort(), listenports))
+                       {
+                               ssl_cert* tofree;
+                               user->GetExt("ssl_cert", tofree);
+                               delete tofree;
+                               user->Shrink("ssl_cert");
+                       }
+               }
+       }
+
+       virtual void OnUnloadModule(Module* mod, const std::string &name)
+       {
+               if (mod == this)
+               {
+                       for(unsigned int i = 0; i < listenports.size(); i++)
+                       {
+                               ServerInstance->Config->DelIOHook(listenports[i]);
+                               for (size_t j = 0; j < ServerInstance->Config->ports.size(); j++)
+                                       if (ServerInstance->Config->ports[j]->GetPort() == listenports[i])
+                                               ServerInstance->Config->ports[j]->SetDescription("plaintext");
+                       }
+               }
+       }
+
+       virtual Version GetVersion()
+       {
+               return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION);
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnRawSocketConnect] = List[I_OnRawSocketAccept] = List[I_OnRawSocketClose] = List[I_OnRawSocketRead] = List[I_OnRawSocketWrite] = List[I_OnCleanup] = List[I_On005Numeric] = 1;
+               List[I_OnRequest] = List[I_OnSyncUserMetaData] = List[I_OnDecodeMetaData] = List[I_OnUnloadModule] = List[I_OnRehash] = List[I_OnWhois] = List[I_OnPostConnect] = 1;
+       }
+
+       virtual char* OnRequest(Request* request)
+       {
+               ISHRequest* ISR = (ISHRequest*)request;
+               if (strcmp("IS_NAME", request->GetId()) == 0)
+               {
+                       return "openssl";
+               }
+               else if (strcmp("IS_HOOK", request->GetId()) == 0)
+               {
+                       char* ret = "OK";
+                       try
+                       {
+                               ret = ServerInstance->Config->AddIOHook((Module*)this, (InspSocket*)ISR->Sock) ? (char*)"OK" : NULL;
+                       }
+                       catch (ModuleException &e)
+                       {
+                               return NULL;
+                       }
+
+                       return ret;
+               }
+               else if (strcmp("IS_UNHOOK", request->GetId()) == 0)
+               {
+                       return ServerInstance->Config->DelIOHook((InspSocket*)ISR->Sock) ? (char*)"OK" : NULL;
+               }
+               else if (strcmp("IS_HSDONE", request->GetId()) == 0)
+               {
+                       ServerInstance->Log(DEBUG,"Module checking if handshake is done");
+                       if (ISR->Sock->GetFd() < 0)
+                               return (char*)"OK";
+
+                       issl_session* session = &sessions[ISR->Sock->GetFd()];
+                       return (session->status == ISSL_HANDSHAKING) ? NULL : (char*)"OK";
+               }
+               else if (strcmp("IS_ATTACH", request->GetId()) == 0)
+               {
+                       issl_session* session = &sessions[ISR->Sock->GetFd()];
+                       if (session->sess)
+                       {
+                               VerifyCertificate(session, (InspSocket*)ISR->Sock);
+                               return "OK";
+                       }
+               }
+               return NULL;
+       }
+
+
+       virtual void OnRawSocketAccept(int fd, const std::string &ip, int localport)
+       {
+               issl_session* session = &sessions[fd];
+
+               session->fd = fd;
+               session->inbuf = new char[inbufsize];
+               session->inbufoffset = 0;
+               session->sess = SSL_new(ctx);
+               session->status = ISSL_NONE;
+               session->outbound = false;
+
+               if (session->sess == NULL)
+                       return;
+
+               if (SSL_set_fd(session->sess, fd) == 0)
+               {
+                       ServerInstance->Log(DEBUG,"BUG: Can't set fd with SSL_set_fd: %d", fd);
+                       return;
+               }
+
+               Handshake(session);
+       }
+
+       virtual void OnRawSocketConnect(int fd)
+       {
+               ServerInstance->Log(DEBUG,"OnRawSocketConnect connecting");
+               issl_session* session = &sessions[fd];
+
+               session->fd = fd;
+               session->inbuf = new char[inbufsize];
+               session->inbufoffset = 0;
+               session->sess = SSL_new(clictx);
+               session->status = ISSL_NONE;
+               session->outbound = true;
+
+               if (session->sess == NULL)
+                       return;
+
+               if (SSL_set_fd(session->sess, fd) == 0)
+               {
+                       ServerInstance->Log(DEBUG,"BUG: Can't set fd with SSL_set_fd: %d", fd);
+                       return;
+               }
+
+               Handshake(session);
+               ServerInstance->Log(DEBUG,"Exiting OnRawSocketConnect");
+       }
+
+       virtual void OnRawSocketClose(int fd)
+       {
+               CloseSession(&sessions[fd]);
+
+               EventHandler* user = ServerInstance->SE->GetRef(fd);
+
+               if ((user) && (user->GetExt("ssl_cert", dummy)))
+               {
+                       ssl_cert* tofree;
+                       user->GetExt("ssl_cert", tofree);
+                       delete tofree;
+                       user->Shrink("ssl_cert");
+               }
+       }
+
+       virtual int OnRawSocketRead(int fd, char* buffer, unsigned int count, int &readresult)
+       {
+               issl_session* session = &sessions[fd];
+
+               ServerInstance->Log(DEBUG,"OnRawSocketRead");
+
+               if (!session->sess)
+               {
+                       ServerInstance->Log(DEBUG,"OnRawSocketRead has no session");
+                       readresult = 0;
+                       CloseSession(session);
+                       return 1;
+               }
+
+               if (session->status == ISSL_HANDSHAKING)
+               {
+                       if (session->rstat == ISSL_READ || session->wstat == ISSL_READ)
+                       {
+                               ServerInstance->Log(DEBUG,"Resume handshake in read");
+                               // The handshake isn't finished and it wants to read, try to finish it.
+                               if (!Handshake(session))
+                               {
+                                       ServerInstance->Log(DEBUG,"Cant resume handshake in read");
+                                       // Couldn't resume handshake.
+                                       return -1;
+                               }
+                       }
+                       else
+                       {
+                               errno = EAGAIN;
+                               return -1;
+                       }
+               }
+
+               // If we resumed the handshake then session->status will be ISSL_OPEN
+
+               if (session->status == ISSL_OPEN)
+               {
+                       if (session->wstat == ISSL_READ)
+                       {
+                               if(DoWrite(session) == 0)
+                                       return 0;
+                       }
+
+                       if (session->rstat == ISSL_READ)
+                       {
+                               int ret = DoRead(session);
+
+                               if (ret > 0)
+                               {
+                                       if (count <= session->inbufoffset)
+                                       {
+                                               memcpy(buffer, session->inbuf, count);
+                                               // Move the stuff left in inbuf to the beginning of it
+                                               memcpy(session->inbuf, session->inbuf + count, (session->inbufoffset - count));
+                                               // Now we need to set session->inbufoffset to the amount of data still waiting to be handed to insp.
+                                               session->inbufoffset -= count;
+                                               // Insp uses readresult as the count of how much data there is in buffer, so:
+                                               readresult = count;
+                                       }
+                                       else
+                                       {
+                                               // There's not as much in the inbuf as there is space in the buffer, so just copy the whole thing.
+                                               memcpy(buffer, session->inbuf, session->inbufoffset);
+
+                                               readresult = session->inbufoffset;
+                                               // Zero the offset, as there's nothing there..
+                                               session->inbufoffset = 0;
+                                       }
+
+                                       return 1;
+                               }
+                               else
+                               {
+                                       return ret;
+                               }
+                       }
+               }
+
+               return -1;
+       }
+
+       virtual int OnRawSocketWrite(int fd, const char* buffer, int count)
+       {
+               issl_session* session = &sessions[fd];
+
+               if (!session->sess)
+               {
+                       ServerInstance->Log(DEBUG,"Close session missing sess");
+                       CloseSession(session);
+                       return -1;
+               }
+
+               session->outbuf.append(buffer, count);
+
+               if (session->status == ISSL_HANDSHAKING)
+               {
+                       // The handshake isn't finished, try to finish it.
+                       if (session->rstat == ISSL_WRITE || session->wstat == ISSL_WRITE)
+                       {
+                               ServerInstance->Log(DEBUG,"Handshake resume");
+                               Handshake(session);
+                       }
+               }
+
+               if (session->status == ISSL_OPEN)
+               {
+                       if (session->rstat == ISSL_WRITE)
+                       {
+                               ServerInstance->Log(DEBUG,"DoRead");
+                               DoRead(session);
+                       }
+
+                       if (session->wstat == ISSL_WRITE)
+                       {
+                               ServerInstance->Log(DEBUG,"DoWrite");
+                               return DoWrite(session);
+                       }
+               }
+
+               return 1;
+       }
+
+       int DoWrite(issl_session* session)
+       {
+               if (!session->outbuf.size())
+                       return -1;
+
+               int ret = SSL_write(session->sess, session->outbuf.data(), session->outbuf.size());
+
+               if (ret == 0)
+               {
+                       ServerInstance->Log(DEBUG,"Oops, got 0 from SSL_write");
+                       CloseSession(session);
+                       return 0;
+               }
+               else if (ret < 0)
+               {
+                       int err = SSL_get_error(session->sess, ret);
+
+                       if (err == SSL_ERROR_WANT_WRITE)
+                       {
+                               session->wstat = ISSL_WRITE;
+                               return -1;
+                       }
+                       else if (err == SSL_ERROR_WANT_READ)
+                       {
+                               session->wstat = ISSL_READ;
+                               return -1;
+                       }
+                       else
+                       {
+                               ServerInstance->Log(DEBUG,"Close due to returned -1 in SSL_Write");
+                               CloseSession(session);
+                               return 0;
+                       }
+               }
+               else
+               {
+                       session->outbuf = session->outbuf.substr(ret);
+                       return ret;
+               }
+       }
+
+       int DoRead(issl_session* session)
+       {
+               // Is this right? Not sure if the unencrypted data is garaunteed to be the same length.
+               // Read into the inbuffer, offset from the beginning by the amount of data we have that insp hasn't taken yet.
+               
+               ServerInstance->Log(DEBUG,"DoRead");
+
+               int ret = SSL_read(session->sess, session->inbuf + session->inbufoffset, inbufsize - session->inbufoffset);
+
+               if (ret == 0)
+               {
+                       // Client closed connection.
+                       ServerInstance->Log(DEBUG,"Oops, got 0 from SSL_read");
+                       CloseSession(session);
+                       return 0;
+               }
+               else if (ret < 0)
+               {
+                       int err = SSL_get_error(session->sess, ret);
+
+                       if (err == SSL_ERROR_WANT_READ)
+                       {
+                               session->rstat = ISSL_READ;
+                               ServerInstance->Log(DEBUG,"Setting want_read");
+                               return -1;
+                       }
+                       else if (err == SSL_ERROR_WANT_WRITE)
+                       {
+                               session->rstat = ISSL_WRITE;
+                               ServerInstance->Log(DEBUG,"Setting want_write");
+                               return -1;
+                       }
+                       else
+                       {
+                               ServerInstance->Log(DEBUG,"Closed due to returned -1 in SSL_Read");
+                               CloseSession(session);
+                               return 0;
+                       }
+               }
+               else
+               {
+                       // Read successfully 'ret' bytes into inbuf + inbufoffset
+                       // There are 'ret' + 'inbufoffset' bytes of data in 'inbuf'
+                       // 'buffer' is 'count' long
+
+                       session->inbufoffset += ret;
+
+                       return ret;
+               }
+       }
+
+       // :kenny.chatspike.net 320 Om Epy|AFK :is a Secure Connection
+       virtual void OnWhois(userrec* source, userrec* dest)
+       {
+               if (!clientactive)
+                       return;
+
+               // Bugfix, only send this numeric for *our* SSL users
+               if (dest->GetExt("ssl", dummy) || (IS_LOCAL(dest) &&  isin(dest->GetPort(), listenports)))
+               {
+                       ServerInstance->SendWhoisLine(source, dest, 320, "%s %s :is using a secure connection", source->nick, dest->nick);
+               }
+       }
+
+       virtual void OnSyncUserMetaData(userrec* user, Module* proto, void* opaque, const std::string &extname, bool displayable)
+       {
+               // check if the linking module wants to know about OUR metadata
+               if (extname == "ssl")
+               {
+                       // check if this user has an swhois field to send
+                       if(user->GetExt(extname, dummy))
+                       {
+                               // call this function in the linking module, let it format the data how it
+                               // sees fit, and send it on its way. We dont need or want to know how.
+                               proto->ProtoSendMetaData(opaque, TYPE_USER, user, extname, displayable ? "Enabled" : "ON");
+                       }
+               }
+       }
+
+       virtual void OnDecodeMetaData(int target_type, void* target, const std::string &extname, const std::string &extdata)
+       {
+               // check if its our metadata key, and its associated with a user
+               if ((target_type == TYPE_USER) && (extname == "ssl"))
+               {
+                       userrec* dest = (userrec*)target;
+                       // if they dont already have an ssl flag, accept the remote server's
+                       if (!dest->GetExt(extname, dummy))
+                       {
+                               dest->Extend(extname, "ON");
+                       }
+               }
+       }
+
+       bool Handshake(issl_session* session)
+       {
+               ServerInstance->Log(DEBUG,"Handshake");
+               int ret;
+
+               if (session->outbound)
+               {
+                       ServerInstance->Log(DEBUG,"SSL_connect");
+                       ret = SSL_connect(session->sess);
+               }
+               else
+                       ret = SSL_accept(session->sess);
+
+               if (ret < 0)
+               {
+                       int err = SSL_get_error(session->sess, ret);
+
+                       if (err == SSL_ERROR_WANT_READ)
+                       {
+                               ServerInstance->Log(DEBUG,"Want read, handshaking");
+                               session->rstat = ISSL_READ;
+                               session->status = ISSL_HANDSHAKING;
+                               return true;
+                       }
+                       else if (err == SSL_ERROR_WANT_WRITE)
+                       {
+                               ServerInstance->Log(DEBUG,"Want write, handshaking");
+                               session->wstat = ISSL_WRITE;
+                               session->status = ISSL_HANDSHAKING;
+                               MakePollWrite(session);
+                               return true;
+                       }
+                       else
+                       {
+                               ServerInstance->Log(DEBUG,"Handshake failed");
+                               CloseSession(session);
+                       }
+
+                       return false;
+               }
+               else if (ret > 0)
+               {
+                       // Handshake complete.
+                       // This will do for setting the ssl flag...it could be done earlier if it's needed. But this seems neater.
+                       userrec* u = ServerInstance->FindDescriptor(session->fd);
+                       if (u)
+                       {
+                               if (!u->GetExt("ssl", dummy))
+                                       u->Extend("ssl", "ON");
+                       }
+
+                       session->status = ISSL_OPEN;
+
+                       MakePollWrite(session);
+
+                       return true;
+               }
+               else if (ret == 0)
+               {
+                       int ssl_err = SSL_get_error(session->sess, ret);
+                       char buf[1024];
+                       ERR_print_errors_fp(stderr);
+                       ServerInstance->Log(DEBUG,"Handshake fail 2: %d: %s", ssl_err, ERR_error_string(ssl_err,buf));
+                       CloseSession(session);
+                       return true;
+               }
+
+               return true;
+       }
+
+       virtual void OnPostConnect(userrec* user)
+       {
+               // This occurs AFTER OnUserConnect so we can be sure the
+               // protocol module has propogated the NICK message.
+               if ((user->GetExt("ssl", dummy)) && (IS_LOCAL(user)))
+               {
+                       // Tell whatever protocol module we're using that we need to inform other servers of this metadata NOW.
+                       std::deque<std::string>* metadata = new std::deque<std::string>;
+                       metadata->push_back(user->nick);
+                       metadata->push_back("ssl");             // The metadata id
+                       metadata->push_back("ON");              // The value to send
+                       Event* event = new Event((char*)metadata,(Module*)this,"send_metadata");
+                       event->Send(ServerInstance);            // Trigger the event. We don't care what module picks it up.
+                       DELETE(event);
+                       DELETE(metadata);
+
+                       VerifyCertificate(&sessions[user->GetFd()], user);
+                       if (sessions[user->GetFd()].sess)
+                               user->WriteServ("NOTICE %s :*** You are connected using SSL cipher \"%s\"", user->nick, SSL_get_cipher(sessions[user->GetFd()].sess));
+               }
+       }
+
+       void MakePollWrite(issl_session* session)
+       {
+               OnRawSocketWrite(session->fd, NULL, 0);
+               //EventHandler* eh = ServerInstance->FindDescriptor(session->fd);
+               //if (eh)
+               //      ServerInstance->SE->WantWrite(eh);
+       }
+
+       void CloseSession(issl_session* session)
+       {
+               if (session->sess)
+               {
+                       SSL_shutdown(session->sess);
+                       SSL_free(session->sess);
+               }
+
+               if (session->inbuf)
+               {
+                       delete[] session->inbuf;
+               }
+
+               session->outbuf.clear();
+               session->inbuf = NULL;
+               session->sess = NULL;
+               session->status = ISSL_NONE;
+       }
+
+       void VerifyCertificate(issl_session* session, Extensible* user)
+       {
+               if (!session->sess || !user)
+                       return;
+
+               X509* cert;
+               ssl_cert* certinfo = new ssl_cert;
+               unsigned int n;
+               unsigned char md[EVP_MAX_MD_SIZE];
+               const EVP_MD *digest = EVP_md5();
+
+               user->Extend("ssl_cert",certinfo);
+
+               cert = SSL_get_peer_certificate((SSL*)session->sess);
+
+               if (!cert)
+               {
+                       certinfo->data.insert(std::make_pair("error","Could not get peer certificate: "+std::string(get_error())));
+                       return;
+               }
+
+               certinfo->data.insert(std::make_pair("invalid", SSL_get_verify_result(session->sess) != X509_V_OK ? ConvToStr(1) : ConvToStr(0)));
+
+               if (SelfSigned)
+               {
+                       certinfo->data.insert(std::make_pair("unknownsigner",ConvToStr(0)));
+                       certinfo->data.insert(std::make_pair("trusted",ConvToStr(1)));
+               }
+               else
+               {
+                       certinfo->data.insert(std::make_pair("unknownsigner",ConvToStr(1)));
+                       certinfo->data.insert(std::make_pair("trusted",ConvToStr(0)));
+               }
+
+               certinfo->data.insert(std::make_pair("dn",std::string(X509_NAME_oneline(X509_get_subject_name(cert),0,0))));
+               certinfo->data.insert(std::make_pair("issuer",std::string(X509_NAME_oneline(X509_get_issuer_name(cert),0,0))));
+
+               if (!X509_digest(cert, digest, md, &n))
+               {
+                       certinfo->data.insert(std::make_pair("error","Out of memory generating fingerprint"));
+               }
+               else
+               {
+                       certinfo->data.insert(std::make_pair("fingerprint",irc::hex(md, n)));
+               }
+
+               if ((ASN1_UTCTIME_cmp_time_t(X509_get_notAfter(cert), time(NULL)) == -1) || (ASN1_UTCTIME_cmp_time_t(X509_get_notBefore(cert), time(NULL)) == 0))
+               {
+                       certinfo->data.insert(std::make_pair("error","Not activated, or expired certificate"));
+               }
+
+               X509_free(cert);
+       }
+};
+
+static int error_callback(const char *str, size_t len, void *u)
+{
+       ModuleSSLOpenSSL* mssl = (ModuleSSLOpenSSL*)u;
+       mssl->PublicInstance->Log(DEFAULT, "SSL error: " + std::string(str, len - 1));
+       return 0;
+}
+
+MODULE_INIT(ModuleSSLOpenSSL);
+
index 7b1c9086841ade510fb28c5c3150028b4237e7e8..c67b50c8c82495fd285c8e7ff5a485ad64eff343 100644 (file)
@@ -1 +1,180 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r/* $ModDesc: Allows for MD5 encrypted oper passwords */\r/* $ModDep: transport.h */\r\r#include "inspircd.h"\r#include "inspircd_config.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r#include "transport.h"\r#include "wildcard.h"\r\r/** Handle /FINGERPRINT\r */\rclass cmd_fingerprint : public command_t\r{\r public:\r        cmd_fingerprint (InspIRCd* Instance) : command_t(Instance,"FINGERPRINT", 0, 1)\r {\r              this->source = "m_ssl_oper_cert.so";\r           syntax = "<nickname>";\r }       \r                 \r     CmdResult Handle (const char** parameters, int pcnt, userrec *user)\r    {\r              userrec* target = ServerInstance->FindNick(parameters[0]);\r             if (target)\r            {\r                      ssl_cert* cert;\r                        if (target->GetExt("ssl_cert",cert))\r                   {\r                              if (cert->GetFingerprint().length())\r                           {\r                                      user->WriteServ("NOTICE %s :Certificate fingerprint for %s is %s",user->nick,target->nick,cert->GetFingerprint().c_str());\r                                     return CMD_SUCCESS;\r                            }\r                              else\r                           {\r                                      user->WriteServ("NOTICE %s :Certificate fingerprint for %s does not exist!", user->nick,target->nick);\r                                 return CMD_FAILURE;\r                            }\r                      }\r                      else\r                   {\r                              user->WriteServ("NOTICE %s :Certificate fingerprint for %s does not exist!", user->nick, target->nick);\r                                return CMD_FAILURE;\r                    }\r              }\r              else\r           {\r                      user->WriteServ("401 %s %s :No such nickname", user->nick, parameters[0]);\r                     return CMD_FAILURE;\r            }\r      }\r};\r\r\r\rclass ModuleOperSSLCert : public Module\r{\r      ssl_cert* cert;\r        bool HasCert;\r  cmd_fingerprint* mycommand;\r    ConfigReader* cf;\r public:\r\r    ModuleOperSSLCert(InspIRCd* Me)\r                : Module(Me)\r   {\r              mycommand = new cmd_fingerprint(ServerInstance);\r               ServerInstance->AddCommand(mycommand);\r         cf = new ConfigReader(ServerInstance);\r }\r\r     virtual ~ModuleOperSSLCert()\r   {\r              delete cf;\r     }\r\r     void Implements(char* List)\r    {\r              List[I_OnPreCommand] = List[I_OnRehash] = 1;\r   }\r\r     virtual void OnRehash(userrec* user, const std::string &parameter)\r     {\r              delete cf;\r             cf = new ConfigReader(ServerInstance);\r }\r\r     bool OneOfMatches(const char* host, const char* ip, const char* hostlist)\r      {\r              std::stringstream hl(hostlist);\r                std::string xhost;\r             while (hl >> xhost)\r            {\r                      if (match(host,xhost.c_str()) || match(ip,xhost.c_str(),true))\r                 {\r                              return true;\r                   }\r              }\r              return false;\r  }\r\r\r    virtual int OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line)\r       {\r              irc::string cmd = command.c_str();\r             \r               if ((cmd == "OPER") && (validated))\r            {\r                      char TheHost[MAXBUF];\r                  char TheIP[MAXBUF];\r                    std::string LoginName;\r                 std::string Password;\r                  std::string OperType;\r                  std::string HostName;\r                  std::string FingerPrint;\r                       bool SSLOnly;\r                  char* dummy;\r\r                  snprintf(TheHost,MAXBUF,"%s@%s",user->ident,user->host);\r                       snprintf(TheIP, MAXBUF,"%s@%s",user->ident,user->GetIPString());\r\r                      HasCert = user->GetExt("ssl_cert",cert);\r\r                      for (int i = 0; i < cf->Enumerate("oper"); i++)\r                        {\r                              LoginName = cf->ReadValue("oper", "name", i);\r                          Password = cf->ReadValue("oper", "password", i);\r                               OperType = cf->ReadValue("oper", "type", i);\r                           HostName = cf->ReadValue("oper", "host", i);\r                           FingerPrint = cf->ReadValue("oper", "fingerprint", i);\r                         SSLOnly = cf->ReadFlag("oper", "sslonly", i);\r\r                         if (SSLOnly || !FingerPrint.empty())\r                           {\r                                      if ((!strcmp(LoginName.c_str(),parameters[0])) && (!ServerInstance->OperPassCompare(Password.c_str(),parameters[1],i)) && (OneOfMatches(TheHost,TheIP,HostName.c_str())))\r                                      {\r                                              if (SSLOnly && !user->GetExt("ssl", dummy))\r                                            {\r                                                      user->WriteServ("491 %s :This oper login name requires an SSL connection.", user->nick);\r                                                       return 1;\r                                              }\r\r                                             /* This oper would match */\r                                            if ((!cert) || (cert->GetFingerprint() != FingerPrint))\r                                                {\r                                                      user->WriteServ("491 %s :This oper login name requires a matching key fingerprint.",user->nick);\r                                                       ServerInstance->SNO->WriteToSnoMask('o',"'%s' cannot oper, does not match fingerprint", user->nick);\r                                                   ServerInstance->Log(DEFAULT,"OPER: Failed oper attempt by %s!%s@%s: credentials valid, but wrong fingerprint.",user->nick,user->ident,user->host);\r                                                     return 1;\r                                              }\r                                      }\r                              }\r                      }\r              }\r              return 0;\r      }\r\r     virtual Version GetVersion()\r   {\r              return Version(1,1,0,0,VF_VENDOR,API_VERSION);\r }\r};\r\rMODULE_INIT(ModuleOperSSLCert);\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+/* $ModDesc: Allows for MD5 encrypted oper passwords */
+/* $ModDep: transport.h */
+
+#include "inspircd.h"
+#include "inspircd_config.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+#include "transport.h"
+#include "wildcard.h"
+
+/** Handle /FINGERPRINT
+ */
+class cmd_fingerprint : public command_t
+{
+ public:
+       cmd_fingerprint (InspIRCd* Instance) : command_t(Instance,"FINGERPRINT", 0, 1)
+       {
+               this->source = "m_ssl_oper_cert.so";
+               syntax = "<nickname>";
+       }       
+                 
+       CmdResult Handle (const char** parameters, int pcnt, userrec *user)
+       {
+               userrec* target = ServerInstance->FindNick(parameters[0]);
+               if (target)
+               {
+                       ssl_cert* cert;
+                       if (target->GetExt("ssl_cert",cert))
+                       {
+                               if (cert->GetFingerprint().length())
+                               {
+                                       user->WriteServ("NOTICE %s :Certificate fingerprint for %s is %s",user->nick,target->nick,cert->GetFingerprint().c_str());
+                                       return CMD_SUCCESS;
+                               }
+                               else
+                               {
+                                       user->WriteServ("NOTICE %s :Certificate fingerprint for %s does not exist!", user->nick,target->nick);
+                                       return CMD_FAILURE;
+                               }
+                       }
+                       else
+                       {
+                               user->WriteServ("NOTICE %s :Certificate fingerprint for %s does not exist!", user->nick, target->nick);
+                               return CMD_FAILURE;
+                       }
+               }
+               else
+               {
+                       user->WriteServ("401 %s %s :No such nickname", user->nick, parameters[0]);
+                       return CMD_FAILURE;
+               }
+       }
+};
+
+
+
+class ModuleOperSSLCert : public Module
+{
+       ssl_cert* cert;
+       bool HasCert;
+       cmd_fingerprint* mycommand;
+       ConfigReader* cf;
+ public:
+
+       ModuleOperSSLCert(InspIRCd* Me)
+               : Module(Me)
+       {
+               mycommand = new cmd_fingerprint(ServerInstance);
+               ServerInstance->AddCommand(mycommand);
+               cf = new ConfigReader(ServerInstance);
+       }
+
+       virtual ~ModuleOperSSLCert()
+       {
+               delete cf;
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnPreCommand] = List[I_OnRehash] = 1;
+       }
+
+       virtual void OnRehash(userrec* user, const std::string &parameter)
+       {
+               delete cf;
+               cf = new ConfigReader(ServerInstance);
+       }
+
+       bool OneOfMatches(const char* host, const char* ip, const char* hostlist)
+       {
+               std::stringstream hl(hostlist);
+               std::string xhost;
+               while (hl >> xhost)
+               {
+                       if (match(host,xhost.c_str()) || match(ip,xhost.c_str(),true))
+                       {
+                               return true;
+                       }
+               }
+               return false;
+       }
+
+
+       virtual int OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line)
+       {
+               irc::string cmd = command.c_str();
+               
+               if ((cmd == "OPER") && (validated))
+               {
+                       char TheHost[MAXBUF];
+                       char TheIP[MAXBUF];
+                       std::string LoginName;
+                       std::string Password;
+                       std::string OperType;
+                       std::string HostName;
+                       std::string FingerPrint;
+                       bool SSLOnly;
+                       char* dummy;
+
+                       snprintf(TheHost,MAXBUF,"%s@%s",user->ident,user->host);
+                       snprintf(TheIP, MAXBUF,"%s@%s",user->ident,user->GetIPString());
+
+                       HasCert = user->GetExt("ssl_cert",cert);
+
+                       for (int i = 0; i < cf->Enumerate("oper"); i++)
+                       {
+                               LoginName = cf->ReadValue("oper", "name", i);
+                               Password = cf->ReadValue("oper", "password", i);
+                               OperType = cf->ReadValue("oper", "type", i);
+                               HostName = cf->ReadValue("oper", "host", i);
+                               FingerPrint = cf->ReadValue("oper", "fingerprint", i);
+                               SSLOnly = cf->ReadFlag("oper", "sslonly", i);
+
+                               if (SSLOnly || !FingerPrint.empty())
+                               {
+                                       if ((!strcmp(LoginName.c_str(),parameters[0])) && (!ServerInstance->OperPassCompare(Password.c_str(),parameters[1],i)) && (OneOfMatches(TheHost,TheIP,HostName.c_str())))
+                                       {
+                                               if (SSLOnly && !user->GetExt("ssl", dummy))
+                                               {
+                                                       user->WriteServ("491 %s :This oper login name requires an SSL connection.", user->nick);
+                                                       return 1;
+                                               }
+
+                                               /* This oper would match */
+                                               if ((!cert) || (cert->GetFingerprint() != FingerPrint))
+                                               {
+                                                       user->WriteServ("491 %s :This oper login name requires a matching key fingerprint.",user->nick);
+                                                       ServerInstance->SNO->WriteToSnoMask('o',"'%s' cannot oper, does not match fingerprint", user->nick);
+                                                       ServerInstance->Log(DEFAULT,"OPER: Failed oper attempt by %s!%s@%s: credentials valid, but wrong fingerprint.",user->nick,user->ident,user->host);
+                                                       return 1;
+                                               }
+                                       }
+                               }
+                       }
+               }
+               return 0;
+       }
+
+       virtual Version GetVersion()
+       {
+               return Version(1,1,0,0,VF_VENDOR,API_VERSION);
+       }
+};
+
+MODULE_INIT(ModuleOperSSLCert);
+
index 83de798c8b69f59ed5ffc1cb47c06165357eda4d..dc9274f1e9c2909fa5fb2fb3b3ba93d45ea96592 100644 (file)
@@ -1 +1,94 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r#include "transport.h"\r#include "wildcard.h"\r#include "dns.h"\r\r/* $ModDesc: Provides /sslinfo command used to test who a mask matches */\r/* $ModDep: transport.h */\r\r/** Handle /SSLINFO\r */\rclass cmd_sslinfo : public command_t\r{\r public:\r  cmd_sslinfo (InspIRCd* Instance) : command_t(Instance,"SSLINFO", 0, 1)\r {\r              this->source = "m_sslinfo.so";\r         this->syntax = "<nick>";\r       }\r\r     CmdResult Handle (const char** parameters, int pcnt, userrec *user)\r    {\r              userrec* target = ServerInstance->FindNick(parameters[0]);\r             ssl_cert* cert;\r\r               if (target)\r            {\r                      if (target->GetExt("ssl_cert", cert))\r                  {\r                              if (cert->GetError().length())\r                         {\r                                      user->WriteServ("NOTICE %s :*** Error:             %s", user->nick, cert->GetError().c_str());\r                         }\r                              user->WriteServ("NOTICE %s :*** Distinguised Name: %s", user->nick, cert->GetDN().c_str());\r                            user->WriteServ("NOTICE %s :*** Issuer:            %s", user->nick, cert->GetIssuer().c_str());\r                                user->WriteServ("NOTICE %s :*** Key Fingerprint:   %s", user->nick, cert->GetFingerprint().c_str());\r                           return CMD_SUCCESS;\r                    }\r                      else\r                   {\r                              user->WriteServ("NOTICE %s :*** No SSL certificate information for this user.", user->nick);\r                           return CMD_FAILURE;\r                    }\r              }\r              else\r                   user->WriteServ("401 %s %s :No such nickname", user->nick, parameters[0]);\r\r            return CMD_FAILURE;\r    }\r};\r\rclass ModuleSSLInfo : public Module\r{\r    cmd_sslinfo* newcommand;\r public:\r      ModuleSSLInfo(InspIRCd* Me)\r            : Module(Me)\r   {\r              \r               newcommand = new cmd_sslinfo(ServerInstance);\r          ServerInstance->AddCommand(newcommand);\r        }\r\r     void Implements(char* List)\r    {\r      }\r\r     virtual ~ModuleSSLInfo()\r       {\r      }\r      \r       virtual Version GetVersion()\r   {\r              return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION);\r    }\r};\r\rMODULE_INIT(ModuleSSLInfo);\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+#include "transport.h"
+#include "wildcard.h"
+#include "dns.h"
+
+/* $ModDesc: Provides /sslinfo command used to test who a mask matches */
+/* $ModDep: transport.h */
+
+/** Handle /SSLINFO
+ */
+class cmd_sslinfo : public command_t
+{
+ public:
+       cmd_sslinfo (InspIRCd* Instance) : command_t(Instance,"SSLINFO", 0, 1)
+       {
+               this->source = "m_sslinfo.so";
+               this->syntax = "<nick>";
+       }
+
+       CmdResult Handle (const char** parameters, int pcnt, userrec *user)
+       {
+               userrec* target = ServerInstance->FindNick(parameters[0]);
+               ssl_cert* cert;
+
+               if (target)
+               {
+                       if (target->GetExt("ssl_cert", cert))
+                       {
+                               if (cert->GetError().length())
+                               {
+                                       user->WriteServ("NOTICE %s :*** Error:             %s", user->nick, cert->GetError().c_str());
+                               }
+                               user->WriteServ("NOTICE %s :*** Distinguised Name: %s", user->nick, cert->GetDN().c_str());
+                               user->WriteServ("NOTICE %s :*** Issuer:            %s", user->nick, cert->GetIssuer().c_str());
+                               user->WriteServ("NOTICE %s :*** Key Fingerprint:   %s", user->nick, cert->GetFingerprint().c_str());
+                               return CMD_SUCCESS;
+                       }
+                       else
+                       {
+                               user->WriteServ("NOTICE %s :*** No SSL certificate information for this user.", user->nick);
+                               return CMD_FAILURE;
+                       }
+               }
+               else
+                       user->WriteServ("401 %s %s :No such nickname", user->nick, parameters[0]);
+
+               return CMD_FAILURE;
+       }
+};
+
+class ModuleSSLInfo : public Module
+{
+       cmd_sslinfo* newcommand;
+ public:
+       ModuleSSLInfo(InspIRCd* Me)
+               : Module(Me)
+       {
+               
+               newcommand = new cmd_sslinfo(ServerInstance);
+               ServerInstance->AddCommand(newcommand);
+       }
+
+       void Implements(char* List)
+       {
+       }
+
+       virtual ~ModuleSSLInfo()
+       {
+       }
+       
+       virtual Version GetVersion()
+       {
+               return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION);
+       }
+};
+
+MODULE_INIT(ModuleSSLInfo);
+
index a867dad203947c1a351618fccce1f821f5f63bfb..f4e58b7b5969cbee5810b759585c3c129d47ac95 100644 (file)
@@ -1 +1,110 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r#include "configreader.h"\r#include "m_sqlv2.h"\r\rclass ModuleTestClient : public Module\r{\rprivate:\r     \r\rpublic:\r      ModuleTestClient(InspIRCd* Me)\r         : Module::Module(Me)\r   {\r      }\r\r     void Implements(char* List)\r    {\r              List[I_OnRequest] = List[I_OnBackgroundTimer] = 1;\r     }\r              \r       virtual Version GetVersion()\r   {\r              return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION);\r    }\r      \r       virtual void OnBackgroundTimer(time_t foo)\r     {\r              Module* target = ServerInstance->FindFeature("SQL");\r           \r               if(target)\r             {\r                      SQLrequest foo = SQLreq(this, target, "foo", "UPDATE rawr SET foo = '?' WHERE bar = 42", ConvToStr(time(NULL)));\r                       \r                       if(foo.Send())\r                 {\r                              ServerInstance->Log(DEBUG, "Sent query, got given ID %lu", foo.id);\r                    }\r                      else\r                   {\r                              ServerInstance->Log(DEBUG, "SQLrequest failed: %s", foo.error.Str());\r                  }\r              }\r      }\r      \r       virtual char* OnRequest(Request* request)\r      {\r              if(strcmp(SQLRESID, request->GetId()) == 0)\r            {\r                      ServerInstance->Log(DEBUG, "Got SQL result (%s)", request->GetId());\r           \r                       SQLresult* res = (SQLresult*)request;\r\r                 if (res->error.Id() == NO_ERROR)\r                       {\r                              if(res->Cols())\r                                {\r                                      ServerInstance->Log(DEBUG, "Got result with %d rows and %d columns", res->Rows(), res->Cols());\r\r                                       for (int r = 0; r < res->Rows(); r++)\r                                  {\r                                              ServerInstance->Log(DEBUG, "Row %d:", r);\r                                              \r                                               for(int i = 0; i < res->Cols(); i++)\r                                           {\r                                                      ServerInstance->Log(DEBUG, "\t[%s]: %s", res->ColName(i).c_str(), res->GetValue(r, i).d.c_str());\r                                              }\r                                      }\r                              }\r                              else\r                           {\r                                      ServerInstance->Log(DEBUG, "%d rows affected in query", res->Rows());\r                          }\r                      }\r                      else\r                   {\r                              ServerInstance->Log(DEBUG, "SQLrequest failed: %s", res->error.Str());\r                         \r                       }\r              \r                       return SQLSUCCESS;\r             }\r              \r               ServerInstance->Log(DEBUG, "Got unsupported API version string: %s", request->GetId());\r                \r               return NULL;\r   }\r      \r       virtual ~ModuleTestClient()\r    {\r      }       \r};\r\rMODULE_INIT(ModuleTestClient);\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+#include "configreader.h"
+#include "m_sqlv2.h"
+
+class ModuleTestClient : public Module
+{
+private:
+       
+
+public:
+       ModuleTestClient(InspIRCd* Me)
+               : Module::Module(Me)
+       {
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnRequest] = List[I_OnBackgroundTimer] = 1;
+       }
+               
+       virtual Version GetVersion()
+       {
+               return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION);
+       }
+       
+       virtual void OnBackgroundTimer(time_t foo)
+       {
+               Module* target = ServerInstance->FindFeature("SQL");
+               
+               if(target)
+               {
+                       SQLrequest foo = SQLreq(this, target, "foo", "UPDATE rawr SET foo = '?' WHERE bar = 42", ConvToStr(time(NULL)));
+                       
+                       if(foo.Send())
+                       {
+                               ServerInstance->Log(DEBUG, "Sent query, got given ID %lu", foo.id);
+                       }
+                       else
+                       {
+                               ServerInstance->Log(DEBUG, "SQLrequest failed: %s", foo.error.Str());
+                       }
+               }
+       }
+       
+       virtual char* OnRequest(Request* request)
+       {
+               if(strcmp(SQLRESID, request->GetId()) == 0)
+               {
+                       ServerInstance->Log(DEBUG, "Got SQL result (%s)", request->GetId());
+               
+                       SQLresult* res = (SQLresult*)request;
+
+                       if (res->error.Id() == NO_ERROR)
+                       {
+                               if(res->Cols())
+                               {
+                                       ServerInstance->Log(DEBUG, "Got result with %d rows and %d columns", res->Rows(), res->Cols());
+
+                                       for (int r = 0; r < res->Rows(); r++)
+                                       {
+                                               ServerInstance->Log(DEBUG, "Row %d:", r);
+                                               
+                                               for(int i = 0; i < res->Cols(); i++)
+                                               {
+                                                       ServerInstance->Log(DEBUG, "\t[%s]: %s", res->ColName(i).c_str(), res->GetValue(r, i).d.c_str());
+                                               }
+                                       }
+                               }
+                               else
+                               {
+                                       ServerInstance->Log(DEBUG, "%d rows affected in query", res->Rows());
+                               }
+                       }
+                       else
+                       {
+                               ServerInstance->Log(DEBUG, "SQLrequest failed: %s", res->error.Str());
+                               
+                       }
+               
+                       return SQLSUCCESS;
+               }
+               
+               ServerInstance->Log(DEBUG, "Got unsupported API version string: %s", request->GetId());
+               
+               return NULL;
+       }
+       
+       virtual ~ModuleTestClient()
+       {
+       }       
+};
+
+MODULE_INIT(ModuleTestClient);
+
index 2a127258dc883a89c503df3b20824b68dafc2986..e815d1042531764d112aa499bd6ae96c4a0b847a 100644 (file)
@@ -1 +1,452 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include <zlib.h>\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r#include "socket.h"\r#include "hashcomp.h"\r#include "transport.h"\r\r/* $ModDesc: Provides zlib link support for servers */\r/* $LinkerFlags: -lz */\r/* $ModDep: transport.h */\r\r/*\r * Compressed data is transmitted across the link in the following format:\r *\r *   0   1   2   3   4 ... n\r * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+\r * |       n       |              Z0 -> Zn                         |\r * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+\r *\r * Where: n is the size of a frame, in network byte order, 4 bytes.\r * Z0 through Zn are Zlib compressed data, n bytes in length.\r *\r * If the module fails to read the entire frame, then it will buffer\r * the portion of the last frame it received, then attempt to read\r * the next part of the frame next time a write notification arrives.\r *\r * ZLIB_BEST_COMPRESSION (9) is used for all sending of data with\r * a flush after each frame. A frame may contain multiple lines\r * and should be treated as raw binary data.\r *\r */\r\r/* Status of a connection */\renum izip_status { IZIP_OPEN, IZIP_CLOSED };\r\r/* Maximum transfer size per read operation */\rconst unsigned int CHUNK = 128 * 1024;\r\r/* This class manages a compressed chunk of data preceeded by\r * a length count.\r *\r * It can handle having multiple chunks of data in the buffer\r * at any time.\r */\rclass CountedBuffer : public classbase\r{\r  std::string buffer;             /* Current buffer contents */\r  unsigned int amount_expected;   /* Amount of data expected */\r public:\r CountedBuffer()\r        {\r              amount_expected = 0;\r   }\r\r     /** Adds arbitrary compressed data to the buffer.\r       * - Binsry safe, of course.\r    */\r    void AddData(unsigned char* data, int data_length)\r     {\r              buffer.append((const char*)data, data_length);\r         this->NextFrameSize();\r }\r\r     /** Works out the size of the next compressed frame\r     */\r    void NextFrameSize()\r   {\r              if ((!amount_expected) && (buffer.length() >= 4))\r              {\r                      /* We have enough to read an int -\r                      * Yes, this is safe, but its ugly. Give me\r                     * a nicer way to read 4 bytes from a binary\r                    * stream, and push them into a 32 bit int,\r                     * and i'll consider replacing this.\r                    */\r                    amount_expected = ntohl((buffer[3] << 24) | (buffer[2] << 16) | (buffer[1] << 8) | buffer[0]);\r                 buffer = buffer.substr(4);\r             }\r      }\r\r     /** Gets the next frame and returns its size, or returns\r        * zero if there isnt one available yet.\r        * A frame can contain multiple plaintext lines.\r        * - Binary safe.\r       */\r    int GetFrame(unsigned char* frame, int maxsize)\r        {\r              if (amount_expected)\r           {\r                      /* We know how much we're expecting...\r                  * Do we have enough yet?\r                       */\r                    if (buffer.length() >= amount_expected)\r                        {\r                              int j = 0;\r                             for (unsigned int i = 0; i < amount_expected; i++, j++)\r                                        frame[i] = buffer[i];\r\r                         buffer = buffer.substr(j);\r                             amount_expected = 0;\r                           NextFrameSize();\r                               return j;\r                      }\r              }\r              /* Not enough for a frame yet, COME AGAIN! */\r          return 0;\r      }\r};\r\r/** Represents an zipped connections extra data\r */\rclass izip_session : public classbase\r{\r public:\r     z_stream c_stream;      /* compression stream */\r       z_stream d_stream;      /* decompress stream */\r        izip_status status;     /* Connection status */\r        int fd;                 /* File descriptor */\r  CountedBuffer* inbuf;   /* Holds input buffer */\r       std::string outbuf;     /* Holds output buffer */\r};\r\rclass ModuleZLib : public Module\r{\r       izip_session sessions[MAX_DESCRIPTORS];\r\r       /* Used for stats z extensions */\r      float total_out_compressed;\r    float total_in_compressed;\r     float total_out_uncompressed;\r  float total_in_uncompressed;\r   \r public:\r      \r       ModuleZLib(InspIRCd* Me)\r               : Module::Module(Me)\r   {\r              ServerInstance->PublishInterface("InspSocketHook", this);\r\r             total_out_compressed = total_in_compressed = 0;\r                total_out_uncompressed = total_out_uncompressed = 0;\r   }\r\r     virtual ~ModuleZLib()\r  {\r              ServerInstance->UnpublishInterface("InspSocketHook", this);\r    }\r\r     virtual Version GetVersion()\r   {\r              return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION);\r    }\r\r     void Implements(char* List)\r    {\r              List[I_OnRawSocketConnect] = List[I_OnRawSocketAccept] = List[I_OnRawSocketClose] = List[I_OnRawSocketRead] = List[I_OnRawSocketWrite] = 1;\r            List[I_OnStats] = List[I_OnRequest] = 1;\r       }\r\r     /* Handle InspSocketHook API requests */\r       virtual char* OnRequest(Request* request)\r      {\r              ISHRequest* ISR = (ISHRequest*)request;\r                if (strcmp("IS_NAME", request->GetId()) == 0)\r          {\r                      /* Return name */\r                      return "zip";\r          }\r              else if (strcmp("IS_HOOK", request->GetId()) == 0)\r             {\r                      /* Attach to an inspsocket */\r                  char* ret = "OK";\r                      try\r                    {\r                              ret = ServerInstance->Config->AddIOHook((Module*)this, (InspSocket*)ISR->Sock) ? (char*)"OK" : NULL;\r                   }\r                      catch (ModuleException& e)\r                     {\r                              return NULL;\r                   }\r                      return ret;\r            }\r              else if (strcmp("IS_UNHOOK", request->GetId()) == 0)\r           {\r                      /* Detatch from an inspsocket */\r                       return ServerInstance->Config->DelIOHook((InspSocket*)ISR->Sock) ? (char*)"OK" : NULL;\r         }\r              else if (strcmp("IS_HSDONE", request->GetId()) == 0)\r           {\r                      /* Check for completion of handshake\r                    * (actually, this module doesnt handshake)\r                     */\r                    return "OK";\r           }\r              else if (strcmp("IS_ATTACH", request->GetId()) == 0)\r           {\r                      /* Attach certificate data to the inspsocket\r                    * (this module doesnt do that, either)\r                         */\r                    return NULL;\r           }\r              return NULL;\r   }\r\r     /* Handle stats z (misc stats) */\r      virtual int OnStats(char symbol, userrec* user, string_list &results)\r  {\r              if (symbol == 'z')\r             {\r                      std::string sn = ServerInstance->Config->ServerName;\r\r                  /* Yeah yeah, i know, floats are ew.\r                    * We used them here because we'd be casting to float anyway to do this maths,\r                  * and also only floating point numbers can deal with the pretty large numbers\r                  * involved in the total throughput of a server over a large period of time.\r                    * (we dont count 64 bit ints because not all systems have 64 bit ints, and floats\r                      * can still hold more.\r                         */\r                    float outbound_r = 100 - ((total_out_compressed / (total_out_uncompressed + 0.001)) * 100);\r                    float inbound_r = 100 - ((total_in_compressed / (total_in_uncompressed + 0.001)) * 100);\r\r                      float total_compressed = total_in_compressed + total_out_compressed;\r                   float total_uncompressed = total_in_uncompressed + total_out_uncompressed;\r\r                    float total_r = 100 - ((total_compressed / (total_uncompressed + 0.001)) * 100);\r\r                      char outbound_ratio[MAXBUF], inbound_ratio[MAXBUF], combined_ratio[MAXBUF];\r\r                   sprintf(outbound_ratio, "%3.2f%%", outbound_r);\r                        sprintf(inbound_ratio, "%3.2f%%", inbound_r);\r                  sprintf(combined_ratio, "%3.2f%%", total_r);\r\r                  results.push_back(sn+" 304 "+user->nick+" :ZIPSTATS outbound_compressed   = "+ConvToStr(total_out_compressed));\r                        results.push_back(sn+" 304 "+user->nick+" :ZIPSTATS inbound_compressed    = "+ConvToStr(total_in_compressed));\r                 results.push_back(sn+" 304 "+user->nick+" :ZIPSTATS outbound_uncompressed = "+ConvToStr(total_out_uncompressed));\r                      results.push_back(sn+" 304 "+user->nick+" :ZIPSTATS inbound_uncompressed  = "+ConvToStr(total_in_uncompressed));\r                       results.push_back(sn+" 304 "+user->nick+" :ZIPSTATS outbound_ratio        = "+outbound_ratio);\r                 results.push_back(sn+" 304 "+user->nick+" :ZIPSTATS inbound_ratio         = "+inbound_ratio);\r                  results.push_back(sn+" 304 "+user->nick+" :ZIPSTATS combined_ratio        = "+combined_ratio);\r                 return 0;\r              }\r\r             return 0;\r      }\r\r     virtual void OnRawSocketAccept(int fd, const std::string &ip, int localport)\r   {\r              izip_session* session = &sessions[fd];\r \r               /* allocate state and buffers */\r               session->fd = fd;\r              session->status = IZIP_OPEN;\r           session->inbuf = new CountedBuffer();\r\r         session->c_stream.zalloc = (alloc_func)0;\r              session->c_stream.zfree = (free_func)0;\r                session->c_stream.opaque = (voidpf)0;\r\r         session->d_stream.zalloc = (alloc_func)0;\r              session->d_stream.zfree = (free_func)0;\r                session->d_stream.opaque = (voidpf)0;\r  }\r\r     virtual void OnRawSocketConnect(int fd)\r        {\r              /* Nothing special needs doing here compared to accept() */\r            OnRawSocketAccept(fd, "", 0);\r  }\r\r     virtual void OnRawSocketClose(int fd)\r  {\r              CloseSession(&sessions[fd]);\r   }\r\r     virtual int OnRawSocketRead(int fd, char* buffer, unsigned int count, int &readresult)\r {\r              /* Find the sockets session */\r         izip_session* session = &sessions[fd];\r\r                if (session->status == IZIP_CLOSED)\r                    return 0;\r\r             unsigned char compr[CHUNK + 4];\r                unsigned int offset = 0;\r               unsigned int total_size = 0;\r\r          /* Read CHUNK bytes at a time to the buffer (usually 128k) */\r          readresult = read(fd, compr, CHUNK);\r\r          /* Did we get anything? */\r             if (readresult > 0)\r            {\r                      /* Add it to the frame queue */\r                        session->inbuf->AddData(compr, readresult);\r                    total_in_compressed += readresult;\r     \r                       /* Parse all completed frames */\r                       int size = 0;\r                  while ((size = session->inbuf->GetFrame(compr, CHUNK)) != 0)\r                   {\r                              session->d_stream.next_in  = (Bytef*)compr;\r                            session->d_stream.avail_in = 0;\r                                session->d_stream.next_out = (Bytef*)(buffer + offset);\r\r                               /* If we cant call this, well, we're boned. */\r                         if (inflateInit(&session->d_stream) != Z_OK)\r                                   return 0;\r      \r                               while ((session->d_stream.total_out < count) && (session->d_stream.total_in < (unsigned int)size))\r                             {\r                                      session->d_stream.avail_in = session->d_stream.avail_out = 1;\r                                  if (inflate(&session->d_stream, Z_NO_FLUSH) == Z_STREAM_END)\r                                           break;\r                         }\r      \r                               /* Stick a fork in me, i'm done */\r                             inflateEnd(&session->d_stream);\r\r                               /* Update counters and offsets */\r                              total_size += session->d_stream.total_out;\r                             total_in_uncompressed += session->d_stream.total_out;\r                          offset += session->d_stream.total_out;\r                 }\r\r                     /* Null-terminate the buffer -- this doesnt harm binary data */\r                        buffer[total_size] = 0;\r\r                       /* Set the read size to the correct total size */\r                      readresult = total_size;\r\r              }\r              return (readresult > 0);\r       }\r\r     virtual int OnRawSocketWrite(int fd, const char* buffer, int count)\r    {\r              izip_session* session = &sessions[fd];\r         int ocount = count;\r\r           if (!count)     /* Nothing to do! */\r                   return 0;\r\r             if(session->status != IZIP_OPEN)\r               {\r                      /* Seriously, wtf? */\r                  CloseSession(session);\r                 return 0;\r              }\r\r             unsigned char compr[CHUNK + 4];\r\r               /* Gentlemen, start your engines! */\r           if (deflateInit(&session->c_stream, Z_BEST_COMPRESSION) != Z_OK)\r               {\r                      CloseSession(session);\r                 return 0;\r              }\r\r             /* Set buffer sizes (we reserve 4 bytes at the start of the\r             * buffer for the length counters)\r              */\r            session->c_stream.next_in  = (Bytef*)buffer;\r           session->c_stream.next_out = compr + 4;\r\r               /* Compress the text */\r                while ((session->c_stream.total_in < (unsigned int)count) && (session->c_stream.total_out < CHUNK))\r            {\r                      session->c_stream.avail_in = session->c_stream.avail_out = 1;\r                  if (deflate(&session->c_stream, Z_NO_FLUSH) != Z_OK)\r                   {\r                              CloseSession(session);\r                         return 0;\r                      }\r              }\r              /* Finish the stream */\r                for (session->c_stream.avail_out = 1; deflate(&session->c_stream, Z_FINISH) != Z_STREAM_END; session->c_stream.avail_out = 1);\r         deflateEnd(&session->c_stream);\r\r               total_out_uncompressed += ocount;\r              total_out_compressed += session->c_stream.total_out;\r\r          /** Assemble the frame length onto the frame, in network byte order */\r         compr[0] = (session->c_stream.total_out >> 24);\r                compr[1] = (session->c_stream.total_out >> 16);\r                compr[2] = (session->c_stream.total_out >> 8);\r         compr[3] = (session->c_stream.total_out & 0xFF);\r\r              /* Add compressed data plus leading length to the output buffer -\r               * Note, we may have incomplete half-sent frames in here.\r               */\r            session->outbuf.append((const char*)compr, session->c_stream.total_out + 4);\r\r          /* Lets see how much we can send out */\r                int ret = write(fd, session->outbuf.data(), session->outbuf.length());\r\r                /* Check for errors, and advance the buffer if any was sent */\r         if (ret > 0)\r                   session->outbuf = session->outbuf.substr(ret);\r         else if (ret < 1)\r              {\r                      if (ret == -1)\r                 {\r                              if (errno == EAGAIN)\r                                   return 0;\r                              else\r                           {\r                                      session->outbuf.clear();\r                                       return 0;\r                              }\r                      }\r                      else\r                   {\r                              session->outbuf.clear();\r                               return 0;\r                      }\r              }\r\r             /* ALL LIES the lot of it, we havent really written\r             * this amount, but the layer above doesnt need to know.\r                */\r            return ocount;\r }\r      \r       void CloseSession(izip_session* session)\r       {\r              if (session->status == IZIP_OPEN)\r              {\r                      session->status = IZIP_CLOSED;\r                 session->outbuf.clear();\r                       delete session->inbuf;\r         }\r      }\r\r};\r\rMODULE_INIT(ModuleZLib);\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include <zlib.h>
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+#include "socket.h"
+#include "hashcomp.h"
+#include "transport.h"
+
+/* $ModDesc: Provides zlib link support for servers */
+/* $LinkerFlags: -lz */
+/* $ModDep: transport.h */
+
+/*
+ * Compressed data is transmitted across the link in the following format:
+ *
+ *   0   1   2   3   4 ... n
+ * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
+ * |       n       |              Z0 -> Zn                         |
+ * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
+ *
+ * Where: n is the size of a frame, in network byte order, 4 bytes.
+ * Z0 through Zn are Zlib compressed data, n bytes in length.
+ *
+ * If the module fails to read the entire frame, then it will buffer
+ * the portion of the last frame it received, then attempt to read
+ * the next part of the frame next time a write notification arrives.
+ *
+ * ZLIB_BEST_COMPRESSION (9) is used for all sending of data with
+ * a flush after each frame. A frame may contain multiple lines
+ * and should be treated as raw binary data.
+ *
+ */
+
+/* Status of a connection */
+enum izip_status { IZIP_OPEN, IZIP_CLOSED };
+
+/* Maximum transfer size per read operation */
+const unsigned int CHUNK = 128 * 1024;
+
+/* This class manages a compressed chunk of data preceeded by
+ * a length count.
+ *
+ * It can handle having multiple chunks of data in the buffer
+ * at any time.
+ */
+class CountedBuffer : public classbase
+{
+       std::string buffer;             /* Current buffer contents */
+       unsigned int amount_expected;   /* Amount of data expected */
+ public:
+       CountedBuffer()
+       {
+               amount_expected = 0;
+       }
+
+       /** Adds arbitrary compressed data to the buffer.
+        * - Binsry safe, of course.
+        */
+       void AddData(unsigned char* data, int data_length)
+       {
+               buffer.append((const char*)data, data_length);
+               this->NextFrameSize();
+       }
+
+       /** Works out the size of the next compressed frame
+        */
+       void NextFrameSize()
+       {
+               if ((!amount_expected) && (buffer.length() >= 4))
+               {
+                       /* We have enough to read an int -
+                        * Yes, this is safe, but its ugly. Give me
+                        * a nicer way to read 4 bytes from a binary
+                        * stream, and push them into a 32 bit int,
+                        * and i'll consider replacing this.
+                        */
+                       amount_expected = ntohl((buffer[3] << 24) | (buffer[2] << 16) | (buffer[1] << 8) | buffer[0]);
+                       buffer = buffer.substr(4);
+               }
+       }
+
+       /** Gets the next frame and returns its size, or returns
+        * zero if there isnt one available yet.
+        * A frame can contain multiple plaintext lines.
+        * - Binary safe.
+        */
+       int GetFrame(unsigned char* frame, int maxsize)
+       {
+               if (amount_expected)
+               {
+                       /* We know how much we're expecting...
+                        * Do we have enough yet?
+                        */
+                       if (buffer.length() >= amount_expected)
+                       {
+                               int j = 0;
+                               for (unsigned int i = 0; i < amount_expected; i++, j++)
+                                       frame[i] = buffer[i];
+
+                               buffer = buffer.substr(j);
+                               amount_expected = 0;
+                               NextFrameSize();
+                               return j;
+                       }
+               }
+               /* Not enough for a frame yet, COME AGAIN! */
+               return 0;
+       }
+};
+
+/** Represents an zipped connections extra data
+ */
+class izip_session : public classbase
+{
+ public:
+       z_stream c_stream;      /* compression stream */
+       z_stream d_stream;      /* decompress stream */
+       izip_status status;     /* Connection status */
+       int fd;                 /* File descriptor */
+       CountedBuffer* inbuf;   /* Holds input buffer */
+       std::string outbuf;     /* Holds output buffer */
+};
+
+class ModuleZLib : public Module
+{
+       izip_session sessions[MAX_DESCRIPTORS];
+
+       /* Used for stats z extensions */
+       float total_out_compressed;
+       float total_in_compressed;
+       float total_out_uncompressed;
+       float total_in_uncompressed;
+       
+ public:
+       
+       ModuleZLib(InspIRCd* Me)
+               : Module::Module(Me)
+       {
+               ServerInstance->PublishInterface("InspSocketHook", this);
+
+               total_out_compressed = total_in_compressed = 0;
+               total_out_uncompressed = total_out_uncompressed = 0;
+       }
+
+       virtual ~ModuleZLib()
+       {
+               ServerInstance->UnpublishInterface("InspSocketHook", this);
+       }
+
+       virtual Version GetVersion()
+       {
+               return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION);
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnRawSocketConnect] = List[I_OnRawSocketAccept] = List[I_OnRawSocketClose] = List[I_OnRawSocketRead] = List[I_OnRawSocketWrite] = 1;
+               List[I_OnStats] = List[I_OnRequest] = 1;
+       }
+
+       /* Handle InspSocketHook API requests */
+       virtual char* OnRequest(Request* request)
+       {
+               ISHRequest* ISR = (ISHRequest*)request;
+               if (strcmp("IS_NAME", request->GetId()) == 0)
+               {
+                       /* Return name */
+                       return "zip";
+               }
+               else if (strcmp("IS_HOOK", request->GetId()) == 0)
+               {
+                       /* Attach to an inspsocket */
+                       char* ret = "OK";
+                       try
+                       {
+                               ret = ServerInstance->Config->AddIOHook((Module*)this, (InspSocket*)ISR->Sock) ? (char*)"OK" : NULL;
+                       }
+                       catch (ModuleException& e)
+                       {
+                               return NULL;
+                       }
+                       return ret;
+               }
+               else if (strcmp("IS_UNHOOK", request->GetId()) == 0)
+               {
+                       /* Detatch from an inspsocket */
+                       return ServerInstance->Config->DelIOHook((InspSocket*)ISR->Sock) ? (char*)"OK" : NULL;
+               }
+               else if (strcmp("IS_HSDONE", request->GetId()) == 0)
+               {
+                       /* Check for completion of handshake
+                        * (actually, this module doesnt handshake)
+                        */
+                       return "OK";
+               }
+               else if (strcmp("IS_ATTACH", request->GetId()) == 0)
+               {
+                       /* Attach certificate data to the inspsocket
+                        * (this module doesnt do that, either)
+                        */
+                       return NULL;
+               }
+               return NULL;
+       }
+
+       /* Handle stats z (misc stats) */
+       virtual int OnStats(char symbol, userrec* user, string_list &results)
+       {
+               if (symbol == 'z')
+               {
+                       std::string sn = ServerInstance->Config->ServerName;
+
+                       /* Yeah yeah, i know, floats are ew.
+                        * We used them here because we'd be casting to float anyway to do this maths,
+                        * and also only floating point numbers can deal with the pretty large numbers
+                        * involved in the total throughput of a server over a large period of time.
+                        * (we dont count 64 bit ints because not all systems have 64 bit ints, and floats
+                        * can still hold more.
+                        */
+                       float outbound_r = 100 - ((total_out_compressed / (total_out_uncompressed + 0.001)) * 100);
+                       float inbound_r = 100 - ((total_in_compressed / (total_in_uncompressed + 0.001)) * 100);
+
+                       float total_compressed = total_in_compressed + total_out_compressed;
+                       float total_uncompressed = total_in_uncompressed + total_out_uncompressed;
+
+                       float total_r = 100 - ((total_compressed / (total_uncompressed + 0.001)) * 100);
+
+                       char outbound_ratio[MAXBUF], inbound_ratio[MAXBUF], combined_ratio[MAXBUF];
+
+                       sprintf(outbound_ratio, "%3.2f%%", outbound_r);
+                       sprintf(inbound_ratio, "%3.2f%%", inbound_r);
+                       sprintf(combined_ratio, "%3.2f%%", total_r);
+
+                       results.push_back(sn+" 304 "+user->nick+" :ZIPSTATS outbound_compressed   = "+ConvToStr(total_out_compressed));
+                       results.push_back(sn+" 304 "+user->nick+" :ZIPSTATS inbound_compressed    = "+ConvToStr(total_in_compressed));
+                       results.push_back(sn+" 304 "+user->nick+" :ZIPSTATS outbound_uncompressed = "+ConvToStr(total_out_uncompressed));
+                       results.push_back(sn+" 304 "+user->nick+" :ZIPSTATS inbound_uncompressed  = "+ConvToStr(total_in_uncompressed));
+                       results.push_back(sn+" 304 "+user->nick+" :ZIPSTATS outbound_ratio        = "+outbound_ratio);
+                       results.push_back(sn+" 304 "+user->nick+" :ZIPSTATS inbound_ratio         = "+inbound_ratio);
+                       results.push_back(sn+" 304 "+user->nick+" :ZIPSTATS combined_ratio        = "+combined_ratio);
+                       return 0;
+               }
+
+               return 0;
+       }
+
+       virtual void OnRawSocketAccept(int fd, const std::string &ip, int localport)
+       {
+               izip_session* session = &sessions[fd];
+       
+               /* allocate state and buffers */
+               session->fd = fd;
+               session->status = IZIP_OPEN;
+               session->inbuf = new CountedBuffer();
+
+               session->c_stream.zalloc = (alloc_func)0;
+               session->c_stream.zfree = (free_func)0;
+               session->c_stream.opaque = (voidpf)0;
+
+               session->d_stream.zalloc = (alloc_func)0;
+               session->d_stream.zfree = (free_func)0;
+               session->d_stream.opaque = (voidpf)0;
+       }
+
+       virtual void OnRawSocketConnect(int fd)
+       {
+               /* Nothing special needs doing here compared to accept() */
+               OnRawSocketAccept(fd, "", 0);
+       }
+
+       virtual void OnRawSocketClose(int fd)
+       {
+               CloseSession(&sessions[fd]);
+       }
+
+       virtual int OnRawSocketRead(int fd, char* buffer, unsigned int count, int &readresult)
+       {
+               /* Find the sockets session */
+               izip_session* session = &sessions[fd];
+
+               if (session->status == IZIP_CLOSED)
+                       return 0;
+
+               unsigned char compr[CHUNK + 4];
+               unsigned int offset = 0;
+               unsigned int total_size = 0;
+
+               /* Read CHUNK bytes at a time to the buffer (usually 128k) */
+               readresult = read(fd, compr, CHUNK);
+
+               /* Did we get anything? */
+               if (readresult > 0)
+               {
+                       /* Add it to the frame queue */
+                       session->inbuf->AddData(compr, readresult);
+                       total_in_compressed += readresult;
+       
+                       /* Parse all completed frames */
+                       int size = 0;
+                       while ((size = session->inbuf->GetFrame(compr, CHUNK)) != 0)
+                       {
+                               session->d_stream.next_in  = (Bytef*)compr;
+                               session->d_stream.avail_in = 0;
+                               session->d_stream.next_out = (Bytef*)(buffer + offset);
+
+                               /* If we cant call this, well, we're boned. */
+                               if (inflateInit(&session->d_stream) != Z_OK)
+                                       return 0;
+       
+                               while ((session->d_stream.total_out < count) && (session->d_stream.total_in < (unsigned int)size))
+                               {
+                                       session->d_stream.avail_in = session->d_stream.avail_out = 1;
+                                       if (inflate(&session->d_stream, Z_NO_FLUSH) == Z_STREAM_END)
+                                               break;
+                               }
+       
+                               /* Stick a fork in me, i'm done */
+                               inflateEnd(&session->d_stream);
+
+                               /* Update counters and offsets */
+                               total_size += session->d_stream.total_out;
+                               total_in_uncompressed += session->d_stream.total_out;
+                               offset += session->d_stream.total_out;
+                       }
+
+                       /* Null-terminate the buffer -- this doesnt harm binary data */
+                       buffer[total_size] = 0;
+
+                       /* Set the read size to the correct total size */
+                       readresult = total_size;
+
+               }
+               return (readresult > 0);
+       }
+
+       virtual int OnRawSocketWrite(int fd, const char* buffer, int count)
+       {
+               izip_session* session = &sessions[fd];
+               int ocount = count;
+
+               if (!count)     /* Nothing to do! */
+                       return 0;
+
+               if(session->status != IZIP_OPEN)
+               {
+                       /* Seriously, wtf? */
+                       CloseSession(session);
+                       return 0;
+               }
+
+               unsigned char compr[CHUNK + 4];
+
+               /* Gentlemen, start your engines! */
+               if (deflateInit(&session->c_stream, Z_BEST_COMPRESSION) != Z_OK)
+               {
+                       CloseSession(session);
+                       return 0;
+               }
+
+               /* Set buffer sizes (we reserve 4 bytes at the start of the
+                * buffer for the length counters)
+                */
+               session->c_stream.next_in  = (Bytef*)buffer;
+               session->c_stream.next_out = compr + 4;
+
+               /* Compress the text */
+               while ((session->c_stream.total_in < (unsigned int)count) && (session->c_stream.total_out < CHUNK))
+               {
+                       session->c_stream.avail_in = session->c_stream.avail_out = 1;
+                       if (deflate(&session->c_stream, Z_NO_FLUSH) != Z_OK)
+                       {
+                               CloseSession(session);
+                               return 0;
+                       }
+               }
+               /* Finish the stream */
+               for (session->c_stream.avail_out = 1; deflate(&session->c_stream, Z_FINISH) != Z_STREAM_END; session->c_stream.avail_out = 1);
+               deflateEnd(&session->c_stream);
+
+               total_out_uncompressed += ocount;
+               total_out_compressed += session->c_stream.total_out;
+
+               /** Assemble the frame length onto the frame, in network byte order */
+               compr[0] = (session->c_stream.total_out >> 24);
+               compr[1] = (session->c_stream.total_out >> 16);
+               compr[2] = (session->c_stream.total_out >> 8);
+               compr[3] = (session->c_stream.total_out & 0xFF);
+
+               /* Add compressed data plus leading length to the output buffer -
+                * Note, we may have incomplete half-sent frames in here.
+                */
+               session->outbuf.append((const char*)compr, session->c_stream.total_out + 4);
+
+               /* Lets see how much we can send out */
+               int ret = write(fd, session->outbuf.data(), session->outbuf.length());
+
+               /* Check for errors, and advance the buffer if any was sent */
+               if (ret > 0)
+                       session->outbuf = session->outbuf.substr(ret);
+               else if (ret < 1)
+               {
+                       if (ret == -1)
+                       {
+                               if (errno == EAGAIN)
+                                       return 0;
+                               else
+                               {
+                                       session->outbuf.clear();
+                                       return 0;
+                               }
+                       }
+                       else
+                       {
+                               session->outbuf.clear();
+                               return 0;
+                       }
+               }
+
+               /* ALL LIES the lot of it, we havent really written
+                * this amount, but the layer above doesnt need to know.
+                */
+               return ocount;
+       }
+       
+       void CloseSession(izip_session* session)
+       {
+               if (session->status == IZIP_OPEN)
+               {
+                       session->status = IZIP_CLOSED;
+                       session->outbuf.clear();
+                       delete session->inbuf;
+               }
+       }
+
+};
+
+MODULE_INIT(ModuleZLib);
+
index 109bfa6660c990a194ab3f5b58b7a83f3656727a..c5e84261f770b30e54e5ff80cc0e743761113f29 100644 (file)
@@ -1 +1,127 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "base.h"\r\r#ifndef HTTPCLIENT_H__\r#define HTTPCLIENT_H__\r\r#include <string>\r#include <map>\r\rtypedef std::map<std::string,std::string> HeaderMap;\r\rconst char* HTTP_CLIENT_RESPONSE = "HTTPCLIENT_RESPONSE";\rconst char* HTTP_CLIENT_REQUEST = "HTTPCLIENT_REQUEST";\r\r/** This class represents an outgoing HTTP request\r */\rclass HTTPClientRequest : public Request\r{\r protected:\r        std::string url;\r       InspIRCd *Instance;\r    Module *src;\r   HeaderMap Headers;\r public:\r    HTTPClientRequest(InspIRCd *Instance, Module *src, Module* target, const std::string &url)\r             : Request(src, target, HTTP_CLIENT_REQUEST), url(url), Instance(Instance), src(src)\r    {\r              Headers["User-Agent"] = "InspIRCd (m_http_client.so)";\r         Headers["Connection"] = "Close";\r               Headers["Accept"] = "*/*";\r     }\r\r     HTTPClientRequest() : Request(NULL, NULL, HTTP_CLIENT_REQUEST)\r {\r      }\r\r     const std::string &GetURL()\r    {\r              return url;\r    }\r\r     void AddHeader(std::string &header, std::string &data)\r {\r              Headers[header] = data;\r        }\r      \r       void DeleteHeader(std::string &header)\r {\r              Headers.erase(header);\r }\r\r     HeaderMap GetHeaders()\r {\r              return Headers;\r        }\r};\r\rclass HTTPClientResponse : public Request\r{\r protected:\r  friend class HTTPSocket;\r       \r       std::string url;\r       std::string data;\r      int response;\r  std::string responsestr;\r       HeaderMap Headers;\r public:\r    HTTPClientResponse(Module* src, Module* target, std::string &url, int response, std::string responsestr)\r               : Request(src, target, HTTP_CLIENT_RESPONSE), url(url), response(response), responsestr(responsestr)\r   {\r      }\r\r     HTTPClientResponse() : Request(NULL, NULL, HTTP_CLIENT_RESPONSE)\r       {\r      }\r\r     void SetData(const std::string &ndata)\r {\r              data = ndata;\r  }\r      \r       void AddHeader(const std::string &header, const std::string &data)\r     {\r              Headers[header] = data;\r        }\r      \r       const std::string &GetURL()\r    {\r              return url;\r    }\r      \r       const std::string &GetData()\r   {\r              return data;\r   }\r      \r       int GetResponse(std::string &str)\r      {\r              str = responsestr;\r             return response;\r       }\r      \r       std::string GetHeader(const std::string &header)\r       {\r              HeaderMap::iterator i = Headers.find(header);\r          \r               if (i != Headers.end())\r                        return i->second;\r              else\r                   return "";\r     }\r};\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "base.h"
+
+#ifndef HTTPCLIENT_H__
+#define HTTPCLIENT_H__
+
+#include <string>
+#include <map>
+
+typedef std::map<std::string,std::string> HeaderMap;
+
+const char* HTTP_CLIENT_RESPONSE = "HTTPCLIENT_RESPONSE";
+const char* HTTP_CLIENT_REQUEST = "HTTPCLIENT_REQUEST";
+
+/** This class represents an outgoing HTTP request
+ */
+class HTTPClientRequest : public Request
+{
+ protected:
+       std::string url;
+       InspIRCd *Instance;
+       Module *src;
+       HeaderMap Headers;
+ public:
+       HTTPClientRequest(InspIRCd *Instance, Module *src, Module* target, const std::string &url)
+               : Request(src, target, HTTP_CLIENT_REQUEST), url(url), Instance(Instance), src(src)
+       {
+               Headers["User-Agent"] = "InspIRCd (m_http_client.so)";
+               Headers["Connection"] = "Close";
+               Headers["Accept"] = "*/*";
+       }
+
+       HTTPClientRequest() : Request(NULL, NULL, HTTP_CLIENT_REQUEST)
+       {
+       }
+
+       const std::string &GetURL()
+       {
+               return url;
+       }
+
+       void AddHeader(std::string &header, std::string &data)
+       {
+               Headers[header] = data;
+       }
+       
+       void DeleteHeader(std::string &header)
+       {
+               Headers.erase(header);
+       }
+
+       HeaderMap GetHeaders()
+       {
+               return Headers;
+       }
+};
+
+class HTTPClientResponse : public Request
+{
+ protected:
+       friend class HTTPSocket;
+       
+       std::string url;
+       std::string data;
+       int response;
+       std::string responsestr;
+       HeaderMap Headers;
+ public:
+       HTTPClientResponse(Module* src, Module* target, std::string &url, int response, std::string responsestr)
+               : Request(src, target, HTTP_CLIENT_RESPONSE), url(url), response(response), responsestr(responsestr)
+       {
+       }
+
+       HTTPClientResponse() : Request(NULL, NULL, HTTP_CLIENT_RESPONSE)
+       {
+       }
+
+       void SetData(const std::string &ndata)
+       {
+               data = ndata;
+       }
+       
+       void AddHeader(const std::string &header, const std::string &data)
+       {
+               Headers[header] = data;
+       }
+       
+       const std::string &GetURL()
+       {
+               return url;
+       }
+       
+       const std::string &GetData()
+       {
+               return data;
+       }
+       
+       int GetResponse(std::string &str)
+       {
+               str = responsestr;
+               return response;
+       }
+       
+       std::string GetHeader(const std::string &header)
+       {
+               HeaderMap::iterator i = Headers.find(header);
+               
+               if (i != Headers.end())
+                       return i->second;
+               else
+                       return "";
+       }
+};
+
+#endif
index 32bac757f12835d50d8db92e14346add3f8219c2..a8b0bafcdc81f2c26307d27c8972e67d0c508eac 100644 (file)
@@ -1 +1,166 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "base.h"\r\r#ifndef __HTTPD_H__\r#define __HTTPD_H__\r\r#include <string>\r#include <sstream>\r\r/** This class represents a HTTP request.\r * It will be sent to all modules as the data section of\r * an Event.\r */\rclass HTTPRequest : public classbase\r{\r protected:\r\r std::string type;\r      std::string document;\r  std::string ipaddr;\r    std::string postdata;\r  std::stringstream* headers;\r\r public:\r\r /** A socket pointer, which you must return in your HTTPDocument class\r  * if you reply to this request.\r        */\r    void* sock;\r\r   /** Initialize HTTPRequest.\r     * This constructor is called by m_httpd.so to initialize the class.\r    * @param request_type The request type, e.g. GET, POST, HEAD\r   * @param uri The URI, e.g. /page\r       * @param hdr The headers sent with the request\r         * @param opaque An opaque pointer used internally by m_httpd, which you must pass back to the module in your reply.\r    * @param ip The IP address making the web request.\r     * @param pdata The post data (content after headers) received with the request, up to Content-Length in size\r   */\r    HTTPRequest(const std::string &request_type, const std::string &uri, std::stringstream* hdr, void* opaque, const std::string &ip, const std::string &pdata)\r            : type(request_type), document(uri), ipaddr(ip), postdata(pdata), headers(hdr), sock(opaque)\r   {\r      }\r\r     /** Get headers.\r        * All the headers for the web request are returned, as a pointer to a stringstream.\r    * @return The header information\r       */\r    std::stringstream* GetHeaders()\r        {\r              return headers;\r        }\r\r     /** Get the post data (request content).\r        * All post data will be returned, including carriage returns and linefeeds.\r    * @return The postdata\r         */\r    std::string& GetPostData()\r     {\r              return postdata;\r       }\r\r     /** Get the request type.\r       * Any request type can be intercepted, even ones which are invalid in the HTTP/1.1 spec.\r       * @return The request type, e.g. GET, POST, HEAD\r       */\r    std::string& GetType()\r {\r              return type;\r   }\r\r     /** Get URI.\r    * The URI string (URL minus hostname and scheme) will be provided by this function.\r    * @return The URI being requested\r      */\r    std::string& GetURI()\r  {\r              return document;\r       }\r\r     /** Get IP address of requester.\r        * The requesting system's ip address will be returned.\r         * @return The IP address as a string\r   */\r    std::string& GetIP()\r   {\r              return ipaddr;\r }\r};\r\r/** You must return a HTTPDocument to the httpd module by using the Request class.\r * When you initialize this class you may initialize it with all components required to\r * form a valid HTTP response, including document data, headers, and a response code.\r */\rclass HTTPDocument : public classbase\r{\r protected:\r\r        std::stringstream* document;\r   int responsecode;\r      std::string extraheaders;\r\r public:\r\r   /** The socket pointer from an earlier HTTPRequest\r      */\r    void* sock;\r\r   /** Initialize a HTTPRequest ready for sending to m_httpd.so.\r   * @param opaque The socket pointer you obtained from the HTTPRequest at an earlier time\r        * @param doc A stringstream containing the document body\r       * @param response A valid HTTP/1.0 or HTTP/1.1 response code. The response text will be determined for you\r     * based upon the response code.\r        * @param extra Any extra headers to include with the defaults, seperated by carriage return and linefeed.\r      */\r    HTTPDocument(void* opaque, std::stringstream* doc, int response, const std::string &extra) : document(doc), responsecode(response), extraheaders(extra), sock(opaque)\r  {\r      }\r\r     /** Get the document text.\r      * @return The document text\r    */\r    std::stringstream* GetDocument()\r       {\r              return this->document;\r }\r\r     /** Get the document size.\r      * @return the size of the document text in bytes\r       */\r    unsigned long GetDocumentSize()\r        {\r              return this->document->str().length();\r }\r\r     /** Get the response code.\r      * @return The response code\r    */\r    int GetResponseCode()\r  {\r              return this->responsecode;\r     }\r\r     /** Get the headers.\r    * @return The header text, headers seperated by carriage return and linefeed.\r  */\r    std::string& GetExtraHeaders()\r {\r              return this->extraheaders;\r     }\r};\r\r#endif\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "base.h"
+
+#ifndef __HTTPD_H__
+#define __HTTPD_H__
+
+#include <string>
+#include <sstream>
+
+/** This class represents a HTTP request.
+ * It will be sent to all modules as the data section of
+ * an Event.
+ */
+class HTTPRequest : public classbase
+{
+ protected:
+
+       std::string type;
+       std::string document;
+       std::string ipaddr;
+       std::string postdata;
+       std::stringstream* headers;
+
+ public:
+
+       /** A socket pointer, which you must return in your HTTPDocument class
+        * if you reply to this request.
+        */
+       void* sock;
+
+       /** Initialize HTTPRequest.
+        * This constructor is called by m_httpd.so to initialize the class.
+        * @param request_type The request type, e.g. GET, POST, HEAD
+        * @param uri The URI, e.g. /page
+        * @param hdr The headers sent with the request
+        * @param opaque An opaque pointer used internally by m_httpd, which you must pass back to the module in your reply.
+        * @param ip The IP address making the web request.
+        * @param pdata The post data (content after headers) received with the request, up to Content-Length in size
+        */
+       HTTPRequest(const std::string &request_type, const std::string &uri, std::stringstream* hdr, void* opaque, const std::string &ip, const std::string &pdata)
+               : type(request_type), document(uri), ipaddr(ip), postdata(pdata), headers(hdr), sock(opaque)
+       {
+       }
+
+       /** Get headers.
+        * All the headers for the web request are returned, as a pointer to a stringstream.
+        * @return The header information
+        */
+       std::stringstream* GetHeaders()
+       {
+               return headers;
+       }
+
+       /** Get the post data (request content).
+        * All post data will be returned, including carriage returns and linefeeds.
+        * @return The postdata
+        */
+       std::string& GetPostData()
+       {
+               return postdata;
+       }
+
+       /** Get the request type.
+        * Any request type can be intercepted, even ones which are invalid in the HTTP/1.1 spec.
+        * @return The request type, e.g. GET, POST, HEAD
+        */
+       std::string& GetType()
+       {
+               return type;
+       }
+
+       /** Get URI.
+        * The URI string (URL minus hostname and scheme) will be provided by this function.
+        * @return The URI being requested
+        */
+       std::string& GetURI()
+       {
+               return document;
+       }
+
+       /** Get IP address of requester.
+        * The requesting system's ip address will be returned.
+        * @return The IP address as a string
+        */
+       std::string& GetIP()
+       {
+               return ipaddr;
+       }
+};
+
+/** You must return a HTTPDocument to the httpd module by using the Request class.
+ * When you initialize this class you may initialize it with all components required to
+ * form a valid HTTP response, including document data, headers, and a response code.
+ */
+class HTTPDocument : public classbase
+{
+ protected:
+
+       std::stringstream* document;
+       int responsecode;
+       std::string extraheaders;
+
+ public:
+
+       /** The socket pointer from an earlier HTTPRequest
+        */
+       void* sock;
+
+       /** Initialize a HTTPRequest ready for sending to m_httpd.so.
+        * @param opaque The socket pointer you obtained from the HTTPRequest at an earlier time
+        * @param doc A stringstream containing the document body
+        * @param response A valid HTTP/1.0 or HTTP/1.1 response code. The response text will be determined for you
+        * based upon the response code.
+        * @param extra Any extra headers to include with the defaults, seperated by carriage return and linefeed.
+        */
+       HTTPDocument(void* opaque, std::stringstream* doc, int response, const std::string &extra) : document(doc), responsecode(response), extraheaders(extra), sock(opaque)
+       {
+       }
+
+       /** Get the document text.
+        * @return The document text
+        */
+       std::stringstream* GetDocument()
+       {
+               return this->document;
+       }
+
+       /** Get the document size.
+        * @return the size of the document text in bytes
+        */
+       unsigned long GetDocumentSize()
+       {
+               return this->document->str().length();
+       }
+
+       /** Get the response code.
+        * @return The response code
+        */
+       int GetResponseCode()
+       {
+               return this->responsecode;
+       }
+
+       /** Get the headers.
+        * @return The header text, headers seperated by carriage return and linefeed.
+        */
+       std::string& GetExtraHeaders()
+       {
+               return this->extraheaders;
+       }
+};
+
+#endif
+
index 039aeed92c5a0fb3a6979ff727c9e064c4476904..94c64b4055868754377e406f6f7ba9d19f9aa173 100644 (file)
@@ -1 +1,272 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r#include "wildcard.h"\r\r/* $ModDesc: Provides aliases of commands. */\r\r/** An alias definition\r */\rclass Alias : public classbase\r{\r public:\r   /** The text of the alias command */\r   irc::string text;\r      /** Text to replace with */\r    std::string replace_with;\r      /** Nickname required to perform alias */\r      std::string requires;\r  /** Alias requires ulined server */\r    bool uline;\r    /** Requires oper? */\r  bool operonly;\r /* is case sensitive params */\r bool case_sensitive;\r   /** Format that must be matched for use */\r     std::string format;\r};\r\rclass ModuleAlias : public Module\r{\r private:\r  /** We cant use a map, there may be multiple aliases with the same name */\r     std::vector<Alias> Aliases;\r    std::map<std::string, int> AliasMap;\r   std::vector<std::string> pars;\r\r        virtual void ReadAliases()\r     {\r              ConfigReader MyConf(ServerInstance);\r\r          Aliases.clear();\r               AliasMap.clear();\r              for (int i = 0; i < MyConf.Enumerate("alias"); i++)\r            {\r                      Alias a;\r                       std::string txt;\r                       txt = MyConf.ReadValue("alias", "text", i);\r                    a.text = txt.c_str();\r                  a.replace_with = MyConf.ReadValue("alias", "replace", i, true);\r                        a.requires = MyConf.ReadValue("alias", "requires", i);\r                 a.uline = MyConf.ReadFlag("alias", "uline", i);\r                        a.operonly = MyConf.ReadFlag("alias", "operonly", i);\r                  a.format = MyConf.ReadValue("alias", "format", i);\r                     a.case_sensitive = MyConf.ReadFlag("alias", "matchcase", i);\r                   Aliases.push_back(a);\r                  AliasMap[txt] = 1;\r             }\r      }\r\r public:\r    \r       ModuleAlias(InspIRCd* Me)\r              : Module(Me)\r   {\r              ReadAliases();\r         pars.resize(127);\r      }\r\r     void Implements(char* List)\r    {\r              List[I_OnPreCommand] = List[I_OnRehash] = 1;\r   }\r\r     virtual ~ModuleAlias()\r {\r      }\r\r     virtual Version GetVersion()\r   {\r              return Version(1,1,0,1,VF_VENDOR,API_VERSION);\r }\r\r     std::string GetVar(std::string varname, const std::string &original_line)\r      {\r              irc::spacesepstream ss(original_line);\r         varname.erase(varname.begin());\r                int index = *(varname.begin()) - 48;\r           varname.erase(varname.begin());\r                bool everything_after = (varname == "-");\r              std::string word;\r\r             for (int j = 0; j < index; j++)\r                        word = ss.GetToken();\r\r         if (everything_after)\r          {\r                      std::string more = "*";\r                        while ((more = ss.GetToken()) != "")\r                   {\r                              word.append(" ");\r                              word.append(more);\r                     }\r              }\r\r             return word;\r   }\r\r     void SearchAndReplace(std::string& newline, const std::string &find, const std::string &replace)\r       {\r              std::string::size_type x = newline.find(find);\r         while (x != std::string::npos)\r         {\r                      newline.erase(x, find.length());\r                       newline.insert(x, replace);\r                    x = newline.find(find);\r                }\r      }\r\r     virtual int OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line)\r       {\r              userrec *u = NULL;\r\r            /* If theyre not registered yet, we dont want\r           * to know.\r             */\r            if (user->registered != REG_ALL)\r                       return 0;\r\r             /* We dont have any commands looking like this, dont bother with the loop */\r           if (AliasMap.find(command) == AliasMap.end())\r                  return 0;\r\r             irc::string c = command.c_str();\r               /* The parameters for the command in their original form, with the command stripped off */\r             std::string compare = original_line.substr(command.length());\r          while (*(compare.c_str()) == ' ')\r                      compare.erase(compare.begin());\r\r               std::string safe(original_line);\r\r              /* Escape out any $ symbols in the user provided text */\r\r              SearchAndReplace(safe, "$", "\r");\r\r            for (unsigned int i = 0; i < Aliases.size(); i++)\r              {\r                      if (Aliases[i].text == c)\r                      {\r                              /* Does it match the pattern? */\r                               if (!Aliases[i].format.empty())\r                                {\r                                      if (!match(Aliases[i].case_sensitive, compare.c_str(), Aliases[i].format.c_str()))\r                                             continue;\r                              }\r\r                             if ((Aliases[i].operonly) && (!IS_OPER(user)))\r                                 return 0;\r\r                             if (!Aliases[i].requires.empty())\r                              {\r                                      u = ServerInstance->FindNick(Aliases[i].requires);\r                                     if (!u)\r                                        {\r                                              user->WriteServ("401 "+std::string(user->nick)+" "+Aliases[i].requires+" :is currently unavailable. Please try again later.");\r                                         return 1;\r                                      }\r                              }\r                              if ((u != NULL) && (!Aliases[i].requires.empty()) && (Aliases[i].uline))\r                               {\r                                      if (!ServerInstance->ULine(u->server))\r                                 {\r                                              ServerInstance->WriteOpers("*** NOTICE -- Service "+Aliases[i].requires+" required by alias "+std::string(Aliases[i].text.c_str())+" is not on a u-lined server, possibly underhanded antics detected!"); \r                                             user->WriteServ("401 "+std::string(user->nick)+" "+Aliases[i].requires+" :is an imposter! Please inform an IRC operator as soon as possible.");\r                                                return 1;\r                                      }\r                              }\r\r                             /* Now, search and replace in a copy of the original_line, replacing $1 through $9 and $1- etc */\r\r                             std::string::size_type crlf = Aliases[i].replace_with.find('\n');\r\r                             if (crlf == std::string::npos)\r                         {\r                                      DoCommand(Aliases[i].replace_with, user, safe);\r                                        return 1;\r                              }\r                              else\r                           {\r                                      irc::sepstream commands(Aliases[i].replace_with, '\n');\r                                        std::string command = "*";\r                                     while ((command = commands.GetToken()) != "")\r                                  {\r                                              DoCommand(command, user, safe);\r                                        }\r                                      return 1;\r                              }\r                      }\r              }\r              return 0;\r      }\r\r     void DoCommand(std::string newline, userrec* user, const std::string &original_line)\r   {\r              for (int v = 1; v < 10; v++)\r           {\r                      std::string var = "$";\r                 var.append(ConvToStr(v));\r                      var.append("-");\r                       std::string::size_type x = newline.find(var);\r\r                 while (x != std::string::npos)\r                 {\r                              newline.erase(x, var.length());\r                                newline.insert(x, GetVar(var, original_line));\r                         x = newline.find(var);\r                 }\r\r                     var = "$";\r                     var.append(ConvToStr(v));\r                      x = newline.find(var);\r\r                        while (x != std::string::npos)\r                 {\r                              newline.erase(x, var.length());\r                                newline.insert(x, GetVar(var, original_line));\r                         x = newline.find(var);\r                 }\r              }\r\r             /* Special variables */\r                SearchAndReplace(newline, "$nick", user->nick);\r                SearchAndReplace(newline, "$ident", user->ident);\r              SearchAndReplace(newline, "$host", user->host);\r                SearchAndReplace(newline, "$vhost", user->dhost);\r\r             /* Unescape any variable names in the user text before sending */\r              SearchAndReplace(newline, "\r", "$");\r\r         irc::tokenstream ss(newline);\r          const char* parv[127];\r         int x = 0;\r\r            while (ss.GetToken(pars[x]))\r           {\r                      parv[x] = pars[x].c_str();\r                     x++;\r           }\r\r             ServerInstance->Parser->CallHandler(parv[0], &parv[1], x-1, user);\r     }\r \r    virtual void OnRehash(userrec* user, const std::string &parameter)\r     {\r              ReadAliases();\r         }\r};\r\rMODULE_INIT(ModuleAlias)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+#include "wildcard.h"
+
+/* $ModDesc: Provides aliases of commands. */
+
+/** An alias definition
+ */
+class Alias : public classbase
+{
+ public:
+       /** The text of the alias command */
+       irc::string text;
+       /** Text to replace with */
+       std::string replace_with;
+       /** Nickname required to perform alias */
+       std::string requires;
+       /** Alias requires ulined server */
+       bool uline;
+       /** Requires oper? */
+       bool operonly;
+       /* is case sensitive params */
+       bool case_sensitive;
+       /** Format that must be matched for use */
+       std::string format;
+};
+
+class ModuleAlias : public Module
+{
+ private:
+       /** We cant use a map, there may be multiple aliases with the same name */
+       std::vector<Alias> Aliases;
+       std::map<std::string, int> AliasMap;
+       std::vector<std::string> pars;
+
+       virtual void ReadAliases()
+       {
+               ConfigReader MyConf(ServerInstance);
+
+               Aliases.clear();
+               AliasMap.clear();
+               for (int i = 0; i < MyConf.Enumerate("alias"); i++)
+               {
+                       Alias a;
+                       std::string txt;
+                       txt = MyConf.ReadValue("alias", "text", i);
+                       a.text = txt.c_str();
+                       a.replace_with = MyConf.ReadValue("alias", "replace", i, true);
+                       a.requires = MyConf.ReadValue("alias", "requires", i);
+                       a.uline = MyConf.ReadFlag("alias", "uline", i);
+                       a.operonly = MyConf.ReadFlag("alias", "operonly", i);
+                       a.format = MyConf.ReadValue("alias", "format", i);
+                       a.case_sensitive = MyConf.ReadFlag("alias", "matchcase", i);
+                       Aliases.push_back(a);
+                       AliasMap[txt] = 1;
+               }
+       }
+
+ public:
+       
+       ModuleAlias(InspIRCd* Me)
+               : Module(Me)
+       {
+               ReadAliases();
+               pars.resize(127);
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnPreCommand] = List[I_OnRehash] = 1;
+       }
+
+       virtual ~ModuleAlias()
+       {
+       }
+
+       virtual Version GetVersion()
+       {
+               return Version(1,1,0,1,VF_VENDOR,API_VERSION);
+       }
+
+       std::string GetVar(std::string varname, const std::string &original_line)
+       {
+               irc::spacesepstream ss(original_line);
+               varname.erase(varname.begin());
+               int index = *(varname.begin()) - 48;
+               varname.erase(varname.begin());
+               bool everything_after = (varname == "-");
+               std::string word;
+
+               for (int j = 0; j < index; j++)
+                       word = ss.GetToken();
+
+               if (everything_after)
+               {
+                       std::string more = "*";
+                       while ((more = ss.GetToken()) != "")
+                       {
+                               word.append(" ");
+                               word.append(more);
+                       }
+               }
+
+               return word;
+       }
+
+       void SearchAndReplace(std::string& newline, const std::string &find, const std::string &replace)
+       {
+               std::string::size_type x = newline.find(find);
+               while (x != std::string::npos)
+               {
+                       newline.erase(x, find.length());
+                       newline.insert(x, replace);
+                       x = newline.find(find);
+               }
+       }
+
+       virtual int OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line)
+       {
+               userrec *u = NULL;
+
+               /* If theyre not registered yet, we dont want
+                * to know.
+                */
+               if (user->registered != REG_ALL)
+                       return 0;
+
+               /* We dont have any commands looking like this, dont bother with the loop */
+               if (AliasMap.find(command) == AliasMap.end())
+                       return 0;
+
+               irc::string c = command.c_str();
+               /* The parameters for the command in their original form, with the command stripped off */
+               std::string compare = original_line.substr(command.length());
+               while (*(compare.c_str()) == ' ')
+                       compare.erase(compare.begin());
+
+               std::string safe(original_line);
+
+               /* Escape out any $ symbols in the user provided text */
+
+               SearchAndReplace(safe, "$", "\r");
+
+               for (unsigned int i = 0; i < Aliases.size(); i++)
+               {
+                       if (Aliases[i].text == c)
+                       {
+                               /* Does it match the pattern? */
+                               if (!Aliases[i].format.empty())
+                               {
+                                       if (!match(Aliases[i].case_sensitive, compare.c_str(), Aliases[i].format.c_str()))
+                                               continue;
+                               }
+
+                               if ((Aliases[i].operonly) && (!IS_OPER(user)))
+                                       return 0;
+
+                               if (!Aliases[i].requires.empty())
+                               {
+                                       u = ServerInstance->FindNick(Aliases[i].requires);
+                                       if (!u)
+                                       {
+                                               user->WriteServ("401 "+std::string(user->nick)+" "+Aliases[i].requires+" :is currently unavailable. Please try again later.");
+                                               return 1;
+                                       }
+                               }
+                               if ((u != NULL) && (!Aliases[i].requires.empty()) && (Aliases[i].uline))
+                               {
+                                       if (!ServerInstance->ULine(u->server))
+                                       {
+                                               ServerInstance->WriteOpers("*** NOTICE -- Service "+Aliases[i].requires+" required by alias "+std::string(Aliases[i].text.c_str())+" is not on a u-lined server, possibly underhanded antics detected!"); 
+                                               user->WriteServ("401 "+std::string(user->nick)+" "+Aliases[i].requires+" :is an imposter! Please inform an IRC operator as soon as possible.");
+                                               return 1;
+                                       }
+                               }
+
+                               /* Now, search and replace in a copy of the original_line, replacing $1 through $9 and $1- etc */
+
+                               std::string::size_type crlf = Aliases[i].replace_with.find('\n');
+
+                               if (crlf == std::string::npos)
+                               {
+                                       DoCommand(Aliases[i].replace_with, user, safe);
+                                       return 1;
+                               }
+                               else
+                               {
+                                       irc::sepstream commands(Aliases[i].replace_with, '\n');
+                                       std::string command = "*";
+                                       while ((command = commands.GetToken()) != "")
+                                       {
+                                               DoCommand(command, user, safe);
+                                       }
+                                       return 1;
+                               }
+                       }
+               }
+               return 0;
+       }
+
+       void DoCommand(std::string newline, userrec* user, const std::string &original_line)
+       {
+               for (int v = 1; v < 10; v++)
+               {
+                       std::string var = "$";
+                       var.append(ConvToStr(v));
+                       var.append("-");
+                       std::string::size_type x = newline.find(var);
+
+                       while (x != std::string::npos)
+                       {
+                               newline.erase(x, var.length());
+                               newline.insert(x, GetVar(var, original_line));
+                               x = newline.find(var);
+                       }
+
+                       var = "$";
+                       var.append(ConvToStr(v));
+                       x = newline.find(var);
+
+                       while (x != std::string::npos)
+                       {
+                               newline.erase(x, var.length());
+                               newline.insert(x, GetVar(var, original_line));
+                               x = newline.find(var);
+                       }
+               }
+
+               /* Special variables */
+               SearchAndReplace(newline, "$nick", user->nick);
+               SearchAndReplace(newline, "$ident", user->ident);
+               SearchAndReplace(newline, "$host", user->host);
+               SearchAndReplace(newline, "$vhost", user->dhost);
+
+               /* Unescape any variable names in the user text before sending */
+               SearchAndReplace(newline, "\r", "$");
+
+               irc::tokenstream ss(newline);
+               const char* parv[127];
+               int x = 0;
+
+               while (ss.GetToken(pars[x]))
+               {
+                       parv[x] = pars[x].c_str();
+                       x++;
+               }
+
+               ServerInstance->Parser->CallHandler(parv[0], &parv[1], x-1, user);
+       }
+       virtual void OnRehash(userrec* user, const std::string &parameter)
+       {
+               ReadAliases();
+       }
+};
+
+MODULE_INIT(ModuleAlias)
index 6a3f27ba80da62491800103b10be2ce7c990ec0f..97ab6a3fe38fbded253bd11978b131e11b9ef83a 100644 (file)
@@ -1 +1,83 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "modules.h"\r\r/* $ModDesc: Display timestamps from all servers connected to the network */\r\rclass cmd_alltime : public command_t\r{\r public:\r cmd_alltime(InspIRCd *Instance) : command_t(Instance, "ALLTIME", 'o', 0)\r       {\r              this->source = "m_alltime.so";\r         syntax.clear();\r        }\r\r     CmdResult Handle(const char **parameters, int pcnt, userrec *user)\r     {\r              char fmtdate[64];\r              char fmtdate2[64];\r             time_t now = ServerInstance->Time(false);\r              strftime(fmtdate, sizeof(fmtdate), "%F %T", gmtime(&now));\r             now = ServerInstance->Time(true);\r              strftime(fmtdate2, sizeof(fmtdate2), "%F %T", gmtime(&now));\r           \r               int delta = ServerInstance->GetTimeDelta();\r            \r               string msg = ":" + string(ServerInstance->Config->ServerName) + " NOTICE " + user->nick + " :System time for " +\r                       ServerInstance->Config->ServerName + " is: " + fmtdate + " (delta " + ConvToStr(delta) + " seconds): Time with delta: "+ fmtdate2;\r             \r               if (IS_LOCAL(user))\r            {\r                      user->Write(msg);\r              }\r              else\r           {\r                      deque<string> params;\r                  params.push_back(user->nick);\r                  params.push_back(msg);\r                 Event ev((char *) &params, NULL, "send_push");\r                 ev.Send(ServerInstance);\r               }\r\r             /* we want this routed out! */\r         return CMD_SUCCESS;\r    }\r};\r\r\rclass Modulealltime : public Module\r{\r   cmd_alltime *mycommand;\r public:\r       Modulealltime(InspIRCd *Me)\r            : Module(Me)\r   {\r              mycommand = new cmd_alltime(ServerInstance);\r           ServerInstance->AddCommand(mycommand);\r }\r      \r       virtual ~Modulealltime()\r       {\r      }\r      \r       virtual Version GetVersion()\r   {\r              return Version(1, 0, 0, 0, VF_COMMON | VF_VENDOR, API_VERSION);\r        }\r      \r};\r\rMODULE_INIT(Modulealltime)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "modules.h"
+
+/* $ModDesc: Display timestamps from all servers connected to the network */
+
+class cmd_alltime : public command_t
+{
+ public:
+       cmd_alltime(InspIRCd *Instance) : command_t(Instance, "ALLTIME", 'o', 0)
+       {
+               this->source = "m_alltime.so";
+               syntax.clear();
+       }
+
+       CmdResult Handle(const char **parameters, int pcnt, userrec *user)
+       {
+               char fmtdate[64];
+               char fmtdate2[64];
+               time_t now = ServerInstance->Time(false);
+               strftime(fmtdate, sizeof(fmtdate), "%F %T", gmtime(&now));
+               now = ServerInstance->Time(true);
+               strftime(fmtdate2, sizeof(fmtdate2), "%F %T", gmtime(&now));
+               
+               int delta = ServerInstance->GetTimeDelta();
+               
+               string msg = ":" + string(ServerInstance->Config->ServerName) + " NOTICE " + user->nick + " :System time for " +
+                       ServerInstance->Config->ServerName + " is: " + fmtdate + " (delta " + ConvToStr(delta) + " seconds): Time with delta: "+ fmtdate2;
+               
+               if (IS_LOCAL(user))
+               {
+                       user->Write(msg);
+               }
+               else
+               {
+                       deque<string> params;
+                       params.push_back(user->nick);
+                       params.push_back(msg);
+                       Event ev((char *) &params, NULL, "send_push");
+                       ev.Send(ServerInstance);
+               }
+
+               /* we want this routed out! */
+               return CMD_SUCCESS;
+       }
+};
+
+
+class Modulealltime : public Module
+{
+       cmd_alltime *mycommand;
+ public:
+       Modulealltime(InspIRCd *Me)
+               : Module(Me)
+       {
+               mycommand = new cmd_alltime(ServerInstance);
+               ServerInstance->AddCommand(mycommand);
+       }
+       
+       virtual ~Modulealltime()
+       {
+       }
+       
+       virtual Version GetVersion()
+       {
+               return Version(1, 0, 0, 0, VF_COMMON | VF_VENDOR, API_VERSION);
+       }
+       
+};
+
+MODULE_INIT(Modulealltime)
index d95c7028209908f249dc8d446acee57bb7482355..2718cbb4ce6b4db2a005259697aab864492830b4 100644 (file)
@@ -1 +1,78 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r#include "xline.h"\r\r/* $ModDesc: Sends a numeric on connect which cripples a common type of trojan/spambot */\r\rclass ModuleAntiBear : public Module\r{\r private:\r\r public:\r     ModuleAntiBear(InspIRCd* Me) : Module(Me)\r      {\r              \r       }\r      \r       virtual ~ModuleAntiBear()\r      {\r      }\r      \r       virtual Version GetVersion()\r   {\r              return Version(1,1,0,0,VF_VENDOR,API_VERSION);\r }\r\r     void Implements(char* List)\r    {\r              List[I_OnUserRegister] = List[I_OnPreCommand] = 1;\r     }\r\r     virtual int OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line)\r       {\r              if (command == "NOTICE" && !validated && pcnt > 1 && user->GetExt("antibear_timewait"))\r                {\r                      if (!strncmp(parameters[1], "\1TIME Mon May 01 18:54:20 2006", 30))\r                    {\r                              if (ServerInstance->XLines->add_zline(86400, ServerInstance->Config->ServerName, "Unless you're stuck in a time warp, you appear to be a bear bot!", user->MakeHostIP()))\r                              {\r                                      ServerInstance->XLines->apply_lines(APPLY_ZLINES);\r                                     FOREACH_MOD(I_OnAddGLine,OnAddZLine(86400, NULL, "Unless you're stuck in a time warp, you appear to be a bear bot!", user->MakeHostIP()));\r                                     return 1;\r                              }\r                      }\r                      \r                       user->Shrink("antibear_timewait");\r                     // Block the command, so the user doesn't receive a no such nick notice\r                        return 1;\r              }\r              \r               return 0;\r      }\r\r     virtual int OnUserRegister(userrec* user)\r      {\r              user->WriteServ("439 %s :This server has anti-spambot mechanisms enabled.", user->nick);\r               user->WriteServ("931 %s :Malicious bots, spammers, and other automated systems of dubious origin are NOT welcome here.", user->nick);\r          user->WriteServ("PRIVMSG %s :\1TIME\1", user->nick);\r           user->Extend("antibear_timewait");\r             return 0;\r      }\r};\r\rMODULE_INIT(ModuleAntiBear)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+#include "xline.h"
+
+/* $ModDesc: Sends a numeric on connect which cripples a common type of trojan/spambot */
+
+class ModuleAntiBear : public Module
+{
+ private:
+
+ public:
+       ModuleAntiBear(InspIRCd* Me) : Module(Me)
+       {
+               
+       }
+       
+       virtual ~ModuleAntiBear()
+       {
+       }
+       
+       virtual Version GetVersion()
+       {
+               return Version(1,1,0,0,VF_VENDOR,API_VERSION);
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnUserRegister] = List[I_OnPreCommand] = 1;
+       }
+
+       virtual int OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line)
+       {
+               if (command == "NOTICE" && !validated && pcnt > 1 && user->GetExt("antibear_timewait"))
+               {
+                       if (!strncmp(parameters[1], "\1TIME Mon May 01 18:54:20 2006", 30))
+                       {
+                               if (ServerInstance->XLines->add_zline(86400, ServerInstance->Config->ServerName, "Unless you're stuck in a time warp, you appear to be a bear bot!", user->MakeHostIP()))
+                               {
+                                       ServerInstance->XLines->apply_lines(APPLY_ZLINES);
+                                       FOREACH_MOD(I_OnAddGLine,OnAddZLine(86400, NULL, "Unless you're stuck in a time warp, you appear to be a bear bot!", user->MakeHostIP()));
+                                       return 1;
+                               }
+                       }
+                       
+                       user->Shrink("antibear_timewait");
+                       // Block the command, so the user doesn't receive a no such nick notice
+                       return 1;
+               }
+               
+               return 0;
+       }
+
+       virtual int OnUserRegister(userrec* user)
+       {
+               user->WriteServ("439 %s :This server has anti-spambot mechanisms enabled.", user->nick);
+               user->WriteServ("931 %s :Malicious bots, spammers, and other automated systems of dubious origin are NOT welcome here.", user->nick);
+               user->WriteServ("PRIVMSG %s :\1TIME\1", user->nick);
+               user->Extend("antibear_timewait");
+               return 0;
+       }
+};
+
+MODULE_INIT(ModuleAntiBear)
index 907cfb39da3d956fec6a008788bc6d78de4bd68d..3aa5592ccd985d69e4c0fabe43926c8bf600cddd 100644 (file)
@@ -1 +1,99 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r\r/* $ModDesc: Changes the ident of connecting bottler clients to 'bottler' */\r\rclass ModuleAntiBottler : public Module\r{\r public:\r     ModuleAntiBottler(InspIRCd* Me)\r                : Module(Me)\r   {\r              \r       }\r\r     void Implements(char* List)\r    {\r              List[I_OnPreCommand] = 1;\r      }\r\r     \r       virtual ~ModuleAntiBottler()\r   {\r      }\r      \r       virtual Version GetVersion()\r   {\r              return Version(1,1,0,1,VF_VENDOR,API_VERSION);\r }\r\r     virtual int OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line)\r       {\r              char data[MAXBUF];\r             strlcpy(data,original_line.c_str(),MAXBUF);\r            bool not_bottler = false;\r              if (!strncmp(data,"user ",5))\r          {\r                      for (char* j = data; *j; j++)\r                  {\r                              if (*j == ':')\r                                 break;\r                                 \r                               if (*j == '"')\r                         {\r                                      not_bottler = true;\r                            }\r                      }\r                      // Bug Fix (#14) -- FCS\r                        if (!(data) || !(*data))\r                               return 0;\r\r                     strtok(data," ");\r                      char *ident = strtok(NULL," ");\r                        char *local = strtok(NULL," ");\r                        char *remote = strtok(NULL," :");\r                      char *gecos = strtok(NULL,"\r\n");\r\r                    if (!ident || !local || !remote || !gecos)\r                             return 0;\r\r                     for (char* j = remote; *j; j++)\r                        {\r                              if (((*j < '0') || (*j > '9')) && (*j != '.'))\r                         {\r                                      not_bottler = true;\r                            }\r                      }\r\r                     if (!not_bottler)\r                      {\r                              std::string strgecos = std::string(gecos) + "[Possible bottler, ident: " + std::string(ident) + "]";\r                           const char* modified[4];\r                               modified[0] = "bottler";\r                               modified[1] = local;\r                           modified[2] = remote;\r                          modified[3] = strgecos.c_str();\r                                ServerInstance->Parser->CallHandler("USER", modified, 4, user);\r                                return 1;\r                      }\r              }\r              return 0;\r      }\r};\r\rMODULE_INIT(ModuleAntiBottler)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+
+/* $ModDesc: Changes the ident of connecting bottler clients to 'bottler' */
+
+class ModuleAntiBottler : public Module
+{
+ public:
+       ModuleAntiBottler(InspIRCd* Me)
+               : Module(Me)
+       {
+               
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnPreCommand] = 1;
+       }
+
+       
+       virtual ~ModuleAntiBottler()
+       {
+       }
+       
+       virtual Version GetVersion()
+       {
+               return Version(1,1,0,1,VF_VENDOR,API_VERSION);
+       }
+
+       virtual int OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line)
+       {
+               char data[MAXBUF];
+               strlcpy(data,original_line.c_str(),MAXBUF);
+               bool not_bottler = false;
+               if (!strncmp(data,"user ",5))
+               {
+                       for (char* j = data; *j; j++)
+                       {
+                               if (*j == ':')
+                                       break;
+                                       
+                               if (*j == '"')
+                               {
+                                       not_bottler = true;
+                               }
+                       }
+                       // Bug Fix (#14) -- FCS
+                       if (!(data) || !(*data))
+                               return 0;
+
+                       strtok(data," ");
+                       char *ident = strtok(NULL," ");
+                       char *local = strtok(NULL," ");
+                       char *remote = strtok(NULL," :");
+                       char *gecos = strtok(NULL,"\r\n");
+
+                       if (!ident || !local || !remote || !gecos)
+                               return 0;
+
+                       for (char* j = remote; *j; j++)
+                       {
+                               if (((*j < '0') || (*j > '9')) && (*j != '.'))
+                               {
+                                       not_bottler = true;
+                               }
+                       }
+
+                       if (!not_bottler)
+                       {
+                               std::string strgecos = std::string(gecos) + "[Possible bottler, ident: " + std::string(ident) + "]";
+                               const char* modified[4];
+                               modified[0] = "bottler";
+                               modified[1] = local;
+                               modified[2] = remote;
+                               modified[3] = strgecos.c_str();
+                               ServerInstance->Parser->CallHandler("USER", modified, 4, user);
+                               return 1;
+                       }
+               }
+               return 0;
+       }
+};
+
+MODULE_INIT(ModuleAntiBottler)
index 419738ea74cc8b2ec3cd058bc021e7328f81833f..6d709e431f90710882f9cc8a6b7a7b9bae884b59 100644 (file)
@@ -1 +1,191 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r\r/* $ModDesc: Allows for auditorium channels (+u) where nobody can see others joining and parting or the nick list */\r\rclass AuditoriumMode : public ModeHandler\r{\r public:\r   AuditoriumMode(InspIRCd* Instance) : ModeHandler(Instance, 'u', 0, 0, false, MODETYPE_CHANNEL, false) { }\r\r     ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)\r {\r              if (channel->IsModeSet('u') != adding)\r         {\r                      if (IS_LOCAL(source) && (channel->GetStatus(source) < STATUS_OP))\r                      {\r                              source->WriteServ("482 %s %s :Only channel operators may %sset channel mode +u", source->nick, channel->name, adding ? "" : "un");\r                             return MODEACTION_DENY;\r                        }\r                      else\r                   {\r                              channel->SetMode('u', adding);\r                         return MODEACTION_ALLOW;\r                       }\r              }\r              else\r           {\r                      return MODEACTION_DENY;\r                }\r      }\r};\r\rclass ModuleAuditorium : public Module\r{\r private:\r       AuditoriumMode* aum;\r   bool ShowOps;\r  CUList nl;\r     CUList except_list;\r public:\r   ModuleAuditorium(InspIRCd* Me)\r         : Module(Me)\r   {\r              aum = new AuditoriumMode(ServerInstance);\r              if (!ServerInstance->AddMode(aum, 'u'))\r                        throw ModuleException("Could not add new modes!");\r             OnRehash(NULL, "");\r    }\r      \r       virtual ~ModuleAuditorium()\r    {\r              ServerInstance->Modes->DelMode(aum);\r           DELETE(aum);\r   }\r\r     virtual void OnRehash(userrec* user, const std::string &parameter)\r     {\r              ConfigReader conf(ServerInstance);\r             ShowOps = conf.ReadFlag("auditorium", "showops", 0);\r   }\r\r     Priority Prioritize()\r  {\r              /* To ensure that we get priority over namesx for names list generation on +u channels */\r              return (Priority)ServerInstance->PriorityBefore("m_namesx.so");\r        }\r\r     virtual Version GetVersion()\r   {\r              return Version(1, 1, 0, 0, VF_COMMON | VF_VENDOR, API_VERSION);\r        }\r\r     void Implements(char* List)\r    {\r              List[I_OnUserJoin] = List[I_OnUserPart] = List[I_OnUserKick] = List[I_OnUserQuit] = List[I_OnUserList] = List[I_OnRehash] = 1;\r }\r\r     virtual int OnUserList(userrec* user, chanrec* Ptr, CUList* &nameslist)\r        {\r              if (Ptr->IsModeSet('u'))\r               {\r                      if (ShowOps)\r                   {\r                              /* Leave the names list alone, theyre an op\r                             * doing /names on the channel after joining it\r                                 */\r                            if (Ptr->GetStatus(user) >= STATUS_OP)\r                         {\r                                      nameslist = Ptr->GetUsers();\r                                   return 0;\r                              }\r\r                             /* Show all the opped users */\r                         nl = *(Ptr->GetOppedUsers());\r                          nl[user] = user->nick;\r                         nameslist = &nl;\r                               return 0;\r                      }\r                      else\r                   {\r                              /* HELLOOO, IS ANYBODY THERE? -- nope, just us. */\r                             user->WriteServ("353 %s = %s :%s", user->nick, Ptr->name, user->nick);\r                         user->WriteServ("366 %s %s :End of /NAMES list.", user->nick, Ptr->name);\r                              return 1;\r                      }\r              }\r              return 0;\r      }\r      \r       virtual void OnUserJoin(userrec* user, chanrec* channel, bool &silent)\r {\r              if (channel->IsModeSet('u'))\r           {\r                      silent = true;\r                 /* Because we silenced the event, make sure it reaches the user whos joining (but only them of course) */\r                      user->WriteFrom(user, "JOIN %s", channel->name);\r                       if (ShowOps)\r                           channel->WriteAllExcept(user, false, channel->GetStatus(user) >= STATUS_OP ? 0 : '@', except_list, "JOIN %s", channel->name);\r          }\r      }\r\r     void OnUserPart(userrec* user, chanrec* channel, const std::string &partmessage, bool &silent)\r {\r              if (channel->IsModeSet('u'))\r           {\r                      silent = true;\r                 /* Because we silenced the event, make sure it reaches the user whos leaving (but only them of course) */\r                      user->WriteFrom(user, "PART %s%s%s", channel->name,\r                                    partmessage.empty() ? "" : " :",\r                                       partmessage.empty() ? "" : partmessage.c_str());\r                       if (ShowOps)\r                   {\r                              channel->WriteAllExcept(user, false, channel->GetStatus(user) >= STATUS_OP ? 0 : '@', except_list, "PART %s%s%s", channel->name, partmessage.empty() ? "" : " :",\r                                              partmessage.empty() ? "" : partmessage.c_str());\r                       }\r              }\r      }\r\r     void OnUserKick(userrec* source, userrec* user, chanrec* chan, const std::string &reason, bool &silent)\r        {\r              if (chan->IsModeSet('u'))\r              {\r                      silent = true;\r                 /* Send silenced event only to the user being kicked and the user doing the kick */\r                    source->WriteFrom(source, "KICK %s %s %s", chan->name, user->nick, reason.c_str());\r                    if (ShowOps)\r                           chan->WriteAllExcept(source, false, chan->GetStatus(source) >= STATUS_OP ? 0 : '@', except_list, "KICK %s %s %s", chan->name, user->nick, reason.c_str());\r                     else\r                           user->WriteFrom(source, "KICK %s %s %s", chan->name, user->nick, reason.c_str());\r              }\r      }\r\r     void OnUserQuit(userrec* user, const std::string &reason, const std::string &oper_message)\r     {\r              command_t* parthandler = ServerInstance->Parser->GetHandler("PART");\r           std::vector<std::string> to_leave;\r             const char* parameters[2];\r             if (parthandler)\r               {\r                      for (UCListIter f = user->chans.begin(); f != user->chans.end(); f++)\r                  {\r                              if (f->first->IsModeSet('u'))\r                                  to_leave.push_back(f->first->name);\r                    }\r                      /* We cant do this neatly in one loop, as we are modifying the map we are iterating */\r                 for (std::vector<std::string>::iterator n = to_leave.begin(); n != to_leave.end(); n++)\r                        {\r                              parameters[0] = n->c_str();\r                            /* This triggers our OnUserPart, above, making the PART silent */\r                              parthandler->Handle(parameters, 1, user);\r                      }\r              }\r      }\r};\r\rMODULE_INIT(ModuleAuditorium)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+
+/* $ModDesc: Allows for auditorium channels (+u) where nobody can see others joining and parting or the nick list */
+
+class AuditoriumMode : public ModeHandler
+{
+ public:
+       AuditoriumMode(InspIRCd* Instance) : ModeHandler(Instance, 'u', 0, 0, false, MODETYPE_CHANNEL, false) { }
+
+       ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)
+       {
+               if (channel->IsModeSet('u') != adding)
+               {
+                       if (IS_LOCAL(source) && (channel->GetStatus(source) < STATUS_OP))
+                       {
+                               source->WriteServ("482 %s %s :Only channel operators may %sset channel mode +u", source->nick, channel->name, adding ? "" : "un");
+                               return MODEACTION_DENY;
+                       }
+                       else
+                       {
+                               channel->SetMode('u', adding);
+                               return MODEACTION_ALLOW;
+                       }
+               }
+               else
+               {
+                       return MODEACTION_DENY;
+               }
+       }
+};
+
+class ModuleAuditorium : public Module
+{
+ private:
+       AuditoriumMode* aum;
+       bool ShowOps;
+       CUList nl;
+       CUList except_list;
+ public:
+       ModuleAuditorium(InspIRCd* Me)
+               : Module(Me)
+       {
+               aum = new AuditoriumMode(ServerInstance);
+               if (!ServerInstance->AddMode(aum, 'u'))
+                       throw ModuleException("Could not add new modes!");
+               OnRehash(NULL, "");
+       }
+       
+       virtual ~ModuleAuditorium()
+       {
+               ServerInstance->Modes->DelMode(aum);
+               DELETE(aum);
+       }
+
+       virtual void OnRehash(userrec* user, const std::string &parameter)
+       {
+               ConfigReader conf(ServerInstance);
+               ShowOps = conf.ReadFlag("auditorium", "showops", 0);
+       }
+
+       Priority Prioritize()
+       {
+               /* To ensure that we get priority over namesx for names list generation on +u channels */
+               return (Priority)ServerInstance->PriorityBefore("m_namesx.so");
+       }
+
+       virtual Version GetVersion()
+       {
+               return Version(1, 1, 0, 0, VF_COMMON | VF_VENDOR, API_VERSION);
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnUserJoin] = List[I_OnUserPart] = List[I_OnUserKick] = List[I_OnUserQuit] = List[I_OnUserList] = List[I_OnRehash] = 1;
+       }
+
+       virtual int OnUserList(userrec* user, chanrec* Ptr, CUList* &nameslist)
+       {
+               if (Ptr->IsModeSet('u'))
+               {
+                       if (ShowOps)
+                       {
+                               /* Leave the names list alone, theyre an op
+                                * doing /names on the channel after joining it
+                                */
+                               if (Ptr->GetStatus(user) >= STATUS_OP)
+                               {
+                                       nameslist = Ptr->GetUsers();
+                                       return 0;
+                               }
+
+                               /* Show all the opped users */
+                               nl = *(Ptr->GetOppedUsers());
+                               nl[user] = user->nick;
+                               nameslist = &nl;
+                               return 0;
+                       }
+                       else
+                       {
+                               /* HELLOOO, IS ANYBODY THERE? -- nope, just us. */
+                               user->WriteServ("353 %s = %s :%s", user->nick, Ptr->name, user->nick);
+                               user->WriteServ("366 %s %s :End of /NAMES list.", user->nick, Ptr->name);
+                               return 1;
+                       }
+               }
+               return 0;
+       }
+       
+       virtual void OnUserJoin(userrec* user, chanrec* channel, bool &silent)
+       {
+               if (channel->IsModeSet('u'))
+               {
+                       silent = true;
+                       /* Because we silenced the event, make sure it reaches the user whos joining (but only them of course) */
+                       user->WriteFrom(user, "JOIN %s", channel->name);
+                       if (ShowOps)
+                               channel->WriteAllExcept(user, false, channel->GetStatus(user) >= STATUS_OP ? 0 : '@', except_list, "JOIN %s", channel->name);
+               }
+       }
+
+       void OnUserPart(userrec* user, chanrec* channel, const std::string &partmessage, bool &silent)
+       {
+               if (channel->IsModeSet('u'))
+               {
+                       silent = true;
+                       /* Because we silenced the event, make sure it reaches the user whos leaving (but only them of course) */
+                       user->WriteFrom(user, "PART %s%s%s", channel->name,
+                                       partmessage.empty() ? "" : " :",
+                                       partmessage.empty() ? "" : partmessage.c_str());
+                       if (ShowOps)
+                       {
+                               channel->WriteAllExcept(user, false, channel->GetStatus(user) >= STATUS_OP ? 0 : '@', except_list, "PART %s%s%s", channel->name, partmessage.empty() ? "" : " :",
+                                               partmessage.empty() ? "" : partmessage.c_str());
+                       }
+               }
+       }
+
+       void OnUserKick(userrec* source, userrec* user, chanrec* chan, const std::string &reason, bool &silent)
+       {
+               if (chan->IsModeSet('u'))
+               {
+                       silent = true;
+                       /* Send silenced event only to the user being kicked and the user doing the kick */
+                       source->WriteFrom(source, "KICK %s %s %s", chan->name, user->nick, reason.c_str());
+                       if (ShowOps)
+                               chan->WriteAllExcept(source, false, chan->GetStatus(source) >= STATUS_OP ? 0 : '@', except_list, "KICK %s %s %s", chan->name, user->nick, reason.c_str());
+                       else
+                               user->WriteFrom(source, "KICK %s %s %s", chan->name, user->nick, reason.c_str());
+               }
+       }
+
+       void OnUserQuit(userrec* user, const std::string &reason, const std::string &oper_message)
+       {
+               command_t* parthandler = ServerInstance->Parser->GetHandler("PART");
+               std::vector<std::string> to_leave;
+               const char* parameters[2];
+               if (parthandler)
+               {
+                       for (UCListIter f = user->chans.begin(); f != user->chans.end(); f++)
+                       {
+                               if (f->first->IsModeSet('u'))
+                                       to_leave.push_back(f->first->name);
+                       }
+                       /* We cant do this neatly in one loop, as we are modifying the map we are iterating */
+                       for (std::vector<std::string>::iterator n = to_leave.begin(); n != to_leave.end(); n++)
+                       {
+                               parameters[0] = n->c_str();
+                               /* This triggers our OnUserPart, above, making the PART silent */
+                               parthandler->Handle(parameters, 1, user);
+                       }
+               }
+       }
+};
+
+MODULE_INIT(ModuleAuditorium)
index 8a73e607072400b4a6680246e03afcc51ca99a02..0cd03a08b801c832321227b5e8c380b9c621cd22 100644 (file)
@@ -1 +1,153 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r#include "mode.h"\r#include "u_listmode.h"\r#include "wildcard.h"\r\r/* $ModDesc: Provides support for the +e channel mode */\r/* $ModDep: ../../include/u_listmode.h */\r\r/* Written by Om<om@inspircd.org>, April 2005. */\r/* Rewritten to use the listmode utility by Om, December 2005 */\r/* Adapted from m_exception, which was originally based on m_chanprotect and m_silence */\r\r// The +e channel mode takes a nick!ident@host, glob patterns allowed,\r// and if a user matches an entry on the +e list then they can join the channel, overriding any (+b) bans set on them\r// Now supports CIDR and IP addresses -- Brain\r\r\r/** Handles +e channel mode\r */\rclass BanException : public ListModeBase\r{\r public:\r  BanException(InspIRCd* Instance) : ListModeBase(Instance, 'e', "End of Channel Exception List", "348", "349", true) { }\r};\r\r\rclass ModuleBanException : public Module\r{\r        BanException* be;\r      \r\rpublic:\r      ModuleBanException(InspIRCd* Me)\r       : Module(Me)\r   {\r              be = new BanException(ServerInstance);\r         if (!ServerInstance->AddMode(be, 'e'))\r                 throw ModuleException("Could not add new modes!");\r             ServerInstance->PublishInterface("ChannelBanList", this);\r      }\r      \r       virtual void Implements(char* List)\r    {\r              be->DoImplements(List);\r                List[I_OnRehash] = List[I_OnRequest] = List[I_On005Numeric] = List[I_OnCheckBan] = 1;\r  }\r      \r       virtual void On005Numeric(std::string &output)\r {\r              output.append(" EXCEPTS=e");\r   }\r\r     virtual int OnCheckBan(userrec* user, chanrec* chan)\r   {\r              if (chan != NULL)\r              {\r                      modelist* list;\r                        chan->GetExt(be->GetInfoKey(), list);\r                  \r                       if (list)\r                      {\r                              char mask[MAXBUF];\r                             snprintf(mask, MAXBUF, "%s!%s@%s", user->nick, user->ident, user->GetIPString());\r                              for (modelist::iterator it = list->begin(); it != list->end(); it++)\r                           {\r                                      if (match(user->GetFullRealHost(), it->mask.c_str()) || match(user->GetFullHost(), it->mask.c_str()) || (match(mask, it->mask.c_str(), true)))\r                                 {\r                                              // They match an entry on the list, so let them in.\r                                            return 1;\r                                      }\r                              }\r                              return 0;\r                      }\r                      // or if there wasn't a list, there can't be anyone on it, so we don't need to do anything.\r            }\r              return 0;       \r       }\r\r     virtual void OnCleanup(int target_type, void* item)\r    {\r              be->DoCleanup(target_type, item);\r      }\r\r     virtual void OnSyncChannel(chanrec* chan, Module* proto, void* opaque)\r {\r              be->DoSyncChannel(chan, proto, opaque);\r        }\r\r     virtual void OnChannelDelete(chanrec* chan)\r    {\r              be->DoChannelDelete(chan);\r     }\r\r     virtual void OnRehash(userrec* user, const std::string &param)\r {\r              be->DoRehash();\r        }\r\r     virtual char* OnRequest(Request* request)\r      {\r              ListModeRequest* LM = (ListModeRequest*)request;\r               if (strcmp("LM_CHECKLIST", request->GetId()) == 0)\r             {\r                      modelist* list;\r                        LM->chan->GetExt(be->GetInfoKey(), list);\r                      if (list)\r                      {\r                              char mask[MAXBUF];\r                             snprintf(mask, MAXBUF, "%s!%s@%s", LM->user->nick, LM->user->ident, LM->user->GetIPString());\r                          for (modelist::iterator it = list->begin(); it != list->end(); it++)\r                           {\r                                      if (match(LM->user->GetFullRealHost(), it->mask.c_str()) || match(LM->user->GetFullHost(), it->mask.c_str()) || (match(mask, it->mask.c_str(), true)))\r                                 {\r                                              // They match an entry\r                                         return (char*)it->mask.c_str();\r                                        }\r                              }\r                              return NULL;\r                   }\r              }\r              return NULL;\r   }\r\r     virtual Version GetVersion()\r   {\r              return Version(1, 1, 0, 3, VF_COMMON | VF_VENDOR, API_VERSION);\r        }\r      \r       virtual ~ModuleBanException()\r  {\r              ServerInstance->Modes->DelMode(be);\r            DELETE(be);\r            ServerInstance->UnpublishInterface("ChannelBanList", this);\r    }\r};\r\rMODULE_INIT(ModuleBanException)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+#include "mode.h"
+#include "u_listmode.h"
+#include "wildcard.h"
+
+/* $ModDesc: Provides support for the +e channel mode */
+/* $ModDep: ../../include/u_listmode.h */
+
+/* Written by Om<om@inspircd.org>, April 2005. */
+/* Rewritten to use the listmode utility by Om, December 2005 */
+/* Adapted from m_exception, which was originally based on m_chanprotect and m_silence */
+
+// The +e channel mode takes a nick!ident@host, glob patterns allowed,
+// and if a user matches an entry on the +e list then they can join the channel, overriding any (+b) bans set on them
+// Now supports CIDR and IP addresses -- Brain
+
+
+/** Handles +e channel mode
+ */
+class BanException : public ListModeBase
+{
+ public:
+       BanException(InspIRCd* Instance) : ListModeBase(Instance, 'e', "End of Channel Exception List", "348", "349", true) { }
+};
+
+
+class ModuleBanException : public Module
+{
+       BanException* be;
+       
+
+public:
+       ModuleBanException(InspIRCd* Me)
+       : Module(Me)
+       {
+               be = new BanException(ServerInstance);
+               if (!ServerInstance->AddMode(be, 'e'))
+                       throw ModuleException("Could not add new modes!");
+               ServerInstance->PublishInterface("ChannelBanList", this);
+       }
+       
+       virtual void Implements(char* List)
+       {
+               be->DoImplements(List);
+               List[I_OnRehash] = List[I_OnRequest] = List[I_On005Numeric] = List[I_OnCheckBan] = 1;
+       }
+       
+       virtual void On005Numeric(std::string &output)
+       {
+               output.append(" EXCEPTS=e");
+       }
+
+       virtual int OnCheckBan(userrec* user, chanrec* chan)
+       {
+               if (chan != NULL)
+               {
+                       modelist* list;
+                       chan->GetExt(be->GetInfoKey(), list);
+                       
+                       if (list)
+                       {
+                               char mask[MAXBUF];
+                               snprintf(mask, MAXBUF, "%s!%s@%s", user->nick, user->ident, user->GetIPString());
+                               for (modelist::iterator it = list->begin(); it != list->end(); it++)
+                               {
+                                       if (match(user->GetFullRealHost(), it->mask.c_str()) || match(user->GetFullHost(), it->mask.c_str()) || (match(mask, it->mask.c_str(), true)))
+                                       {
+                                               // They match an entry on the list, so let them in.
+                                               return 1;
+                                       }
+                               }
+                               return 0;
+                       }
+                       // or if there wasn't a list, there can't be anyone on it, so we don't need to do anything.
+               }
+               return 0;       
+       }
+
+       virtual void OnCleanup(int target_type, void* item)
+       {
+               be->DoCleanup(target_type, item);
+       }
+
+       virtual void OnSyncChannel(chanrec* chan, Module* proto, void* opaque)
+       {
+               be->DoSyncChannel(chan, proto, opaque);
+       }
+
+       virtual void OnChannelDelete(chanrec* chan)
+       {
+               be->DoChannelDelete(chan);
+       }
+
+       virtual void OnRehash(userrec* user, const std::string &param)
+       {
+               be->DoRehash();
+       }
+
+       virtual char* OnRequest(Request* request)
+       {
+               ListModeRequest* LM = (ListModeRequest*)request;
+               if (strcmp("LM_CHECKLIST", request->GetId()) == 0)
+               {
+                       modelist* list;
+                       LM->chan->GetExt(be->GetInfoKey(), list);
+                       if (list)
+                       {
+                               char mask[MAXBUF];
+                               snprintf(mask, MAXBUF, "%s!%s@%s", LM->user->nick, LM->user->ident, LM->user->GetIPString());
+                               for (modelist::iterator it = list->begin(); it != list->end(); it++)
+                               {
+                                       if (match(LM->user->GetFullRealHost(), it->mask.c_str()) || match(LM->user->GetFullHost(), it->mask.c_str()) || (match(mask, it->mask.c_str(), true)))
+                                       {
+                                               // They match an entry
+                                               return (char*)it->mask.c_str();
+                                       }
+                               }
+                               return NULL;
+                       }
+               }
+               return NULL;
+       }
+
+       virtual Version GetVersion()
+       {
+               return Version(1, 1, 0, 3, VF_COMMON | VF_VENDOR, API_VERSION);
+       }
+       
+       virtual ~ModuleBanException()
+       {
+               ServerInstance->Modes->DelMode(be);
+               DELETE(be);
+               ServerInstance->UnpublishInterface("ChannelBanList", this);
+       }
+};
+
+MODULE_INIT(ModuleBanException)
index 2a0ed2ded6756e2184dcfc3cdc5a8bcfcfbbf2dd..1764e6f56689b7f4dfb74af3804c6a2a9aa24aa1 100644 (file)
@@ -1 +1,343 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "mode.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r#include "u_listmode.h"\r\r/* $ModDesc: Allows an extended ban (+b) syntax redirecting banned users to another channel */\r\r/* Originally written by Om, January 2007\r */\r\rclass BanRedirectEntry\r{\r public:\r   std::string targetchan;\r        std::string banmask;\r\r  BanRedirectEntry(const std::string &target = "", const std::string &mask = "")\r : targetchan(target), banmask(mask)\r    {\r      }\r};\r\rtypedef std::vector<BanRedirectEntry> BanRedirectList;\rtypedef std::deque<std::string> StringDeque;\r\rclass BanRedirect : public ModeWatcher\r{\r private:\r  InspIRCd* Srv;\r public:\r        BanRedirect(InspIRCd* Instance)\r        : ModeWatcher(Instance, 'b', MODETYPE_CHANNEL), Srv(Instance)\r  {\r      }\r\r     bool BeforeMode(userrec* source, userrec* dest, chanrec* channel, std::string &param, bool adding, ModeType type)\r      {\r              /* nick!ident@host -> nick!ident@host\r           * nick!ident@host#chan -> nick!ident@host#chan\r                 * nick@host#chan -> nick!*@host#chan\r           * nick!ident#chan -> nick!ident@*#chan\r                 * nick#chan -> nick!*@*#chan\r           */\r            \r               if(channel && (type == MODETYPE_CHANNEL) && param.length())\r            {\r                      BanRedirectList* redirects;\r                    \r                       std::string mask[4];\r                   enum { NICK, IDENT, HOST, CHAN } current = NICK;\r                       std::string::iterator start_pos = param.begin();\r                       long maxbans = channel->GetMaxBans();\r          \r                       if(channel->bans.size() > static_cast<unsigned>(maxbans))\r                      {\r                              source->WriteServ("478 %s %s :Channel ban list for %s is full (maximum entries for this channel is %d)", source->nick, channel->name, channel->name, maxbans);\r                         return false;\r                  }\r                      \r                       for(std::string::iterator curr = start_pos; curr != param.end(); curr++)\r                       {\r                              switch(*curr)\r                          {\r                                      case '!':\r                                              mask[current].assign(start_pos, curr);\r                                         current = IDENT;\r                                               start_pos = curr+1;\r                                            break;\r                                 case '@':\r                                              mask[current].assign(start_pos, curr);\r                                         current = HOST;\r                                                start_pos = curr+1;\r                                            break;\r                                 case '#':\r                                              mask[current].assign(start_pos, curr);\r                                         current = CHAN;\r                                                start_pos = curr;\r                                              break;\r                         }\r                      }\r                              \r                       if(mask[current].empty())\r                      {\r                              mask[current].assign(start_pos, param.end());   \r                       }\r                      \r                       /* nick@host wants to be changed to *!nick@host rather than nick!*@host... */\r                  if(mask[NICK].length() && mask[HOST].length() && mask[IDENT].empty())\r                  {\r                              /* std::string::swap() is fast - it runs in constant time */\r                           mask[NICK].swap(mask[IDENT]);\r                  }\r                              \r                       for(int i = 0; i < 3; i++)\r                     {\r                              if(mask[i].empty())\r                            {\r                                      mask[i].assign("*");\r                           }\r                      }\r                              \r                       param.assign(mask[NICK]).append(1, '!').append(mask[IDENT]).append(1, '@').append(mask[HOST]);\r \r                       if(mask[CHAN].length())\r                        {\r                              if(Srv->IsChannel(mask[CHAN].c_str()))\r                         {\r                                      if(irc::string(channel->name) == irc::string(mask[CHAN].c_str()))\r                                      {\r                                              source->WriteServ("690 %s %s :You cannot set a ban redirection to the channel the ban is on", source->nick, channel->name);\r                                            return false;\r                                  }\r                                      else\r                                   {\r                                              if(adding)\r                                             {\r                                                      /* It's a properly valid redirecting ban, and we're adding it */\r                                                       if(!channel->GetExt("banredirects", redirects))\r                                                        {\r                                                              redirects = new BanRedirectList;\r                                                               channel->Extend("banredirects", redirects);\r                                                    }\r                              \r                                                       /* Here 'param' doesn't have the channel on it yet */\r                                                  redirects->push_back(BanRedirectEntry(mask[CHAN].c_str(), param.c_str()));\r                                                     \r                                                       /* Now it does */\r                                                      param.append(mask[CHAN]);\r                                              }\r                                              else\r                                           {\r                                                      /* Removing a ban, if there's no extensible there are no redirecting bans and we're fine. */\r                                                   if(channel->GetExt("banredirects", redirects))\r                                                 {\r                                                              /* But there were, so we need to remove the matching one if there is one */\r                                    \r                                                               for(BanRedirectList::iterator redir = redirects->begin(); redir != redirects->end(); redir++)\r                                                          {\r                                                                      /* Ugly as fuck */\r                                                                     if((irc::string(redir->targetchan.c_str()) == irc::string(mask[CHAN].c_str())) && (irc::string(redir->banmask.c_str()) == irc::string(param.c_str())))\r                                                                 {\r                                                                              redirects->erase(redir);\r                                                                               \r                                                                               if(redirects->empty())\r                                                                         {\r                                                                                      DELETE(redirects);\r                                                                                     channel->Shrink("banredirects");\r                                                                               }\r                                                                              \r                                                                               break;\r                                                                 }\r                                                              }\r                                                      }\r                                                      \r                                                       /* Append the channel so the default +b handler can remove the entry too */\r                                                    param.append(mask[CHAN]);\r                                              }\r                                      }\r                              }\r                              else\r                           {\r                                      source->WriteServ("403 %s %s :Invalid channel name in redirection (%s)", source->nick, channel->name, mask[CHAN].c_str());\r                                     return false;\r                          }\r                      }\r              }\r              \r               return true;\r   }\r};\r\rclass ModuleBanRedirect : public Module\r{\r        BanRedirect* re;\r       bool nofollow;\r Module* ExceptionModule;\r\r public:\r     ModuleBanRedirect(InspIRCd* Me)\r        : Module(Me)\r   {\r              re = new BanRedirect(Me);\r              nofollow = false;\r              \r               if(!ServerInstance->AddModeWatcher(re))\r                        throw ModuleException("Could not add mode watcher");\r\r          OnRehash(NULL, "");\r    }\r      \r       void Implements(char* List)\r    {\r              List[I_OnRehash] = List[I_OnUserPreJoin] = List[I_OnChannelDelete] = List[I_OnCleanup] = 1;\r    }\r      \r       virtual void OnChannelDelete(chanrec* chan)\r    {\r              OnCleanup(TYPE_CHANNEL, chan);\r }\r      \r       virtual void OnCleanup(int target_type, void* item)\r    {\r              if(target_type == TYPE_CHANNEL)\r                {\r                      chanrec* chan = static_cast<chanrec*>(item);\r                   BanRedirectList* redirects;\r                    \r                       if(chan->GetExt("banredirects", redirects))\r                    {\r                              irc::modestacker modestack(false);\r                             StringDeque stackresult;\r                               const char* mode_junk[MAXMODES+2];\r                             userrec* myhorriblefakeuser = new userrec(ServerInstance);\r                             myhorriblefakeuser->SetFd(FD_MAGIC_NUMBER);\r                            \r                               mode_junk[0] = chan->name;\r                             \r                               for(BanRedirectList::iterator i = redirects->begin(); i != redirects->end(); i++)\r                              {\r                                      modestack.Push('b', i->targetchan.insert(0, i->banmask));\r                              }\r                              \r                               for(BanRedirectList::iterator i = redirects->begin(); i != redirects->end(); i++)\r                              {\r                                      modestack.PushPlus();\r                                  modestack.Push('b', i->banmask);\r                               }\r                              \r                               while(modestack.GetStackedLine(stackresult))\r                           {\r                                      for(StringDeque::size_type i = 0; i < stackresult.size(); i++)\r                                 {\r                                              mode_junk[i+1] = stackresult[i].c_str();\r                                       }\r                                      \r                                       ServerInstance->SendMode(mode_junk, stackresult.size() + 1, myhorriblefakeuser);\r                               }\r                              \r                               DELETE(myhorriblefakeuser);\r                            DELETE(redirects);\r                             chan->Shrink("banredirects");\r                  }\r              }\r      }\r\r     virtual void OnRehash(userrec* user, const std::string &param)\r {\r              ExceptionModule = ServerInstance->FindModule("m_banexception.so");\r     }\r\r     virtual int OnUserPreJoin(userrec* user, chanrec* chan, const char* cname, std::string &privs)\r {\r              /* This prevents recursion when a user sets multiple ban redirects in a chain\r           * (thanks Potter)\r              */\r            if (nofollow)\r                  return 0;\r\r             /* Return 1 to prevent the join, 0 to allow it */\r              if (chan)\r              {\r                      BanRedirectList* redirects;\r                    \r                       if(chan->GetExt("banredirects", redirects))\r                    {\r                              /* We actually had some ban redirects to check */\r                              \r                               /* This was replaced with user->MakeHostIP() when I had a snprintf(), but MakeHostIP() doesn't seem to add the nick.\r                            * Maybe we should have a GetFullIPHost() or something to match GetFullHost() and GetFullRealHost?\r                              */\r\r                           if (ExceptionModule)\r                           {\r                                      ListModeRequest n(this, ExceptionModule, user, chan);\r                                  /* Users with ban exceptions are allowed to join without being redirected */\r                                   if (n.Send())\r                                          return 0;\r                              }\r\r                             std::string ipmask(user->nick);\r                                ipmask.append(1, '!').append(user->MakeHostIP());\r                              \r                               for(BanRedirectList::iterator redir = redirects->begin(); redir != redirects->end(); redir++)\r                          {\r                                      if(ServerInstance->MatchText(user->GetFullRealHost(), redir->banmask) || ServerInstance->MatchText(user->GetFullHost(), redir->banmask) || ServerInstance->MatchText(ipmask, redir->banmask))\r                                  {\r                                              /* tell them they're banned and are being transferred */\r                                               chanrec* destchan = ServerInstance->FindChan(redir->targetchan);\r                                               \r                                               if(destchan && ServerInstance->FindModule("m_redirect.so") && destchan->IsModeSet('L') && destchan->limit && (destchan->GetUserCounter() >= destchan->limit))\r                                          {\r                                                      user->WriteServ("474 %s %s :Cannot join channel (You are banned)", user->nick, chan->name);\r                                                    return 1;\r                                              }\r                                              else\r                                           {\r                                                      user->WriteServ("470 %s :You are banned from %s. You are being automatically redirected to %s", user->nick, chan->name, redir->targetchan.c_str());\r                                                    nofollow = true;\r                                                       chanrec::JoinUser(ServerInstance, user, redir->targetchan.c_str(), false, "", ServerInstance->Time(true));\r                                                     nofollow = false;\r                                                      return 1;\r                                              }\r                                      }\r                              }\r                      }\r              }\r              return 0;\r      }\r\r     virtual ~ModuleBanRedirect()\r   {\r              ServerInstance->Modes->DelModeWatcher(re);\r             DELETE(re);\r    }\r      \r       virtual Version GetVersion()\r   {\r              return Version(1, 0, 0, 0, VF_COMMON | VF_VENDOR, API_VERSION);\r        }\r      \r       Priority Prioritize()\r  {\r              return (Priority)ServerInstance->PriorityBefore("m_banexception.so");\r  }\r};\r\r\rMODULE_INIT(ModuleBanRedirect)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "mode.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+#include "u_listmode.h"
+
+/* $ModDesc: Allows an extended ban (+b) syntax redirecting banned users to another channel */
+
+/* Originally written by Om, January 2007
+ */
+
+class BanRedirectEntry
+{
+ public:
+       std::string targetchan;
+       std::string banmask;
+
+       BanRedirectEntry(const std::string &target = "", const std::string &mask = "")
+       : targetchan(target), banmask(mask)
+       {
+       }
+};
+
+typedef std::vector<BanRedirectEntry> BanRedirectList;
+typedef std::deque<std::string> StringDeque;
+
+class BanRedirect : public ModeWatcher
+{
+ private:
+       InspIRCd* Srv;
+ public:
+       BanRedirect(InspIRCd* Instance)
+       : ModeWatcher(Instance, 'b', MODETYPE_CHANNEL), Srv(Instance)
+       {
+       }
+
+       bool BeforeMode(userrec* source, userrec* dest, chanrec* channel, std::string &param, bool adding, ModeType type)
+       {
+               /* nick!ident@host -> nick!ident@host
+                * nick!ident@host#chan -> nick!ident@host#chan
+                * nick@host#chan -> nick!*@host#chan
+                * nick!ident#chan -> nick!ident@*#chan
+                * nick#chan -> nick!*@*#chan
+                */
+               
+               if(channel && (type == MODETYPE_CHANNEL) && param.length())
+               {
+                       BanRedirectList* redirects;
+                       
+                       std::string mask[4];
+                       enum { NICK, IDENT, HOST, CHAN } current = NICK;
+                       std::string::iterator start_pos = param.begin();
+                       long maxbans = channel->GetMaxBans();
+               
+                       if(channel->bans.size() > static_cast<unsigned>(maxbans))
+                       {
+                               source->WriteServ("478 %s %s :Channel ban list for %s is full (maximum entries for this channel is %d)", source->nick, channel->name, channel->name, maxbans);
+                               return false;
+                       }
+                       
+                       for(std::string::iterator curr = start_pos; curr != param.end(); curr++)
+                       {
+                               switch(*curr)
+                               {
+                                       case '!':
+                                               mask[current].assign(start_pos, curr);
+                                               current = IDENT;
+                                               start_pos = curr+1;
+                                               break;
+                                       case '@':
+                                               mask[current].assign(start_pos, curr);
+                                               current = HOST;
+                                               start_pos = curr+1;
+                                               break;
+                                       case '#':
+                                               mask[current].assign(start_pos, curr);
+                                               current = CHAN;
+                                               start_pos = curr;
+                                               break;
+                               }
+                       }
+                               
+                       if(mask[current].empty())
+                       {
+                               mask[current].assign(start_pos, param.end());   
+                       }
+                       
+                       /* nick@host wants to be changed to *!nick@host rather than nick!*@host... */
+                       if(mask[NICK].length() && mask[HOST].length() && mask[IDENT].empty())
+                       {
+                               /* std::string::swap() is fast - it runs in constant time */
+                               mask[NICK].swap(mask[IDENT]);
+                       }
+                               
+                       for(int i = 0; i < 3; i++)
+                       {
+                               if(mask[i].empty())
+                               {
+                                       mask[i].assign("*");
+                               }
+                       }
+                               
+                       param.assign(mask[NICK]).append(1, '!').append(mask[IDENT]).append(1, '@').append(mask[HOST]);
+       
+                       if(mask[CHAN].length())
+                       {
+                               if(Srv->IsChannel(mask[CHAN].c_str()))
+                               {
+                                       if(irc::string(channel->name) == irc::string(mask[CHAN].c_str()))
+                                       {
+                                               source->WriteServ("690 %s %s :You cannot set a ban redirection to the channel the ban is on", source->nick, channel->name);
+                                               return false;
+                                       }
+                                       else
+                                       {
+                                               if(adding)
+                                               {
+                                                       /* It's a properly valid redirecting ban, and we're adding it */
+                                                       if(!channel->GetExt("banredirects", redirects))
+                                                       {
+                                                               redirects = new BanRedirectList;
+                                                               channel->Extend("banredirects", redirects);
+                                                       }
+                               
+                                                       /* Here 'param' doesn't have the channel on it yet */
+                                                       redirects->push_back(BanRedirectEntry(mask[CHAN].c_str(), param.c_str()));
+                                                       
+                                                       /* Now it does */
+                                                       param.append(mask[CHAN]);
+                                               }
+                                               else
+                                               {
+                                                       /* Removing a ban, if there's no extensible there are no redirecting bans and we're fine. */
+                                                       if(channel->GetExt("banredirects", redirects))
+                                                       {
+                                                               /* But there were, so we need to remove the matching one if there is one */
+                                       
+                                                               for(BanRedirectList::iterator redir = redirects->begin(); redir != redirects->end(); redir++)
+                                                               {
+                                                                       /* Ugly as fuck */
+                                                                       if((irc::string(redir->targetchan.c_str()) == irc::string(mask[CHAN].c_str())) && (irc::string(redir->banmask.c_str()) == irc::string(param.c_str())))
+                                                                       {
+                                                                               redirects->erase(redir);
+                                                                               
+                                                                               if(redirects->empty())
+                                                                               {
+                                                                                       DELETE(redirects);
+                                                                                       channel->Shrink("banredirects");
+                                                                               }
+                                                                               
+                                                                               break;
+                                                                       }
+                                                               }
+                                                       }
+                                                       
+                                                       /* Append the channel so the default +b handler can remove the entry too */
+                                                       param.append(mask[CHAN]);
+                                               }
+                                       }
+                               }
+                               else
+                               {
+                                       source->WriteServ("403 %s %s :Invalid channel name in redirection (%s)", source->nick, channel->name, mask[CHAN].c_str());
+                                       return false;
+                               }
+                       }
+               }
+               
+               return true;
+       }
+};
+
+class ModuleBanRedirect : public Module
+{
+       BanRedirect* re;
+       bool nofollow;
+       Module* ExceptionModule;
+
+ public:
+       ModuleBanRedirect(InspIRCd* Me)
+       : Module(Me)
+       {
+               re = new BanRedirect(Me);
+               nofollow = false;
+               
+               if(!ServerInstance->AddModeWatcher(re))
+                       throw ModuleException("Could not add mode watcher");
+
+               OnRehash(NULL, "");
+       }
+       
+       void Implements(char* List)
+       {
+               List[I_OnRehash] = List[I_OnUserPreJoin] = List[I_OnChannelDelete] = List[I_OnCleanup] = 1;
+       }
+       
+       virtual void OnChannelDelete(chanrec* chan)
+       {
+               OnCleanup(TYPE_CHANNEL, chan);
+       }
+       
+       virtual void OnCleanup(int target_type, void* item)
+       {
+               if(target_type == TYPE_CHANNEL)
+               {
+                       chanrec* chan = static_cast<chanrec*>(item);
+                       BanRedirectList* redirects;
+                       
+                       if(chan->GetExt("banredirects", redirects))
+                       {
+                               irc::modestacker modestack(false);
+                               StringDeque stackresult;
+                               const char* mode_junk[MAXMODES+2];
+                               userrec* myhorriblefakeuser = new userrec(ServerInstance);
+                               myhorriblefakeuser->SetFd(FD_MAGIC_NUMBER);
+                               
+                               mode_junk[0] = chan->name;
+                               
+                               for(BanRedirectList::iterator i = redirects->begin(); i != redirects->end(); i++)
+                               {
+                                       modestack.Push('b', i->targetchan.insert(0, i->banmask));
+                               }
+                               
+                               for(BanRedirectList::iterator i = redirects->begin(); i != redirects->end(); i++)
+                               {
+                                       modestack.PushPlus();
+                                       modestack.Push('b', i->banmask);
+                               }
+                               
+                               while(modestack.GetStackedLine(stackresult))
+                               {
+                                       for(StringDeque::size_type i = 0; i < stackresult.size(); i++)
+                                       {
+                                               mode_junk[i+1] = stackresult[i].c_str();
+                                       }
+                                       
+                                       ServerInstance->SendMode(mode_junk, stackresult.size() + 1, myhorriblefakeuser);
+                               }
+                               
+                               DELETE(myhorriblefakeuser);
+                               DELETE(redirects);
+                               chan->Shrink("banredirects");
+                       }
+               }
+       }
+
+       virtual void OnRehash(userrec* user, const std::string &param)
+       {
+               ExceptionModule = ServerInstance->FindModule("m_banexception.so");
+       }
+
+       virtual int OnUserPreJoin(userrec* user, chanrec* chan, const char* cname, std::string &privs)
+       {
+               /* This prevents recursion when a user sets multiple ban redirects in a chain
+                * (thanks Potter)
+                */
+               if (nofollow)
+                       return 0;
+
+               /* Return 1 to prevent the join, 0 to allow it */
+               if (chan)
+               {
+                       BanRedirectList* redirects;
+                       
+                       if(chan->GetExt("banredirects", redirects))
+                       {
+                               /* We actually had some ban redirects to check */
+                               
+                               /* This was replaced with user->MakeHostIP() when I had a snprintf(), but MakeHostIP() doesn't seem to add the nick.
+                                * Maybe we should have a GetFullIPHost() or something to match GetFullHost() and GetFullRealHost?
+                                */
+
+                               if (ExceptionModule)
+                               {
+                                       ListModeRequest n(this, ExceptionModule, user, chan);
+                                       /* Users with ban exceptions are allowed to join without being redirected */
+                                       if (n.Send())
+                                               return 0;
+                               }
+
+                               std::string ipmask(user->nick);
+                               ipmask.append(1, '!').append(user->MakeHostIP());
+                               
+                               for(BanRedirectList::iterator redir = redirects->begin(); redir != redirects->end(); redir++)
+                               {
+                                       if(ServerInstance->MatchText(user->GetFullRealHost(), redir->banmask) || ServerInstance->MatchText(user->GetFullHost(), redir->banmask) || ServerInstance->MatchText(ipmask, redir->banmask))
+                                       {
+                                               /* tell them they're banned and are being transferred */
+                                               chanrec* destchan = ServerInstance->FindChan(redir->targetchan);
+                                               
+                                               if(destchan && ServerInstance->FindModule("m_redirect.so") && destchan->IsModeSet('L') && destchan->limit && (destchan->GetUserCounter() >= destchan->limit))
+                                               {
+                                                       user->WriteServ("474 %s %s :Cannot join channel (You are banned)", user->nick, chan->name);
+                                                       return 1;
+                                               }
+                                               else
+                                               {
+                                                       user->WriteServ("470 %s :You are banned from %s. You are being automatically redirected to %s", user->nick, chan->name, redir->targetchan.c_str());
+                                                       nofollow = true;
+                                                       chanrec::JoinUser(ServerInstance, user, redir->targetchan.c_str(), false, "", ServerInstance->Time(true));
+                                                       nofollow = false;
+                                                       return 1;
+                                               }
+                                       }
+                               }
+                       }
+               }
+               return 0;
+       }
+
+       virtual ~ModuleBanRedirect()
+       {
+               ServerInstance->Modes->DelModeWatcher(re);
+               DELETE(re);
+       }
+       
+       virtual Version GetVersion()
+       {
+               return Version(1, 0, 0, 0, VF_COMMON | VF_VENDOR, API_VERSION);
+       }
+       
+       Priority Prioritize()
+       {
+               return (Priority)ServerInstance->PriorityBefore("m_banexception.so");
+       }
+};
+
+
+MODULE_INIT(ModuleBanRedirect)
index 5ff0c110065f8e9f2cd5121e64e91a1527e86256..69e99d0bba33306031f3ce153a5cbd6da3bcfa94 100644 (file)
@@ -1 +1,191 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r#include "hashcomp.h"\r\r/* $ModDesc: Attempt to block /amsg, at least some of the irritating mIRC scripts. */\r\renum BlockAction { IBLOCK_KILL, IBLOCK_KILLOPERS, IBLOCK_NOTICE, IBLOCK_NOTICEOPERS, IBLOCK_SILENT };\r/* IBLOCK_NOTICE           - Send a notice to the user informing them of what happened.\r * IBLOCK_NOTICEOPERS      - Send a notice to the user informing them and send an oper notice.\r *  IBLOCK_SILENT           - Generate no output, silently drop messages.\r *        IBLOCK_KILL                     - Kill the user with the reason "Global message (/amsg or /ame) detected".\r *   IBLOCK_KILLOPERS        - As above, but send an oper notice as well. This is the default.\r */\r\r/** Holds a blocked message's details\r */\rclass BlockedMessage : public classbase\r{\rpublic:\r     std::string message;\r   irc::string target;\r    time_t sent;\r\r  BlockedMessage(const std::string &msg, const irc::string &tgt, time_t when)\r    : message(msg), target(tgt), sent(when)\r        {\r      }\r};\r\rclass ModuleBlockAmsg : public Module\r{\r  int ForgetDelay;\r       BlockAction action;\r    \r public:\r      ModuleBlockAmsg(InspIRCd* Me)\r  : Module(Me)\r   {\r              \r               this->OnRehash(NULL,"");\r       }\r\r     void Implements(char* List)\r    {\r              List[I_OnRehash] = List[I_OnPreCommand] = List[I_OnCleanup] = 1;\r       }\r      \r       virtual ~ModuleBlockAmsg()\r     {\r      }\r      \r       virtual Version GetVersion()\r   {\r              return Version(1,1,0,0,VF_VENDOR,API_VERSION);\r }\r      \r       virtual void OnRehash(userrec* user, const std::string &parameter)\r     {\r              ConfigReader Conf(ServerInstance);\r             \r               ForgetDelay = Conf.ReadInteger("blockamsg", "delay", 0, false);\r                \r               if(Conf.GetError() == CONF_VALUE_NOT_FOUND)\r                    ForgetDelay = -1;\r                      \r               std::string act = Conf.ReadValue("blockamsg", "action", 0);\r            \r               if(act == "notice")\r                    action = IBLOCK_NOTICE;\r                else if(act == "noticeopers")\r                  action = IBLOCK_NOTICEOPERS;\r           else if(act == "silent")\r                       action = IBLOCK_SILENT;\r                else if(act == "kill")\r                 action = IBLOCK_KILL;\r          else\r                   action = IBLOCK_KILLOPERS;\r     }\r\r     virtual int OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line)\r       {\r              // Don't do anything with unregistered users, or remote ones.\r          if(!user || (user->registered != REG_ALL) || !IS_LOCAL(user))\r                  return 0;\r                      \r               // We want case insensitive command comparison.\r                // Add std::string contructor for irc::string :x\r               irc::string cmd = command.c_str();\r             \r               if(validated && (cmd == "PRIVMSG" || cmd == "NOTICE") && (pcnt >= 2))\r          {\r                      // parameters[0] should have the target(s) in it.\r                      // I think it will be faster to first check if there are any commas, and if there are then try and parse it out.\r                       // Most messages have a single target so...\r                    \r                       int targets = 1;\r                       int userchans = 0;\r             \r                       if(*parameters[0] != '#')\r                      {\r                              // Decrement if the first target wasn't a channel.\r                             targets--;\r                     }\r                      \r                       for(const char* c = parameters[0]; *c; c++)\r                            if((*c == ',') && *(c+1) && (*(c+1) == '#'))\r                                   targets++;\r                             \r                       /* targets should now contain the number of channel targets the msg/notice was pointed at.\r                      * If the msg/notice was a PM there should be no channel targets and 'targets' should = 0.\r                      * We don't want to block PMs so...\r                     */\r                    if(targets == 0)\r                       {\r                              return 0;\r                      }\r                                      \r                       userchans = user->chans.size();\r\r                       // Check that this message wasn't already sent within a few seconds.\r                   BlockedMessage* m;\r                     user->GetExt("amsgblock", m);\r                  \r                       // If the message is identical and within the time.\r                    // We check the target is *not* identical, that'd straying into the realms of flood control. Which isn't what we're doing...\r                   // OR\r                  // The number of target channels is equal to the number of channels the sender is on..a little suspicious.\r                     // Check it's more than 1 too, or else users on one channel would have fun.\r                    if((m && (m->message == parameters[1]) && (m->target != parameters[0]) && (ForgetDelay != -1) && (m->sent >= ServerInstance->Time()-ForgetDelay)) || ((targets > 1) && (targets == userchans)))\r                        {\r                              // Block it...\r                         if(action == IBLOCK_KILLOPERS || action == IBLOCK_NOTICEOPERS)\r                                 ServerInstance->WriteOpers("*** %s had an /amsg or /ame denied", user->nick);\r\r                         if(action == IBLOCK_KILL || action == IBLOCK_KILLOPERS)\r                                        userrec::QuitUser(ServerInstance, user, "Global message (/amsg or /ame) detected");\r                            else if(action == IBLOCK_NOTICE || action == IBLOCK_NOTICEOPERS)\r                                       user->WriteServ( "NOTICE %s :Global message (/amsg or /ame) detected", user->nick);\r                                                                    \r                               return 1;\r                      }\r                      \r                       if(m)\r                  {\r                              // If there's already a BlockedMessage allocated, use it.\r                              m->message = parameters[1];\r                            m->target = parameters[0];\r                             m->sent = ServerInstance->Time();\r                      }\r                      else\r                   {\r                              m = new BlockedMessage(parameters[1], parameters[0], ServerInstance->Time());\r                          user->Extend("amsgblock", (char*)m);\r                   }\r              }                                       \r               return 0;\r      }\r      \r       void OnCleanup(int target_type, void* item)\r    {\r              if(target_type == TYPE_USER)\r           {\r                      userrec* user = (userrec*)item;\r                        BlockedMessage* m;\r                     user->GetExt("amsgblock", m);\r                  if(m)\r                  {\r                              DELETE(m);\r                             user->Shrink("amsgblock");\r                     }\r              }\r      }\r};\r\r\rMODULE_INIT(ModuleBlockAmsg)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+#include "hashcomp.h"
+
+/* $ModDesc: Attempt to block /amsg, at least some of the irritating mIRC scripts. */
+
+enum BlockAction { IBLOCK_KILL, IBLOCK_KILLOPERS, IBLOCK_NOTICE, IBLOCK_NOTICEOPERS, IBLOCK_SILENT };
+/*     IBLOCK_NOTICE           - Send a notice to the user informing them of what happened.
+ *     IBLOCK_NOTICEOPERS      - Send a notice to the user informing them and send an oper notice.
+ *     IBLOCK_SILENT           - Generate no output, silently drop messages.
+ *     IBLOCK_KILL                     - Kill the user with the reason "Global message (/amsg or /ame) detected".
+ *     IBLOCK_KILLOPERS        - As above, but send an oper notice as well. This is the default.
+ */
+
+/** Holds a blocked message's details
+ */
+class BlockedMessage : public classbase
+{
+public:
+       std::string message;
+       irc::string target;
+       time_t sent;
+
+       BlockedMessage(const std::string &msg, const irc::string &tgt, time_t when)
+       : message(msg), target(tgt), sent(when)
+       {
+       }
+};
+
+class ModuleBlockAmsg : public Module
+{
+       int ForgetDelay;
+       BlockAction action;
+       
+ public:
+       ModuleBlockAmsg(InspIRCd* Me)
+       : Module(Me)
+       {
+               
+               this->OnRehash(NULL,"");
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnRehash] = List[I_OnPreCommand] = List[I_OnCleanup] = 1;
+       }
+       
+       virtual ~ModuleBlockAmsg()
+       {
+       }
+       
+       virtual Version GetVersion()
+       {
+               return Version(1,1,0,0,VF_VENDOR,API_VERSION);
+       }
+       
+       virtual void OnRehash(userrec* user, const std::string &parameter)
+       {
+               ConfigReader Conf(ServerInstance);
+               
+               ForgetDelay = Conf.ReadInteger("blockamsg", "delay", 0, false);
+               
+               if(Conf.GetError() == CONF_VALUE_NOT_FOUND)
+                       ForgetDelay = -1;
+                       
+               std::string act = Conf.ReadValue("blockamsg", "action", 0);
+               
+               if(act == "notice")
+                       action = IBLOCK_NOTICE;
+               else if(act == "noticeopers")
+                       action = IBLOCK_NOTICEOPERS;
+               else if(act == "silent")
+                       action = IBLOCK_SILENT;
+               else if(act == "kill")
+                       action = IBLOCK_KILL;
+               else
+                       action = IBLOCK_KILLOPERS;
+       }
+
+       virtual int OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line)
+       {
+               // Don't do anything with unregistered users, or remote ones.
+               if(!user || (user->registered != REG_ALL) || !IS_LOCAL(user))
+                       return 0;
+                       
+               // We want case insensitive command comparison.
+               // Add std::string contructor for irc::string :x
+               irc::string cmd = command.c_str();
+               
+               if(validated && (cmd == "PRIVMSG" || cmd == "NOTICE") && (pcnt >= 2))
+               {
+                       // parameters[0] should have the target(s) in it.
+                       // I think it will be faster to first check if there are any commas, and if there are then try and parse it out.
+                       // Most messages have a single target so...
+                       
+                       int targets = 1;
+                       int userchans = 0;
+               
+                       if(*parameters[0] != '#')
+                       {
+                               // Decrement if the first target wasn't a channel.
+                               targets--;
+                       }
+                       
+                       for(const char* c = parameters[0]; *c; c++)
+                               if((*c == ',') && *(c+1) && (*(c+1) == '#'))
+                                       targets++;
+                               
+                       /* targets should now contain the number of channel targets the msg/notice was pointed at.
+                        * If the msg/notice was a PM there should be no channel targets and 'targets' should = 0.
+                        * We don't want to block PMs so...
+                        */
+                       if(targets == 0)
+                       {
+                               return 0;
+                       }
+                                       
+                       userchans = user->chans.size();
+
+                       // Check that this message wasn't already sent within a few seconds.
+                       BlockedMessage* m;
+                       user->GetExt("amsgblock", m);
+                       
+                       // If the message is identical and within the time.
+                       // We check the target is *not* identical, that'd straying into the realms of flood control. Which isn't what we're doing...
+                       // OR
+                       // The number of target channels is equal to the number of channels the sender is on..a little suspicious.
+                       // Check it's more than 1 too, or else users on one channel would have fun.
+                       if((m && (m->message == parameters[1]) && (m->target != parameters[0]) && (ForgetDelay != -1) && (m->sent >= ServerInstance->Time()-ForgetDelay)) || ((targets > 1) && (targets == userchans)))
+                       {
+                               // Block it...
+                               if(action == IBLOCK_KILLOPERS || action == IBLOCK_NOTICEOPERS)
+                                       ServerInstance->WriteOpers("*** %s had an /amsg or /ame denied", user->nick);
+
+                               if(action == IBLOCK_KILL || action == IBLOCK_KILLOPERS)
+                                       userrec::QuitUser(ServerInstance, user, "Global message (/amsg or /ame) detected");
+                               else if(action == IBLOCK_NOTICE || action == IBLOCK_NOTICEOPERS)
+                                       user->WriteServ( "NOTICE %s :Global message (/amsg or /ame) detected", user->nick);
+                                                                       
+                               return 1;
+                       }
+                       
+                       if(m)
+                       {
+                               // If there's already a BlockedMessage allocated, use it.
+                               m->message = parameters[1];
+                               m->target = parameters[0];
+                               m->sent = ServerInstance->Time();
+                       }
+                       else
+                       {
+                               m = new BlockedMessage(parameters[1], parameters[0], ServerInstance->Time());
+                               user->Extend("amsgblock", (char*)m);
+                       }
+               }                                       
+               return 0;
+       }
+       
+       void OnCleanup(int target_type, void* item)
+       {
+               if(target_type == TYPE_USER)
+               {
+                       userrec* user = (userrec*)item;
+                       BlockedMessage* m;
+                       user->GetExt("amsgblock", m);
+                       if(m)
+                       {
+                               DELETE(m);
+                               user->Shrink("amsgblock");
+                       }
+               }
+       }
+};
+
+
+MODULE_INIT(ModuleBlockAmsg)
index 8713f8c0d86db8c89c0a43307f84c278762f78a0..9197a8f112c68c06c198414dcb99ee428e901acf 100644 (file)
@@ -1 +1,143 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r#include "mode.h"\r\r/* $ModDesc: Provides support for channel mode +P to block all-CAPS channel messages and notices */\r\r\r/** Handles the +P channel mode\r */\rclass BlockCaps : public ModeHandler\r{\r public:\r  BlockCaps(InspIRCd* Instance) : ModeHandler(Instance, 'P', 0, 0, false, MODETYPE_CHANNEL, false) { }\r\r  ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)\r {\r              if (adding)\r            {\r                      if (!channel->IsModeSet('P'))\r                  {\r                              channel->SetMode('P',true);\r                            return MODEACTION_ALLOW;\r                       }\r              }\r              else\r           {\r                      if (channel->IsModeSet('P'))\r                   {\r                              channel->SetMode('P',false);\r                           return MODEACTION_ALLOW;\r                       }\r              }\r\r             return MODEACTION_DENY;\r        }\r};\r\rclass ModuleBlockCAPS : public Module\r{\r  BlockCaps* bc;\r int percent;\r   unsigned int minlen;\r   char capsmap[256];\rpublic:\r     \r       ModuleBlockCAPS(InspIRCd* Me) : Module(Me)\r     {\r              OnRehash(NULL,"");\r             bc = new BlockCaps(ServerInstance);\r            if (!ServerInstance->AddMode(bc, 'P'))\r                 throw ModuleException("Could not add new modes!");\r     }\r\r     void Implements(char* List)\r    {\r              List[I_OnUserPreMessage] = List[I_OnUserPreNotice] = List[I_OnRehash] = 1;\r     }\r\r     virtual void OnRehash(userrec* user, const std::string &param)\r {\r              ReadConf();\r    }\r\r     virtual int OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)\r    {\r              if (target_type == TYPE_CHANNEL)\r               {\r                      if ((!IS_LOCAL(user)) || (text.length() < minlen))\r                             return 0;\r\r                     chanrec* c = (chanrec*)dest;\r\r                  if (c->IsModeSet('P'))\r                 {\r                              int caps = 0;\r                          for (std::string::iterator i = text.begin(); i != text.end(); i++)\r                                     caps += capsmap[(unsigned char)*i];\r                            if ( ((caps*100)/(int)text.length()) >= percent )\r                              {\r                                      user->WriteServ( "404 %s %s :Your line cannot be more than %d%% capital letters if it is %d or more letters long", user->nick, c->name, percent, minlen);\r                                      return 1;\r                              }\r                      }\r              }\r              return 0;\r      }\r\r     virtual int OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)\r     {\r              return OnUserPreMessage(user,dest,target_type,text,status,exempt_list);\r        }\r\r     void ReadConf()\r        {\r              ConfigReader Conf(ServerInstance);\r             percent = Conf.ReadInteger("blockcaps", "percent", "100", 0, true);\r            minlen = Conf.ReadInteger("blockcaps", "minlen", "0", 0, true);\r                std::string hmap = Conf.ReadValue("blockcaps", "capsmap", 0);\r          if (hmap.empty())\r                      hmap = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";\r           memset(&capsmap, 0, 255);\r              for (std::string::iterator n = hmap.begin(); n != hmap.end(); n++)\r                     capsmap[(unsigned char)*n] = 1;\r                if (percent < 0 || percent > 100)\r              {\r                      ServerInstance->Log(DEFAULT, "<blockcaps:percent> out of range, setting to default of 100.");\r                  percent = 100;\r         }\r              if (minlen < 0 || minlen > MAXBUF-1)\r           {\r                      ServerInstance->Log(DEFAULT, "<blockcaps:minlen> out of range, setting to default of 0.");\r                     minlen = 0;\r            }\r      }\r\r     virtual ~ModuleBlockCAPS()\r     {\r              ServerInstance->Modes->DelMode(bc);\r            DELETE(bc);\r    }\r\r     virtual Version GetVersion()\r   {\r              return Version(1,1,0,0,VF_COMMON|VF_VENDOR,API_VERSION);\r       }\r};\r\rMODULE_INIT(ModuleBlockCAPS)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+#include "mode.h"
+
+/* $ModDesc: Provides support for channel mode +P to block all-CAPS channel messages and notices */
+
+
+/** Handles the +P channel mode
+ */
+class BlockCaps : public ModeHandler
+{
+ public:
+       BlockCaps(InspIRCd* Instance) : ModeHandler(Instance, 'P', 0, 0, false, MODETYPE_CHANNEL, false) { }
+
+       ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)
+       {
+               if (adding)
+               {
+                       if (!channel->IsModeSet('P'))
+                       {
+                               channel->SetMode('P',true);
+                               return MODEACTION_ALLOW;
+                       }
+               }
+               else
+               {
+                       if (channel->IsModeSet('P'))
+                       {
+                               channel->SetMode('P',false);
+                               return MODEACTION_ALLOW;
+                       }
+               }
+
+               return MODEACTION_DENY;
+       }
+};
+
+class ModuleBlockCAPS : public Module
+{
+       BlockCaps* bc;
+       int percent;
+       unsigned int minlen;
+       char capsmap[256];
+public:
+       
+       ModuleBlockCAPS(InspIRCd* Me) : Module(Me)
+       {
+               OnRehash(NULL,"");
+               bc = new BlockCaps(ServerInstance);
+               if (!ServerInstance->AddMode(bc, 'P'))
+                       throw ModuleException("Could not add new modes!");
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnUserPreMessage] = List[I_OnUserPreNotice] = List[I_OnRehash] = 1;
+       }
+
+       virtual void OnRehash(userrec* user, const std::string &param)
+       {
+               ReadConf();
+       }
+
+       virtual int OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
+       {
+               if (target_type == TYPE_CHANNEL)
+               {
+                       if ((!IS_LOCAL(user)) || (text.length() < minlen))
+                               return 0;
+
+                       chanrec* c = (chanrec*)dest;
+
+                       if (c->IsModeSet('P'))
+                       {
+                               int caps = 0;
+                               for (std::string::iterator i = text.begin(); i != text.end(); i++)
+                                       caps += capsmap[(unsigned char)*i];
+                               if ( ((caps*100)/(int)text.length()) >= percent )
+                               {
+                                       user->WriteServ( "404 %s %s :Your line cannot be more than %d%% capital letters if it is %d or more letters long", user->nick, c->name, percent, minlen);
+                                       return 1;
+                               }
+                       }
+               }
+               return 0;
+       }
+
+       virtual int OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
+       {
+               return OnUserPreMessage(user,dest,target_type,text,status,exempt_list);
+       }
+
+       void ReadConf()
+       {
+               ConfigReader Conf(ServerInstance);
+               percent = Conf.ReadInteger("blockcaps", "percent", "100", 0, true);
+               minlen = Conf.ReadInteger("blockcaps", "minlen", "0", 0, true);
+               std::string hmap = Conf.ReadValue("blockcaps", "capsmap", 0);
+               if (hmap.empty())
+                       hmap = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+               memset(&capsmap, 0, 255);
+               for (std::string::iterator n = hmap.begin(); n != hmap.end(); n++)
+                       capsmap[(unsigned char)*n] = 1;
+               if (percent < 0 || percent > 100)
+               {
+                       ServerInstance->Log(DEFAULT, "<blockcaps:percent> out of range, setting to default of 100.");
+                       percent = 100;
+               }
+               if (minlen < 0 || minlen > MAXBUF-1)
+               {
+                       ServerInstance->Log(DEFAULT, "<blockcaps:minlen> out of range, setting to default of 0.");
+                       minlen = 0;
+               }
+       }
+
+       virtual ~ModuleBlockCAPS()
+       {
+               ServerInstance->Modes->DelMode(bc);
+               DELETE(bc);
+       }
+
+       virtual Version GetVersion()
+       {
+               return Version(1,1,0,0,VF_COMMON|VF_VENDOR,API_VERSION);
+       }
+};
+
+MODULE_INIT(ModuleBlockCAPS)
index 0646caa0b65c7d193eaa11bcaa1e8c67fbebdd46..69b0e468699d5195b44fcfaefed33b64daef15c5 100644 (file)
@@ -1 +1,118 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r\r/* $ModDesc: Provides support for unreal-style channel mode +c */\r\r/** Handles the +c channel mode\r */\rclass BlockColor : public ModeHandler\r{\r public:\r      BlockColor(InspIRCd* Instance) : ModeHandler(Instance, 'c', 0, 0, false, MODETYPE_CHANNEL, false) { }\r\r ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)\r {\r              if (adding)\r            {\r                      if (!channel->IsModeSet('c'))\r                  {\r                              channel->SetMode('c',true);\r                            return MODEACTION_ALLOW;\r                       }\r              }\r              else\r           {\r                      if (channel->IsModeSet('c'))\r                   {\r                              channel->SetMode('c',false);\r                           return MODEACTION_ALLOW;\r                       }\r              }\r\r             return MODEACTION_DENY;\r        }\r};\r\rclass ModuleBlockColour : public Module\r{\r        bool AllowChanOps;      \r       BlockColor *bc;\r public:\r \r     ModuleBlockColour(InspIRCd* Me) : Module(Me)\r   {\r              bc = new BlockColor(ServerInstance);\r           if (!ServerInstance->AddMode(bc, 'c'))\r                 throw ModuleException("Could not add new modes!");\r     }\r\r     void Implements(char* List)\r    {\r              List[I_OnUserPreMessage] = List[I_OnUserPreNotice] = 1;\r        }\r\r\r    virtual int OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)\r    {\r              if ((target_type == TYPE_CHANNEL) && (IS_LOCAL(user)))\r         {\r                      chanrec* c = (chanrec*)dest;\r                   \r                       if(c->IsModeSet('c'))\r                  {\r                              if (!CHANOPS_EXEMPT(ServerInstance, 'c') || CHANOPS_EXEMPT(ServerInstance, 'c') && c->GetStatus(user) != STATUS_OP)\r                            {\r                                      for (std::string::iterator i = text.begin(); i != text.end(); i++)\r                                     {\r                                              switch (*i)\r                                            {\r                                                      case 2:\r                                                        case 3:\r                                                        case 15:\r                                                       case 21:\r                                                       case 22:\r                                                       case 31:\r                                                               user->WriteServ("404 %s %s :Can't send colours to channel (+c set)",user->nick, c->name);\r                                                              return 1;\r                                                      break;\r                                         }\r                                      }\r                              }\r                      }\r              }\r              return 0;\r      }\r      \r       virtual int OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)\r     {\r              return OnUserPreMessage(user,dest,target_type,text,status,exempt_list);\r        }\r\r     virtual ~ModuleBlockColour()\r   {\r              ServerInstance->Modes->DelMode(bc);\r            DELETE(bc);\r    }\r      \r       virtual Version GetVersion()\r   {\r              return Version(1,1,0,0,VF_COMMON|VF_VENDOR,API_VERSION);\r       }\r};\r\rMODULE_INIT(ModuleBlockColour)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+
+/* $ModDesc: Provides support for unreal-style channel mode +c */
+
+/** Handles the +c channel mode
+ */
+class BlockColor : public ModeHandler
+{
+ public:
+       BlockColor(InspIRCd* Instance) : ModeHandler(Instance, 'c', 0, 0, false, MODETYPE_CHANNEL, false) { }
+
+       ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)
+       {
+               if (adding)
+               {
+                       if (!channel->IsModeSet('c'))
+                       {
+                               channel->SetMode('c',true);
+                               return MODEACTION_ALLOW;
+                       }
+               }
+               else
+               {
+                       if (channel->IsModeSet('c'))
+                       {
+                               channel->SetMode('c',false);
+                               return MODEACTION_ALLOW;
+                       }
+               }
+
+               return MODEACTION_DENY;
+       }
+};
+
+class ModuleBlockColour : public Module
+{
+       bool AllowChanOps;      
+       BlockColor *bc;
+ public:
+       ModuleBlockColour(InspIRCd* Me) : Module(Me)
+       {
+               bc = new BlockColor(ServerInstance);
+               if (!ServerInstance->AddMode(bc, 'c'))
+                       throw ModuleException("Could not add new modes!");
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnUserPreMessage] = List[I_OnUserPreNotice] = 1;
+       }
+
+
+       virtual int OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
+       {
+               if ((target_type == TYPE_CHANNEL) && (IS_LOCAL(user)))
+               {
+                       chanrec* c = (chanrec*)dest;
+                       
+                       if(c->IsModeSet('c'))
+                       {
+                               if (!CHANOPS_EXEMPT(ServerInstance, 'c') || CHANOPS_EXEMPT(ServerInstance, 'c') && c->GetStatus(user) != STATUS_OP)
+                               {
+                                       for (std::string::iterator i = text.begin(); i != text.end(); i++)
+                                       {
+                                               switch (*i)
+                                               {
+                                                       case 2:
+                                                       case 3:
+                                                       case 15:
+                                                       case 21:
+                                                       case 22:
+                                                       case 31:
+                                                               user->WriteServ("404 %s %s :Can't send colours to channel (+c set)",user->nick, c->name);
+                                                               return 1;
+                                                       break;
+                                               }
+                                       }
+                               }
+                       }
+               }
+               return 0;
+       }
+       
+       virtual int OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
+       {
+               return OnUserPreMessage(user,dest,target_type,text,status,exempt_list);
+       }
+
+       virtual ~ModuleBlockColour()
+       {
+               ServerInstance->Modes->DelMode(bc);
+               DELETE(bc);
+       }
+       
+       virtual Version GetVersion()
+       {
+               return Version(1,1,0,0,VF_COMMON|VF_VENDOR,API_VERSION);
+       }
+};
+
+MODULE_INIT(ModuleBlockColour)
index 8cc999f12168dfd0aacb163bd77556500c512f6a..a6cad9577c3b8328cf0a6ff03cf5f1406f4ebf21 100644 (file)
@@ -1 +1,95 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include <stdio.h>\r#include <string>\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r#include "configreader.h"\r\r/* $ModDesc: Provides support for unreal-style umode +B */\r\r/** Handles user mode +B\r */\rclass BotMode : public ModeHandler\r{\r public:\r        BotMode(InspIRCd* Instance) : ModeHandler(Instance, 'B', 0, 0, false, MODETYPE_USER, false) { }\r\r       ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)\r {\r              if (adding)\r            {\r                      if (!dest->IsModeSet('B'))\r                     {\r                              dest->SetMode('B',true);\r                               return MODEACTION_ALLOW;\r                       }\r              }\r              else\r           {\r                      if (dest->IsModeSet('B'))\r                      {\r                              dest->SetMode('B',false);\r                              return MODEACTION_ALLOW;\r                       }\r              }\r              \r               return MODEACTION_DENY;\r        }\r};\r\rclass ModuleBotMode : public Module\r{\r    \r       BotMode* bm;\r public:\r  ModuleBotMode(InspIRCd* Me)\r            : Module(Me)\r   {\r              \r               bm = new BotMode(ServerInstance);\r              if (!ServerInstance->AddMode(bm, 'B'))\r                 throw ModuleException("Could not add new modes!");\r     }\r\r     void Implements(char* List)\r    {\r              List[I_OnWhois] = 1;\r   }\r      \r       virtual ~ModuleBotMode()\r       {\r              ServerInstance->Modes->DelMode(bm);\r            DELETE(bm);\r    }\r      \r       virtual Version GetVersion()\r   {\r              return Version(1,1,0,0,VF_COMMON|VF_VENDOR,API_VERSION);\r       }\r\r     virtual void OnWhois(userrec* src, userrec* dst)\r       {\r              if (dst->IsModeSet('B'))\r               {\r                      ServerInstance->SendWhoisLine(src, dst, 335, std::string(src->nick)+" "+std::string(dst->nick)+" :is a bot on "+ServerInstance->Config->Network);\r              }\r      }\r\r};\r\r\rMODULE_INIT(ModuleBotMode)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include <stdio.h>
+#include <string>
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+#include "configreader.h"
+
+/* $ModDesc: Provides support for unreal-style umode +B */
+
+/** Handles user mode +B
+ */
+class BotMode : public ModeHandler
+{
+ public:
+       BotMode(InspIRCd* Instance) : ModeHandler(Instance, 'B', 0, 0, false, MODETYPE_USER, false) { }
+
+       ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)
+       {
+               if (adding)
+               {
+                       if (!dest->IsModeSet('B'))
+                       {
+                               dest->SetMode('B',true);
+                               return MODEACTION_ALLOW;
+                       }
+               }
+               else
+               {
+                       if (dest->IsModeSet('B'))
+                       {
+                               dest->SetMode('B',false);
+                               return MODEACTION_ALLOW;
+                       }
+               }
+               
+               return MODEACTION_DENY;
+       }
+};
+
+class ModuleBotMode : public Module
+{
+       
+       BotMode* bm;
+ public:
+       ModuleBotMode(InspIRCd* Me)
+               : Module(Me)
+       {
+               
+               bm = new BotMode(ServerInstance);
+               if (!ServerInstance->AddMode(bm, 'B'))
+                       throw ModuleException("Could not add new modes!");
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnWhois] = 1;
+       }
+       
+       virtual ~ModuleBotMode()
+       {
+               ServerInstance->Modes->DelMode(bm);
+               DELETE(bm);
+       }
+       
+       virtual Version GetVersion()
+       {
+               return Version(1,1,0,0,VF_COMMON|VF_VENDOR,API_VERSION);
+       }
+
+       virtual void OnWhois(userrec* src, userrec* dst)
+       {
+               if (dst->IsModeSet('B'))
+               {
+                       ServerInstance->SendWhoisLine(src, dst, 335, std::string(src->nick)+" "+std::string(dst->nick)+" :is a bot on "+ServerInstance->Config->Network);
+               }
+       }
+
+};
+
+
+MODULE_INIT(ModuleBotMode)
index 65be0d9bbf261a3cb552a0e42ad943ebd3bf46f3..c8e6a86b913552757fe7941e61d3e48caf0b6534 100644 (file)
@@ -1 +1,251 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include <algorithm>\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r#include "configreader.h"\r\r/* $ModDesc: Gives /cban, aka C:lines. Think Q:lines, for channels. */\r\r/** Holds a CBAN item\r */\rclass CBan : public classbase\r{\rpublic:\r     irc::string chname;\r    std::string set_by;\r    time_t set_on;\r long length;\r   std::string reason;\r\r   CBan()\r {\r      }\r\r     CBan(irc::string cn, std::string sb, time_t so, long ln, std::string rs) : chname(cn), set_by(sb), set_on(so), length(ln), reason(rs)\r  {\r      }\r};\r\rbool CBanComp(const CBan &ban1, const CBan &ban2);\r\rtypedef std::vector<CBan> cbanlist;\r\r/* cbans is declared here, as our type is right above. Don't try move it. */\rcbanlist cbans;\r\r/** Handle /CBAN\r */\rclass cmd_cban : public command_t\r{\r public:\r cmd_cban(InspIRCd* Me) : command_t(Me, "CBAN", 'o', 1)\r {\r              this->source = "m_cban.so";\r            this->syntax = "<channel> [<duration> :<reason>]";\r     }\r\r     CmdResult Handle(const char** parameters, int pcnt, userrec *user)\r     {\r              /* syntax: CBAN #channel time :reason goes here */\r             /* 'time' is a human-readable timestring, like 2d3h2s. */\r\r             if(pcnt == 1)\r          {\r                      /* form: CBAN #channel removes a CBAN */\r                       for (cbanlist::iterator iter = cbans.begin(); iter != cbans.end(); iter++)\r                     {\r                              if (parameters[0] == iter->chname)\r                             {\r                                      long remaining = iter->length + ServerInstance->Time();\r                                        user->WriteServ("386 %s %s :Removed CBAN due to expire at %s (%s)", user->nick, iter->chname.c_str(), ServerInstance->TimeString(remaining).c_str(), iter->reason.c_str());\r                                    cbans.erase(iter);\r                                     break;\r                         }\r                      }\r              }\r              else if (pcnt >= 2)\r            {\r                      /* full form to add a CBAN */\r                  if (ServerInstance->IsChannel(parameters[0]))\r                  {\r                              // parameters[0] = #channel\r                            // parameters[1] = 1h3m2s\r                              // parameters[2] = Tortoise abuser\r                             long length = ServerInstance->Duration(parameters[1]);\r                         std::string reason = (pcnt > 2) ? parameters[2] : "No reason supplied";\r                                \r                               cbans.push_back(CBan(parameters[0], user->nick, ServerInstance->Time(), length, reason));\r                                      \r                               std::sort(cbans.begin(), cbans.end(), CBanComp);\r                               \r                               if(length > 0)\r                         {\r                                      user->WriteServ("385 %s %s :Added %lu second channel ban (%s)", user->nick, parameters[0], length, reason.c_str());\r                                    ServerInstance->WriteOpers("*** %s added %lu second channel ban on %s (%s)", user->nick, length, parameters[0], reason.c_str());\r                               }\r                              else\r                           {\r                                      user->WriteServ("385 %s %s :Added permanent channel ban (%s)", user->nick, parameters[0], reason.c_str());\r                                     ServerInstance->WriteOpers("*** %s added permanent channel ban on %s (%s)", user->nick, parameters[0], reason.c_str());\r                                }\r                      }\r                      else\r                   {\r                              user->WriteServ("403 %s %s :Invalid channel name", user->nick, parameters[0]);\r                         return CMD_FAILURE;\r                    }\r              }\r\r             /* we want this routed! */\r             return CMD_SUCCESS;\r    }\r};\r\rbool CBanComp(const CBan &ban1, const CBan &ban2)\r{\r      return ((ban1.set_on + ban1.length) < (ban2.set_on + ban2.length));\r}\r\rclass ModuleCBan : public Module\r{\r      cmd_cban* mycommand;\r   \r\r public:\r     ModuleCBan(InspIRCd* Me) : Module(Me)\r  {\r              \r               mycommand = new cmd_cban(Me);\r          ServerInstance->AddCommand(mycommand);\r }\r\r     void Implements(char* List)\r    {\r              List[I_OnUserPreJoin] = List[I_OnSyncOtherMetaData] = List[I_OnDecodeMetaData] = List[I_OnStats] = 1;\r  }\r      \r       virtual int OnStats(char symbol, userrec* user, string_list &results)\r  {\r              ExpireBans();\r  \r               if(symbol == 'C')\r              {\r                      for(cbanlist::iterator iter = cbans.begin(); iter != cbans.end(); iter++)\r                      {\r                              unsigned long remaining = (iter->set_on + iter->length) - ServerInstance->Time();\r                              results.push_back(std::string(ServerInstance->Config->ServerName)+" 210 "+user->nick+" "+iter->chname.c_str()+" "+iter->set_by+" "+ConvToStr(iter->set_on)+" "+ConvToStr(iter->length)+" "+ConvToStr(remaining)+" :"+iter->reason);\r                    }\r              }\r              \r               return 0;\r      }\r\r     virtual int OnUserPreJoin(userrec *user, chanrec *chan, const char *cname, std::string &privs)\r {\r              ExpireBans();\r  \r               /* check cbans in here, and apply as necessary. */\r             for(cbanlist::iterator iter = cbans.begin(); iter != cbans.end(); iter++)\r              {\r                      if(iter->chname == cname && !user->modes[UM_OPERATOR])\r                 {\r                              // Channel is banned.\r                          user->WriteServ( "384 %s %s :Cannot join channel, CBANed (%s)", user->nick, cname, iter->reason.c_str());\r                              ServerInstance->WriteOpers("*** %s tried to join %s which is CBANed (%s)", user->nick, cname, iter->reason.c_str());\r                           return 1;\r                      }\r              }\r              return 0;\r      }\r      \r       virtual void OnSyncOtherMetaData(Module* proto, void* opaque, bool displayable)\r        {\r              for(cbanlist::iterator iter = cbans.begin(); iter != cbans.end(); iter++)\r              {\r                      proto->ProtoSendMetaData(opaque, TYPE_OTHER, NULL, "cban", EncodeCBan(*iter));\r         }\r      }\r      \r       virtual void OnDecodeMetaData(int target_type, void* target, const std::string &extname, const std::string &extdata)\r   {\r              if((target_type == TYPE_OTHER) && (extname == "cban"))\r         {\r                      cbans.push_back(DecodeCBan(extdata));\r                  std::sort(cbans.begin(), cbans.end(), CBanComp);\r               }\r      }\r\r     virtual ~ModuleCBan()\r  {\r      }\r      \r       virtual Version GetVersion()\r   {\r              return Version(1,1,0,1,VF_VENDOR,API_VERSION);\r }\r\r     std::string EncodeCBan(const CBan &ban)\r        {\r              std::ostringstream stream;      \r               stream << ban.chname << " " << ban.set_by << " " << ban.set_on << " " << ban.length << " :" << ban.reason;\r             return stream.str();\r   }\r\r     CBan DecodeCBan(const std::string &data)\r       {\r              CBan res;\r              int set_on;\r            irc::tokenstream tokens(data);\r         tokens.GetToken(res.chname);\r           tokens.GetToken(res.set_by);\r           tokens.GetToken(set_on);\r               res.set_on = set_on;\r           tokens.GetToken(res.length);\r           tokens.GetToken(res.reason);\r           return res;\r    }\r\r     void ExpireBans()\r      {\r              bool go_again = true;\r\r         while (go_again)\r               {\r                      go_again = false;\r      \r                       for (cbanlist::iterator iter = cbans.begin(); iter != cbans.end(); iter++)\r                     {\r                              /* 0 == permanent, don't mess with them! -- w00t */\r                            if (iter->length != 0)\r                         {\r                                      if (iter->set_on + iter->length <= ServerInstance->Time())\r                                     {\r                                              ServerInstance->WriteOpers("*** %li second CBAN on %s (%s) set on %s expired", iter->length, iter->chname.c_str(), iter->reason.c_str(), ServerInstance->TimeString(iter->set_on).c_str());\r                                            cbans.erase(iter);\r                                             go_again = true;\r                                       }\r                              }\r      \r                               if (go_again == true)\r                                  break;\r                 }\r              }\r      }\r};\r\rMODULE_INIT(ModuleCBan)\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include <algorithm>
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+#include "configreader.h"
+
+/* $ModDesc: Gives /cban, aka C:lines. Think Q:lines, for channels. */
+
+/** Holds a CBAN item
+ */
+class CBan : public classbase
+{
+public:
+       irc::string chname;
+       std::string set_by;
+       time_t set_on;
+       long length;
+       std::string reason;
+
+       CBan()
+       {
+       }
+
+       CBan(irc::string cn, std::string sb, time_t so, long ln, std::string rs) : chname(cn), set_by(sb), set_on(so), length(ln), reason(rs)
+       {
+       }
+};
+
+bool CBanComp(const CBan &ban1, const CBan &ban2);
+
+typedef std::vector<CBan> cbanlist;
+
+/* cbans is declared here, as our type is right above. Don't try move it. */
+cbanlist cbans;
+
+/** Handle /CBAN
+ */
+class cmd_cban : public command_t
+{
+ public:
+       cmd_cban(InspIRCd* Me) : command_t(Me, "CBAN", 'o', 1)
+       {
+               this->source = "m_cban.so";
+               this->syntax = "<channel> [<duration> :<reason>]";
+       }
+
+       CmdResult Handle(const char** parameters, int pcnt, userrec *user)
+       {
+               /* syntax: CBAN #channel time :reason goes here */
+               /* 'time' is a human-readable timestring, like 2d3h2s. */
+
+               if(pcnt == 1)
+               {
+                       /* form: CBAN #channel removes a CBAN */
+                       for (cbanlist::iterator iter = cbans.begin(); iter != cbans.end(); iter++)
+                       {
+                               if (parameters[0] == iter->chname)
+                               {
+                                       long remaining = iter->length + ServerInstance->Time();
+                                       user->WriteServ("386 %s %s :Removed CBAN due to expire at %s (%s)", user->nick, iter->chname.c_str(), ServerInstance->TimeString(remaining).c_str(), iter->reason.c_str());
+                                       cbans.erase(iter);
+                                       break;
+                               }
+                       }
+               }
+               else if (pcnt >= 2)
+               {
+                       /* full form to add a CBAN */
+                       if (ServerInstance->IsChannel(parameters[0]))
+                       {
+                               // parameters[0] = #channel
+                               // parameters[1] = 1h3m2s
+                               // parameters[2] = Tortoise abuser
+                               long length = ServerInstance->Duration(parameters[1]);
+                               std::string reason = (pcnt > 2) ? parameters[2] : "No reason supplied";
+                               
+                               cbans.push_back(CBan(parameters[0], user->nick, ServerInstance->Time(), length, reason));
+                                       
+                               std::sort(cbans.begin(), cbans.end(), CBanComp);
+                               
+                               if(length > 0)
+                               {
+                                       user->WriteServ("385 %s %s :Added %lu second channel ban (%s)", user->nick, parameters[0], length, reason.c_str());
+                                       ServerInstance->WriteOpers("*** %s added %lu second channel ban on %s (%s)", user->nick, length, parameters[0], reason.c_str());
+                               }
+                               else
+                               {
+                                       user->WriteServ("385 %s %s :Added permanent channel ban (%s)", user->nick, parameters[0], reason.c_str());
+                                       ServerInstance->WriteOpers("*** %s added permanent channel ban on %s (%s)", user->nick, parameters[0], reason.c_str());
+                               }
+                       }
+                       else
+                       {
+                               user->WriteServ("403 %s %s :Invalid channel name", user->nick, parameters[0]);
+                               return CMD_FAILURE;
+                       }
+               }
+
+               /* we want this routed! */
+               return CMD_SUCCESS;
+       }
+};
+
+bool CBanComp(const CBan &ban1, const CBan &ban2)
+{
+       return ((ban1.set_on + ban1.length) < (ban2.set_on + ban2.length));
+}
+
+class ModuleCBan : public Module
+{
+       cmd_cban* mycommand;
+       
+
+ public:
+       ModuleCBan(InspIRCd* Me) : Module(Me)
+       {
+               
+               mycommand = new cmd_cban(Me);
+               ServerInstance->AddCommand(mycommand);
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnUserPreJoin] = List[I_OnSyncOtherMetaData] = List[I_OnDecodeMetaData] = List[I_OnStats] = 1;
+       }
+       
+       virtual int OnStats(char symbol, userrec* user, string_list &results)
+       {
+               ExpireBans();
+       
+               if(symbol == 'C')
+               {
+                       for(cbanlist::iterator iter = cbans.begin(); iter != cbans.end(); iter++)
+                       {
+                               unsigned long remaining = (iter->set_on + iter->length) - ServerInstance->Time();
+                               results.push_back(std::string(ServerInstance->Config->ServerName)+" 210 "+user->nick+" "+iter->chname.c_str()+" "+iter->set_by+" "+ConvToStr(iter->set_on)+" "+ConvToStr(iter->length)+" "+ConvToStr(remaining)+" :"+iter->reason);
+                       }
+               }
+               
+               return 0;
+       }
+
+       virtual int OnUserPreJoin(userrec *user, chanrec *chan, const char *cname, std::string &privs)
+       {
+               ExpireBans();
+       
+               /* check cbans in here, and apply as necessary. */
+               for(cbanlist::iterator iter = cbans.begin(); iter != cbans.end(); iter++)
+               {
+                       if(iter->chname == cname && !user->modes[UM_OPERATOR])
+                       {
+                               // Channel is banned.
+                               user->WriteServ( "384 %s %s :Cannot join channel, CBANed (%s)", user->nick, cname, iter->reason.c_str());
+                               ServerInstance->WriteOpers("*** %s tried to join %s which is CBANed (%s)", user->nick, cname, iter->reason.c_str());
+                               return 1;
+                       }
+               }
+               return 0;
+       }
+       
+       virtual void OnSyncOtherMetaData(Module* proto, void* opaque, bool displayable)
+       {
+               for(cbanlist::iterator iter = cbans.begin(); iter != cbans.end(); iter++)
+               {
+                       proto->ProtoSendMetaData(opaque, TYPE_OTHER, NULL, "cban", EncodeCBan(*iter));
+               }
+       }
+       
+       virtual void OnDecodeMetaData(int target_type, void* target, const std::string &extname, const std::string &extdata)
+       {
+               if((target_type == TYPE_OTHER) && (extname == "cban"))
+               {
+                       cbans.push_back(DecodeCBan(extdata));
+                       std::sort(cbans.begin(), cbans.end(), CBanComp);
+               }
+       }
+
+       virtual ~ModuleCBan()
+       {
+       }
+       
+       virtual Version GetVersion()
+       {
+               return Version(1,1,0,1,VF_VENDOR,API_VERSION);
+       }
+
+       std::string EncodeCBan(const CBan &ban)
+       {
+               std::ostringstream stream;      
+               stream << ban.chname << " " << ban.set_by << " " << ban.set_on << " " << ban.length << " :" << ban.reason;
+               return stream.str();
+       }
+
+       CBan DecodeCBan(const std::string &data)
+       {
+               CBan res;
+               int set_on;
+               irc::tokenstream tokens(data);
+               tokens.GetToken(res.chname);
+               tokens.GetToken(res.set_by);
+               tokens.GetToken(set_on);
+               res.set_on = set_on;
+               tokens.GetToken(res.length);
+               tokens.GetToken(res.reason);
+               return res;
+       }
+
+       void ExpireBans()
+       {
+               bool go_again = true;
+
+               while (go_again)
+               {
+                       go_again = false;
+       
+                       for (cbanlist::iterator iter = cbans.begin(); iter != cbans.end(); iter++)
+                       {
+                               /* 0 == permanent, don't mess with them! -- w00t */
+                               if (iter->length != 0)
+                               {
+                                       if (iter->set_on + iter->length <= ServerInstance->Time())
+                                       {
+                                               ServerInstance->WriteOpers("*** %li second CBAN on %s (%s) set on %s expired", iter->length, iter->chname.c_str(), iter->reason.c_str(), ServerInstance->TimeString(iter->set_on).c_str());
+                                               cbans.erase(iter);
+                                               go_again = true;
+                                       }
+                               }
+       
+                               if (go_again == true)
+                                       break;
+                       }
+               }
+       }
+};
+
+MODULE_INIT(ModuleCBan)
+
index a7aa2f8b13fe691a45afad70b552114ef655a324..f4a5bd620e32f18ae18c27fac7f04786157ceda0 100644 (file)
@@ -1 +1,196 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#define _CRT_SECURE_NO_DEPRECATE\r#define _SCL_SECURE_NO_DEPRECATE\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r\rtypedef std::map<irc::string,irc::string> censor_t;\r\r/* $ModDesc: Provides user and channel +G mode */\r\r/** Handles usermode +G\r */\rclass CensorUser : public ModeHandler\r{\r public:\r      CensorUser(InspIRCd* Instance) : ModeHandler(Instance, 'G', 0, 0, false, MODETYPE_USER, false) { }\r\r    ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)\r {\r              if (adding)\r            {\r                      if (!dest->IsModeSet('G'))\r                     {\r                              dest->SetMode('G',true);\r                               return MODEACTION_ALLOW;\r                       }\r              }\r              else\r           {\r                      if (dest->IsModeSet('G'))\r                      {\r                              dest->SetMode('G',false);\r                              return MODEACTION_ALLOW;\r                       }\r              }\r\r             return MODEACTION_DENY;\r        }\r};\r\r/** Handles channel mode +G\r */\rclass CensorChannel : public ModeHandler\r{\r public:\r      CensorChannel(InspIRCd* Instance) : ModeHandler(Instance, 'G', 0, 0, false, MODETYPE_CHANNEL, false) { }\r\r      ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)\r {\r              if (adding)\r            {\r                      if (!channel->IsModeSet('G'))\r                  {\r                              channel->SetMode('G',true);\r                            return MODEACTION_ALLOW;\r                       }\r              }\r              else\r           {\r                      if (channel->IsModeSet('G'))\r                   {\r                              channel->SetMode('G',false);\r                           return MODEACTION_ALLOW;\r                       }\r              }\r\r             return MODEACTION_ALLOW;\r       }\r};\r\rclass ModuleCensor : public Module\r{\r\r    \r       censor_t censors;\r      CensorUser *cu;\r        CensorChannel *cc;\r \r public:\r  ModuleCensor(InspIRCd* Me)\r             : Module(Me)\r   {\r              /* Read the configuration file on startup.\r              */\r            OnRehash(NULL,"");\r             cu = new CensorUser(ServerInstance);\r           cc = new CensorChannel(ServerInstance);\r                if (!ServerInstance->AddMode(cu, 'G') || !ServerInstance->AddMode(cc, 'G'))\r                    throw ModuleException("Could not add new modes!");\r     }\r\r     void Implements(char* List)\r    {\r              List[I_OnRehash] = List[I_OnUserPreMessage] = List[I_OnUserPreNotice] = 1;\r     }\r\r     virtual ~ModuleCensor()\r        {\r              ServerInstance->Modes->DelMode(cu);\r            ServerInstance->Modes->DelMode(cc);\r            DELETE(cu);\r            DELETE(cc);\r    }\r\r     virtual void ReplaceLine(irc::string &text, irc::string pattern, irc::string replace)\r  {\r              if ((!pattern.empty()) && (!text.empty()))\r             {\r                      std::string::size_type pos;\r                    while ((pos = text.find(pattern)) != irc::string::npos)\r                        {\r                              text.erase(pos,pattern.length());\r                              text.insert(pos,replace);\r                      }\r              }\r      }\r\r     // format of a config entry is <badword text="shit" replace="poo">\r     virtual int OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)\r    {\r              if (!IS_LOCAL(user))\r                   return 0;\r\r             bool active = false;\r\r          if (target_type == TYPE_USER)\r                  active = ((userrec*)dest)->IsModeSet('G');\r             else if (target_type == TYPE_CHANNEL)\r                  active = ((chanrec*)dest)->IsModeSet('G');\r\r            if (!active)\r                   return 0;\r\r             irc::string text2 = text.c_str();\r              for (censor_t::iterator index = censors.begin(); index != censors.end(); index++)\r              { \r                     if (text2.find(index->first) != irc::string::npos)\r                     {\r                              if (index->second.empty())\r                             {\r                                      user->WriteServ("936 %s %s %s :Your message contained a censored word, and was blocked", user->nick, ((chanrec*)dest)->name, index->first.c_str());\r                                    return 1;\r                              }\r                              \r                               this->ReplaceLine(text2,index->first,index->second);\r                   }\r              }\r              text = text2.c_str();\r          return 0;\r      }\r      \r       virtual int OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)\r     {\r              return OnUserPreMessage(user,dest,target_type,text,status,exempt_list);\r        }\r      \r       virtual void OnRehash(userrec* user, const std::string &parameter)\r     {\r              /*\r              * reload our config file on rehash - we must destroy and re-allocate the classes\r               * to call the constructor again and re-read our data.\r          */\r            ConfigReader* MyConf = new ConfigReader(ServerInstance);\r               censors.clear();\r               for (int index = 0; index < MyConf->Enumerate("badword"); index++)\r             {\r                      irc::string pattern = (MyConf->ReadValue("badword","text",index)).c_str();\r                     irc::string replace = (MyConf->ReadValue("badword","replace",index)).c_str();\r                  censors[pattern] = replace;\r            }\r              DELETE(MyConf);\r        }\r      \r       virtual Version GetVersion()\r   {\r              return Version(1,1,0,0,VF_COMMON|VF_VENDOR,API_VERSION);\r       }\r      \r};\r\rMODULE_INIT(ModuleCensor)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#define _CRT_SECURE_NO_DEPRECATE
+#define _SCL_SECURE_NO_DEPRECATE
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+
+typedef std::map<irc::string,irc::string> censor_t;
+
+/* $ModDesc: Provides user and channel +G mode */
+
+/** Handles usermode +G
+ */
+class CensorUser : public ModeHandler
+{
+ public:
+       CensorUser(InspIRCd* Instance) : ModeHandler(Instance, 'G', 0, 0, false, MODETYPE_USER, false) { }
+
+       ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)
+       {
+               if (adding)
+               {
+                       if (!dest->IsModeSet('G'))
+                       {
+                               dest->SetMode('G',true);
+                               return MODEACTION_ALLOW;
+                       }
+               }
+               else
+               {
+                       if (dest->IsModeSet('G'))
+                       {
+                               dest->SetMode('G',false);
+                               return MODEACTION_ALLOW;
+                       }
+               }
+
+               return MODEACTION_DENY;
+       }
+};
+
+/** Handles channel mode +G
+ */
+class CensorChannel : public ModeHandler
+{
+ public:
+       CensorChannel(InspIRCd* Instance) : ModeHandler(Instance, 'G', 0, 0, false, MODETYPE_CHANNEL, false) { }
+
+       ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)
+       {
+               if (adding)
+               {
+                       if (!channel->IsModeSet('G'))
+                       {
+                               channel->SetMode('G',true);
+                               return MODEACTION_ALLOW;
+                       }
+               }
+               else
+               {
+                       if (channel->IsModeSet('G'))
+                       {
+                               channel->SetMode('G',false);
+                               return MODEACTION_ALLOW;
+                       }
+               }
+
+               return MODEACTION_ALLOW;
+       }
+};
+
+class ModuleCensor : public Module
+{
+
+       
+       censor_t censors;
+       CensorUser *cu;
+       CensorChannel *cc;
+ public:
+       ModuleCensor(InspIRCd* Me)
+               : Module(Me)
+       {
+               /* Read the configuration file on startup.
+                */
+               OnRehash(NULL,"");
+               cu = new CensorUser(ServerInstance);
+               cc = new CensorChannel(ServerInstance);
+               if (!ServerInstance->AddMode(cu, 'G') || !ServerInstance->AddMode(cc, 'G'))
+                       throw ModuleException("Could not add new modes!");
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnRehash] = List[I_OnUserPreMessage] = List[I_OnUserPreNotice] = 1;
+       }
+
+       virtual ~ModuleCensor()
+       {
+               ServerInstance->Modes->DelMode(cu);
+               ServerInstance->Modes->DelMode(cc);
+               DELETE(cu);
+               DELETE(cc);
+       }
+
+       virtual void ReplaceLine(irc::string &text, irc::string pattern, irc::string replace)
+       {
+               if ((!pattern.empty()) && (!text.empty()))
+               {
+                       std::string::size_type pos;
+                       while ((pos = text.find(pattern)) != irc::string::npos)
+                       {
+                               text.erase(pos,pattern.length());
+                               text.insert(pos,replace);
+                       }
+               }
+       }
+
+       // format of a config entry is <badword text="shit" replace="poo">
+       virtual int OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
+       {
+               if (!IS_LOCAL(user))
+                       return 0;
+
+               bool active = false;
+
+               if (target_type == TYPE_USER)
+                       active = ((userrec*)dest)->IsModeSet('G');
+               else if (target_type == TYPE_CHANNEL)
+                       active = ((chanrec*)dest)->IsModeSet('G');
+
+               if (!active)
+                       return 0;
+
+               irc::string text2 = text.c_str();
+               for (censor_t::iterator index = censors.begin(); index != censors.end(); index++)
+               { 
+                       if (text2.find(index->first) != irc::string::npos)
+                       {
+                               if (index->second.empty())
+                               {
+                                       user->WriteServ("936 %s %s %s :Your message contained a censored word, and was blocked", user->nick, ((chanrec*)dest)->name, index->first.c_str());
+                                       return 1;
+                               }
+                               
+                               this->ReplaceLine(text2,index->first,index->second);
+                       }
+               }
+               text = text2.c_str();
+               return 0;
+       }
+       
+       virtual int OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
+       {
+               return OnUserPreMessage(user,dest,target_type,text,status,exempt_list);
+       }
+       
+       virtual void OnRehash(userrec* user, const std::string &parameter)
+       {
+               /*
+                * reload our config file on rehash - we must destroy and re-allocate the classes
+                * to call the constructor again and re-read our data.
+                */
+               ConfigReader* MyConf = new ConfigReader(ServerInstance);
+               censors.clear();
+               for (int index = 0; index < MyConf->Enumerate("badword"); index++)
+               {
+                       irc::string pattern = (MyConf->ReadValue("badword","text",index)).c_str();
+                       irc::string replace = (MyConf->ReadValue("badword","replace",index)).c_str();
+                       censors[pattern] = replace;
+               }
+               DELETE(MyConf);
+       }
+       
+       virtual Version GetVersion()
+       {
+               return Version(1,1,0,0,VF_COMMON|VF_VENDOR,API_VERSION);
+       }
+       
+};
+
+MODULE_INIT(ModuleCensor)
index 64fd6c69fb6ee062b89bb47dc3fdf6803ec8c98f..290f55d22df63cbf0203e76e1abc4a09acf500f9 100644 (file)
@@ -1 +1,511 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "modules.h"\r#include "dns.h"\r#ifndef WINDOWS\r#include <sys/socket.h>\r#include <netinet/in.h>\r#include <arpa/inet.h>\r#endif\r\r/* $ModDesc: Change user's hosts connecting from known CGI:IRC hosts */\r\renum CGItype { PASS, IDENT, PASSFIRST, IDENTFIRST, WEBIRC };\r\r\r/** Holds a CGI site's details\r */\rclass CGIhost : public classbase\r{\rpublic:\r       std::string hostmask;\r  CGItype type;\r  std::string password;\r\r CGIhost(const std::string &mask = "", CGItype t = IDENTFIRST, const std::string &password ="")\r : hostmask(mask), type(t), password(password)\r  {\r      }\r};\rtypedef std::vector<CGIhost> CGIHostlist;\r\rclass cmd_webirc : public command_t\r{\r  InspIRCd* Me;\r  CGIHostlist Hosts;\r     bool notify;\r   public:\r                cmd_webirc(InspIRCd* Me, CGIHostlist &Hosts, bool notify) : command_t(Me, "WEBIRC", 0, 4, true), Hosts(Hosts), notify(notify)\r          {\r                      this->source = "m_cgiirc.so";\r                  this->syntax = "password client hostname ip";\r          }\r              CmdResult Handle(const char** parameters, int pcnt, userrec *user)\r             {\r                      if(user->registered == REG_ALL)\r                                return CMD_FAILURE;\r                    \r                       for(CGIHostlist::iterator iter = Hosts.begin(); iter != Hosts.end(); iter++)\r                   {\r                              if(ServerInstance->MatchText(user->host, iter->hostmask) || ServerInstance->MatchText(user->GetIPString(), iter->hostmask))\r                            {\r                                      if(iter->type == WEBIRC && parameters[0] == iter->password)\r                                    {\r                                              user->Extend("cgiirc_realhost", new std::string(user->host));\r                                          user->Extend("cgiirc_realip", new std::string(user->GetIPString()));\r                                           if (notify)\r                                                    ServerInstance->WriteOpers("*** Connecting user %s detected as using CGI:IRC (%s), changing real host to %s from %s", user->nick, user->host, parameters[2], user->host);\r                                              user->Extend("cgiirc_webirc_hostname", new std::string(parameters[2]));\r                                                user->Extend("cgiirc_webirc_ip", new std::string(parameters[3]));\r                                              return CMD_LOCALONLY;\r                                  }\r                              }\r                      }\r                      return CMD_FAILURE;\r            }\r};\r\r\r/** Resolver for CGI:IRC hostnames encoded in ident/GECOS\r */\rclass CGIResolver : public Resolver\r{\r     std::string typ;\r       int theirfd;\r   userrec* them;\r bool notify;\r public:\r  CGIResolver(Module* me, InspIRCd* ServerInstance, bool NotifyOpers, const std::string &source, bool forward, userrec* u, int userfd, const std::string &type, bool &cached)\r            : Resolver(ServerInstance, source, forward ? DNS_QUERY_A : DNS_QUERY_PTR4, cached, me), typ(type), theirfd(userfd), them(u), notify(NotifyOpers) { }\r\r  virtual void OnLookupComplete(const std::string &result, unsigned int ttl, bool cached)\r        {\r              /* Check the user still exists */\r              if ((them) && (them == ServerInstance->SE->GetRef(theirfd)))\r           {\r                      if (notify)\r                            ServerInstance->WriteOpers("*** Connecting user %s detected as using CGI:IRC (%s), changing real host to %s from %s", them->nick, them->host, result.c_str(), typ.c_str());\r\r                   strlcpy(them->host, result.c_str(), 63);\r                       strlcpy(them->dhost, result.c_str(), 63);\r                      strlcpy(them->ident, "~cgiirc", 8);\r                    them->InvalidateCache();\r               }\r      }\r\r     virtual void OnError(ResolverError e, const std::string &errormessage)\r {\r              if ((them) && (them == ServerInstance->SE->GetRef(theirfd)))\r           {\r                      if (notify)\r                            ServerInstance->WriteOpers("*** Connecting user %s detected as using CGI:IRC (%s), but their host can't be resolved from their %s!", them->nick, them->host,typ.c_str());\r              }\r      }\r\r     virtual ~CGIResolver()\r {\r      }\r};\r\rclass ModuleCgiIRC : public Module\r{\r     cmd_webirc* mycommand;\r bool NotifyOpers;\r      CGIHostlist Hosts;\rpublic:\r     ModuleCgiIRC(InspIRCd* Me) : Module(Me)\r        {\r              \r               OnRehash(NULL,"");\r             mycommand=new cmd_webirc(Me, Hosts, NotifyOpers);\r              ServerInstance->AddCommand(mycommand);\r }\r\r     void Implements(char* List)\r    {\r              List[I_OnRehash] = List[I_OnUserRegister] = List[I_OnCleanup] = List[I_OnSyncUserMetaData] = List[I_OnDecodeMetaData] = List[I_OnUserQuit] = List[I_OnUserConnect] = 1;\r        }\r      \r       virtual Priority Prioritize()\r  {\r              // We want to get here before m_cloaking and m_hostchange etc\r          return PRIORITY_FIRST;\r }\r\r     virtual void OnRehash(userrec* user, const std::string &parameter)\r     {\r              ConfigReader Conf(ServerInstance);\r             \r               NotifyOpers = Conf.ReadFlag("cgiirc", "opernotice", 0); // If we send an oper notice when a CGI:IRC has their host changed.\r            \r               if(Conf.GetError() == CONF_VALUE_NOT_FOUND)\r                    NotifyOpers = true;\r            \r               for(int i = 0; i < Conf.Enumerate("cgihost"); i++)\r             {\r                      std::string hostmask = Conf.ReadValue("cgihost", "mask", i); // An allowed CGI:IRC host\r                        std::string type = Conf.ReadValue("cgihost", "type", i); // What type of user-munging we do on this host.\r                      std::string password = Conf.ReadValue("cgihost", "password", i);\r                       \r                       if(hostmask.length())\r                  {\r                              if(type == "webirc" && !password.length()) {\r                                           ServerInstance->Log(DEFAULT, "m_cgiirc: Missing password in config: %s", hostmask.c_str());\r                            } else {\r                                       CGItype cgitype;\r                                       if(type == "pass")\r                                             cgitype = PASS;\r                                        else if(type == "ident")\r                                               cgitype = IDENT;\r                                       else if(type == "passfirst")\r                                           cgitype = PASSFIRST;\r                                   else if(type == "webirc") {\r                                            cgitype = WEBIRC;\r                                      }\r                                      Hosts.push_back(CGIhost(hostmask,cgitype, password.length() ? password : "" ));\r                                }\r                      }\r                      else\r                   {\r                              ServerInstance->Log(DEFAULT, "m_cgiirc.so: Invalid <cgihost:mask> value in config: %s", hostmask.c_str());\r                             continue;\r                      }\r              }\r      }\r\r     virtual void OnCleanup(int target_type, void* item)\r    {\r              if(target_type == TYPE_USER)\r           {\r                      userrec* user = (userrec*)item;\r                        std::string* realhost;\r                 std::string* realip;\r                   \r                       if(user->GetExt("cgiirc_realhost", realhost))\r                  {\r                              delete realhost;\r                               user->Shrink("cgiirc_realhost");\r                       }\r                      \r                       if(user->GetExt("cgiirc_realip", realip))\r                      {\r                              delete realip;\r                         user->Shrink("cgiirc_realip");\r                 }\r              }\r      }\r      \r       virtual void OnSyncUserMetaData(userrec* user, Module* proto, void* opaque, const std::string &extname, bool displayable)\r      {\r              if((extname == "cgiirc_realhost") || (extname == "cgiirc_realip"))\r             {\r                      std::string* data;\r                     \r                       if(user->GetExt(extname, data))\r                        {\r                              proto->ProtoSendMetaData(opaque, TYPE_USER, user, extname, *data);\r                     }\r              }\r      }\r\r     virtual void OnDecodeMetaData(int target_type, void* target, const std::string &extname, const std::string &extdata)\r   {\r              if(target_type == TYPE_USER)\r           {\r                      userrec* dest = (userrec*)target;\r                      std::string* bleh;\r                     if(((extname == "cgiirc_realhost") || (extname == "cgiirc_realip")) && (!dest->GetExt(extname, bleh)))\r                 {\r                              dest->Extend(extname, new std::string(extdata));\r                       }\r              }\r      }\r\r     virtual void OnUserQuit(userrec* user, const std::string &message, const std::string &oper_message)\r    {\r              OnCleanup(TYPE_USER, user);\r    }\r      \r\r      virtual int OnUserRegister(userrec* user)\r      {       \r               for(CGIHostlist::iterator iter = Hosts.begin(); iter != Hosts.end(); iter++)\r           {                       \r                       if(ServerInstance->MatchText(user->host, iter->hostmask) || ServerInstance->MatchText(user->GetIPString(), iter->hostmask))\r                    {\r                              // Deal with it...\r                             if(iter->type == PASS)\r                         {\r                                      CheckPass(user); // We do nothing if it fails so...\r                            }\r                              else if(iter->type == PASSFIRST && !CheckPass(user))\r                           {\r                                      // If the password lookup failed, try the ident\r                                        CheckIdent(user);       // If this fails too, do nothing\r                               }\r                              else if(iter->type == IDENT)\r                           {\r                                      CheckIdent(user); // Nothing on failure.\r                               }\r                              else if(iter->type == IDENTFIRST && !CheckIdent(user))\r                         {\r                                      // If the ident lookup fails, try the password.\r                                        CheckPass(user);\r                               }\r                              else if(iter->type == WEBIRC)\r                          {\r                                      // We don't need to do anything here\r                           }\r                              return 0;\r                      }\r              }\r              return 0;\r      }\r\r     virtual void OnUserConnect(userrec* user)\r      {\r              std::string *webirc_hostname, *webirc_ip;\r              if(user->GetExt("cgiirc_webirc_hostname", webirc_hostname))\r            {\r                      strlcpy(user->host,webirc_hostname->c_str(),63);\r                       strlcpy(user->dhost,webirc_hostname->c_str(),63);\r                      delete webirc_hostname;\r                        user->InvalidateCache();\r                       user->Shrink("cgiirc_webirc_hostname");\r                }\r              if(user->GetExt("cgiirc_webirc_ip", webirc_ip))\r                {\r                      bool valid=false;\r                      user->RemoveCloneCounts();\r#ifdef IPV6\r                 valid = (inet_pton(AF_INET6, webirc_ip->c_str(), &((sockaddr_in6*)user->ip)->sin6_addr) > 0); \r\r                        if(!valid)\r                             valid = (inet_aton(webirc_ip->c_str(), &((sockaddr_in*)user->ip)->sin_addr));\r#else\r                    if (inet_aton(webirc_ip->c_str(), &((sockaddr_in*)user->ip)->sin_addr))\r                                valid = true;\r#endif\r\r                  delete webirc_ip;\r                      user->InvalidateCache();\r                       user->Shrink("cgiirc_webirc_ip");\r                      ServerInstance->AddLocalClone(user);\r                   ServerInstance->AddGlobalClone(user);\r                  user->CheckClass();\r            }\r      }\r\r     bool CheckPass(userrec* user)\r  {\r              if(IsValidHost(user->password))\r                {\r                      user->Extend("cgiirc_realhost", new std::string(user->host));\r                  user->Extend("cgiirc_realip", new std::string(user->GetIPString()));\r                   strlcpy(user->host, user->password, 64);\r                       strlcpy(user->dhost, user->password, 64);\r                      user->InvalidateCache();\r\r                      bool valid = false;\r                    user->RemoveCloneCounts();\r#ifdef IPV6\r                 if (user->GetProtocolFamily() == AF_INET6)\r                             valid = (inet_pton(AF_INET6, user->password, &((sockaddr_in6*)user->ip)->sin6_addr) > 0);\r                      else\r                           valid = (inet_aton(user->password, &((sockaddr_in*)user->ip)->sin_addr));\r#else\r                        if (inet_aton(user->password, &((sockaddr_in*)user->ip)->sin_addr))\r                            valid = true;\r#endif\r                   ServerInstance->AddLocalClone(user);\r                   ServerInstance->AddGlobalClone(user);\r                  user->CheckClass();\r\r                   if (valid)\r                     {\r                              /* We were given a IP in the password, we don't do DNS so they get this is as their host as well. */\r                           if(NotifyOpers)\r                                        ServerInstance->WriteOpers("*** Connecting user %s detected as using CGI:IRC (%s), changing real host to %s from PASS", user->nick, user->host, user->password);\r                       }\r                      else\r                   {\r                              /* We got as resolved hostname in the password. */\r                             try\r                            {\r\r                                     bool cached;\r                                   CGIResolver* r = new CGIResolver(this, ServerInstance, NotifyOpers, user->password, false, user, user->GetFd(), "PASS", cached);\r                                       ServerInstance->AddResolver(r, cached);\r                                }\r                              catch (...)\r                            {\r                                      if (NotifyOpers)\r                                               ServerInstance->WriteOpers("*** Connecting user %s detected as using CGI:IRC (%s), but i could not resolve their hostname!", user->nick, user->host);\r                          }\r                      }\r                      \r                       *user->password = 0;\r\r                  /*if(NotifyOpers)\r                              ServerInstance->WriteOpers("*** Connecting user %s detected as using CGI:IRC (%s), changing real host to %s from PASS", user->nick, user->host, user->password);*/\r\r                    return true;\r           }\r              \r               return false;\r  }\r      \r       bool CheckIdent(userrec* user)\r {\r              int ip[4];\r             char* ident;\r           char newip[16];\r                int len = strlen(user->ident);\r         \r               if(len == 8)\r                   ident = user->ident;\r           else if(len == 9 && *user->ident == '~')\r                       ident = user->ident+1;\r         else\r                   return false;\r  \r               for(int i = 0; i < 4; i++)\r                     if(!HexToInt(ip[i], ident + i*2))\r                              return false;\r\r         snprintf(newip, 16, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);\r                        \r               user->Extend("cgiirc_realhost", new std::string(user->host));\r          user->Extend("cgiirc_realip", new std::string(user->GetIPString()));\r           user->RemoveCloneCounts();\r#ifdef IPV6\r         if (user->GetProtocolFamily() == AF_INET6)\r                     inet_pton(AF_INET6, newip, &((sockaddr_in6*)user->ip)->sin6_addr);\r             else\r#endif\r            inet_aton(newip, &((sockaddr_in*)user->ip)->sin_addr);\r         ServerInstance->AddLocalClone(user);\r           ServerInstance->AddGlobalClone(user);\r          user->CheckClass();\r            try\r            {\r                      strlcpy(user->host, newip, 16);\r                        strlcpy(user->dhost, newip, 16);\r                       strlcpy(user->ident, "~cgiirc", 8);\r\r                   bool cached;\r                   CGIResolver* r = new CGIResolver(this, ServerInstance, NotifyOpers, newip, false, user, user->GetFd(), "IDENT", cached);\r                       ServerInstance->AddResolver(r, cached);\r                }\r              catch (...)\r            {\r                      strlcpy(user->host, newip, 16);\r                        strlcpy(user->dhost, newip, 16);\r                       strlcpy(user->ident, "~cgiirc", 8);\r                    user->InvalidateCache();\r\r                      if(NotifyOpers)\r                                 ServerInstance->WriteOpers("*** Connecting user %s detected as using CGI:IRC (%s), but i could not resolve their hostname!", user->nick, user->host);\r         }\r              /*strlcpy(user->host, newip, 16);\r              strlcpy(user->dhost, newip, 16);\r               strlcpy(user->ident, "~cgiirc", 8);*/\r\r         return true;\r   }\r      \r       bool IsValidHost(const std::string &host)\r      {\r              if(!host.size())\r                       return false;\r  \r               for(unsigned int i = 0; i < host.size(); i++)\r          {\r                      if(     ((host[i] >= '0') && (host[i] <= '9')) ||\r                                      ((host[i] >= 'A') && (host[i] <= 'Z')) ||\r                                      ((host[i] >= 'a') && (host[i] <= 'z')) ||\r                                      ((host[i] == '-') && (i > 0) && (i+1 < host.size()) && (host[i-1] != '.') && (host[i+1] != '.')) ||\r                                    ((host[i] == '.') && (i > 0) && (i+1 < host.size())) )\r                                 \r                               continue;\r                      else\r                           return false;\r          }\r              \r               return true;\r   }\r\r     bool IsValidIP(const std::string &ip)\r  {\r              if(ip.size() < 7 || ip.size() > 15)\r                    return false;\r  \r               short sincedot = 0;\r            short dots = 0;\r        \r               for(unsigned int i = 0; i < ip.size(); i++)\r            {\r                      if((dots <= 3) && (sincedot <= 3))\r                     {\r                              if((ip[i] >= '0') && (ip[i] <= '9'))\r                           {\r                                      sincedot++;\r                            }\r                              else if(ip[i] == '.')\r                          {\r                                      sincedot = 0;\r                                  dots++;\r                                }\r                      }\r                      else\r                   {\r                              return false;\r                  \r                       }\r              }\r              \r               if(dots != 3)\r                  return false;\r          \r               return true;\r   }\r      \r       bool HexToInt(int &out, const char* in)\r        {\r              char ip[3];\r            ip[0] = in[0];\r         ip[1] = in[1];\r         ip[2] = 0;\r             out = strtol(ip, NULL, 16);\r            \r               if(out > 255 || out < 0)\r                       return false;\r\r         return true;\r   }\r      \r       virtual ~ModuleCgiIRC()\r        {\r      }\r       \r      virtual Version GetVersion()\r   {\r              return Version(1,1,0,0,VF_VENDOR,API_VERSION);\r }\r      \r};\r\rMODULE_INIT(ModuleCgiIRC)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "modules.h"
+#include "dns.h"
+#ifndef WINDOWS
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#endif
+
+/* $ModDesc: Change user's hosts connecting from known CGI:IRC hosts */
+
+enum CGItype { PASS, IDENT, PASSFIRST, IDENTFIRST, WEBIRC };
+
+
+/** Holds a CGI site's details
+ */
+class CGIhost : public classbase
+{
+public:
+       std::string hostmask;
+       CGItype type;
+       std::string password;
+
+       CGIhost(const std::string &mask = "", CGItype t = IDENTFIRST, const std::string &password ="")
+       : hostmask(mask), type(t), password(password)
+       {
+       }
+};
+typedef std::vector<CGIhost> CGIHostlist;
+
+class cmd_webirc : public command_t
+{
+       InspIRCd* Me;
+       CGIHostlist Hosts;
+       bool notify;
+       public:
+               cmd_webirc(InspIRCd* Me, CGIHostlist &Hosts, bool notify) : command_t(Me, "WEBIRC", 0, 4, true), Hosts(Hosts), notify(notify)
+               {
+                       this->source = "m_cgiirc.so";
+                       this->syntax = "password client hostname ip";
+               }
+               CmdResult Handle(const char** parameters, int pcnt, userrec *user)
+               {
+                       if(user->registered == REG_ALL)
+                               return CMD_FAILURE;
+                       
+                       for(CGIHostlist::iterator iter = Hosts.begin(); iter != Hosts.end(); iter++)
+                       {
+                               if(ServerInstance->MatchText(user->host, iter->hostmask) || ServerInstance->MatchText(user->GetIPString(), iter->hostmask))
+                               {
+                                       if(iter->type == WEBIRC && parameters[0] == iter->password)
+                                       {
+                                               user->Extend("cgiirc_realhost", new std::string(user->host));
+                                               user->Extend("cgiirc_realip", new std::string(user->GetIPString()));
+                                               if (notify)
+                                                       ServerInstance->WriteOpers("*** Connecting user %s detected as using CGI:IRC (%s), changing real host to %s from %s", user->nick, user->host, parameters[2], user->host);
+                                               user->Extend("cgiirc_webirc_hostname", new std::string(parameters[2]));
+                                               user->Extend("cgiirc_webirc_ip", new std::string(parameters[3]));
+                                               return CMD_LOCALONLY;
+                                       }
+                               }
+                       }
+                       return CMD_FAILURE;
+               }
+};
+
+
+/** Resolver for CGI:IRC hostnames encoded in ident/GECOS
+ */
+class CGIResolver : public Resolver
+{
+       std::string typ;
+       int theirfd;
+       userrec* them;
+       bool notify;
+ public:
+       CGIResolver(Module* me, InspIRCd* ServerInstance, bool NotifyOpers, const std::string &source, bool forward, userrec* u, int userfd, const std::string &type, bool &cached)
+               : Resolver(ServerInstance, source, forward ? DNS_QUERY_A : DNS_QUERY_PTR4, cached, me), typ(type), theirfd(userfd), them(u), notify(NotifyOpers) { }
+
+       virtual void OnLookupComplete(const std::string &result, unsigned int ttl, bool cached)
+       {
+               /* Check the user still exists */
+               if ((them) && (them == ServerInstance->SE->GetRef(theirfd)))
+               {
+                       if (notify)
+                               ServerInstance->WriteOpers("*** Connecting user %s detected as using CGI:IRC (%s), changing real host to %s from %s", them->nick, them->host, result.c_str(), typ.c_str());
+
+                       strlcpy(them->host, result.c_str(), 63);
+                       strlcpy(them->dhost, result.c_str(), 63);
+                       strlcpy(them->ident, "~cgiirc", 8);
+                       them->InvalidateCache();
+               }
+       }
+
+       virtual void OnError(ResolverError e, const std::string &errormessage)
+       {
+               if ((them) && (them == ServerInstance->SE->GetRef(theirfd)))
+               {
+                       if (notify)
+                               ServerInstance->WriteOpers("*** Connecting user %s detected as using CGI:IRC (%s), but their host can't be resolved from their %s!", them->nick, them->host,typ.c_str());
+               }
+       }
+
+       virtual ~CGIResolver()
+       {
+       }
+};
+
+class ModuleCgiIRC : public Module
+{
+       cmd_webirc* mycommand;
+       bool NotifyOpers;
+       CGIHostlist Hosts;
+public:
+       ModuleCgiIRC(InspIRCd* Me) : Module(Me)
+       {
+               
+               OnRehash(NULL,"");
+               mycommand=new cmd_webirc(Me, Hosts, NotifyOpers);
+               ServerInstance->AddCommand(mycommand);
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnRehash] = List[I_OnUserRegister] = List[I_OnCleanup] = List[I_OnSyncUserMetaData] = List[I_OnDecodeMetaData] = List[I_OnUserQuit] = List[I_OnUserConnect] = 1;
+       }
+       
+       virtual Priority Prioritize()
+       {
+               // We want to get here before m_cloaking and m_hostchange etc
+               return PRIORITY_FIRST;
+       }
+
+       virtual void OnRehash(userrec* user, const std::string &parameter)
+       {
+               ConfigReader Conf(ServerInstance);
+               
+               NotifyOpers = Conf.ReadFlag("cgiirc", "opernotice", 0); // If we send an oper notice when a CGI:IRC has their host changed.
+               
+               if(Conf.GetError() == CONF_VALUE_NOT_FOUND)
+                       NotifyOpers = true;
+               
+               for(int i = 0; i < Conf.Enumerate("cgihost"); i++)
+               {
+                       std::string hostmask = Conf.ReadValue("cgihost", "mask", i); // An allowed CGI:IRC host
+                       std::string type = Conf.ReadValue("cgihost", "type", i); // What type of user-munging we do on this host.
+                       std::string password = Conf.ReadValue("cgihost", "password", i);
+                       
+                       if(hostmask.length())
+                       {
+                               if(type == "webirc" && !password.length()) {
+                                               ServerInstance->Log(DEFAULT, "m_cgiirc: Missing password in config: %s", hostmask.c_str());
+                               } else {
+                                       CGItype cgitype;
+                                       if(type == "pass")
+                                               cgitype = PASS;
+                                       else if(type == "ident")
+                                               cgitype = IDENT;
+                                       else if(type == "passfirst")
+                                               cgitype = PASSFIRST;
+                                       else if(type == "webirc") {
+                                               cgitype = WEBIRC;
+                                       }
+                                       Hosts.push_back(CGIhost(hostmask,cgitype, password.length() ? password : "" ));
+                               }
+                       }
+                       else
+                       {
+                               ServerInstance->Log(DEFAULT, "m_cgiirc.so: Invalid <cgihost:mask> value in config: %s", hostmask.c_str());
+                               continue;
+                       }
+               }
+       }
+
+       virtual void OnCleanup(int target_type, void* item)
+       {
+               if(target_type == TYPE_USER)
+               {
+                       userrec* user = (userrec*)item;
+                       std::string* realhost;
+                       std::string* realip;
+                       
+                       if(user->GetExt("cgiirc_realhost", realhost))
+                       {
+                               delete realhost;
+                               user->Shrink("cgiirc_realhost");
+                       }
+                       
+                       if(user->GetExt("cgiirc_realip", realip))
+                       {
+                               delete realip;
+                               user->Shrink("cgiirc_realip");
+                       }
+               }
+       }
+       
+       virtual void OnSyncUserMetaData(userrec* user, Module* proto, void* opaque, const std::string &extname, bool displayable)
+       {
+               if((extname == "cgiirc_realhost") || (extname == "cgiirc_realip"))
+               {
+                       std::string* data;
+                       
+                       if(user->GetExt(extname, data))
+                       {
+                               proto->ProtoSendMetaData(opaque, TYPE_USER, user, extname, *data);
+                       }
+               }
+       }
+
+       virtual void OnDecodeMetaData(int target_type, void* target, const std::string &extname, const std::string &extdata)
+       {
+               if(target_type == TYPE_USER)
+               {
+                       userrec* dest = (userrec*)target;
+                       std::string* bleh;
+                       if(((extname == "cgiirc_realhost") || (extname == "cgiirc_realip")) && (!dest->GetExt(extname, bleh)))
+                       {
+                               dest->Extend(extname, new std::string(extdata));
+                       }
+               }
+       }
+
+       virtual void OnUserQuit(userrec* user, const std::string &message, const std::string &oper_message)
+       {
+               OnCleanup(TYPE_USER, user);
+       }
+       
+
+       virtual int OnUserRegister(userrec* user)
+       {       
+               for(CGIHostlist::iterator iter = Hosts.begin(); iter != Hosts.end(); iter++)
+               {                       
+                       if(ServerInstance->MatchText(user->host, iter->hostmask) || ServerInstance->MatchText(user->GetIPString(), iter->hostmask))
+                       {
+                               // Deal with it...
+                               if(iter->type == PASS)
+                               {
+                                       CheckPass(user); // We do nothing if it fails so...
+                               }
+                               else if(iter->type == PASSFIRST && !CheckPass(user))
+                               {
+                                       // If the password lookup failed, try the ident
+                                       CheckIdent(user);       // If this fails too, do nothing
+                               }
+                               else if(iter->type == IDENT)
+                               {
+                                       CheckIdent(user); // Nothing on failure.
+                               }
+                               else if(iter->type == IDENTFIRST && !CheckIdent(user))
+                               {
+                                       // If the ident lookup fails, try the password.
+                                       CheckPass(user);
+                               }
+                               else if(iter->type == WEBIRC)
+                               {
+                                       // We don't need to do anything here
+                               }
+                               return 0;
+                       }
+               }
+               return 0;
+       }
+
+       virtual void OnUserConnect(userrec* user)
+       {
+               std::string *webirc_hostname, *webirc_ip;
+               if(user->GetExt("cgiirc_webirc_hostname", webirc_hostname))
+               {
+                       strlcpy(user->host,webirc_hostname->c_str(),63);
+                       strlcpy(user->dhost,webirc_hostname->c_str(),63);
+                       delete webirc_hostname;
+                       user->InvalidateCache();
+                       user->Shrink("cgiirc_webirc_hostname");
+               }
+               if(user->GetExt("cgiirc_webirc_ip", webirc_ip))
+               {
+                       bool valid=false;
+                       user->RemoveCloneCounts();
+#ifdef IPV6
+                       valid = (inet_pton(AF_INET6, webirc_ip->c_str(), &((sockaddr_in6*)user->ip)->sin6_addr) > 0); 
+
+                       if(!valid)
+                               valid = (inet_aton(webirc_ip->c_str(), &((sockaddr_in*)user->ip)->sin_addr));
+#else
+                       if (inet_aton(webirc_ip->c_str(), &((sockaddr_in*)user->ip)->sin_addr))
+                               valid = true;
+#endif
+
+                       delete webirc_ip;
+                       user->InvalidateCache();
+                       user->Shrink("cgiirc_webirc_ip");
+                       ServerInstance->AddLocalClone(user);
+                       ServerInstance->AddGlobalClone(user);
+                       user->CheckClass();
+               }
+       }
+
+       bool CheckPass(userrec* user)
+       {
+               if(IsValidHost(user->password))
+               {
+                       user->Extend("cgiirc_realhost", new std::string(user->host));
+                       user->Extend("cgiirc_realip", new std::string(user->GetIPString()));
+                       strlcpy(user->host, user->password, 64);
+                       strlcpy(user->dhost, user->password, 64);
+                       user->InvalidateCache();
+
+                       bool valid = false;
+                       user->RemoveCloneCounts();
+#ifdef IPV6
+                       if (user->GetProtocolFamily() == AF_INET6)
+                               valid = (inet_pton(AF_INET6, user->password, &((sockaddr_in6*)user->ip)->sin6_addr) > 0);
+                       else
+                               valid = (inet_aton(user->password, &((sockaddr_in*)user->ip)->sin_addr));
+#else
+                       if (inet_aton(user->password, &((sockaddr_in*)user->ip)->sin_addr))
+                               valid = true;
+#endif
+                       ServerInstance->AddLocalClone(user);
+                       ServerInstance->AddGlobalClone(user);
+                       user->CheckClass();
+
+                       if (valid)
+                       {
+                               /* We were given a IP in the password, we don't do DNS so they get this is as their host as well. */
+                               if(NotifyOpers)
+                                       ServerInstance->WriteOpers("*** Connecting user %s detected as using CGI:IRC (%s), changing real host to %s from PASS", user->nick, user->host, user->password);
+                       }
+                       else
+                       {
+                               /* We got as resolved hostname in the password. */
+                               try
+                               {
+
+                                       bool cached;
+                                       CGIResolver* r = new CGIResolver(this, ServerInstance, NotifyOpers, user->password, false, user, user->GetFd(), "PASS", cached);
+                                       ServerInstance->AddResolver(r, cached);
+                               }
+                               catch (...)
+                               {
+                                       if (NotifyOpers)
+                                               ServerInstance->WriteOpers("*** Connecting user %s detected as using CGI:IRC (%s), but i could not resolve their hostname!", user->nick, user->host);
+                               }
+                       }
+                       
+                       *user->password = 0;
+
+                       /*if(NotifyOpers)
+                               ServerInstance->WriteOpers("*** Connecting user %s detected as using CGI:IRC (%s), changing real host to %s from PASS", user->nick, user->host, user->password);*/
+
+                       return true;
+               }
+               
+               return false;
+       }
+       
+       bool CheckIdent(userrec* user)
+       {
+               int ip[4];
+               char* ident;
+               char newip[16];
+               int len = strlen(user->ident);
+               
+               if(len == 8)
+                       ident = user->ident;
+               else if(len == 9 && *user->ident == '~')
+                       ident = user->ident+1;
+               else
+                       return false;
+       
+               for(int i = 0; i < 4; i++)
+                       if(!HexToInt(ip[i], ident + i*2))
+                               return false;
+
+               snprintf(newip, 16, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
+                       
+               user->Extend("cgiirc_realhost", new std::string(user->host));
+               user->Extend("cgiirc_realip", new std::string(user->GetIPString()));
+               user->RemoveCloneCounts();
+#ifdef IPV6
+               if (user->GetProtocolFamily() == AF_INET6)
+                       inet_pton(AF_INET6, newip, &((sockaddr_in6*)user->ip)->sin6_addr);
+               else
+#endif
+               inet_aton(newip, &((sockaddr_in*)user->ip)->sin_addr);
+               ServerInstance->AddLocalClone(user);
+               ServerInstance->AddGlobalClone(user);
+               user->CheckClass();
+               try
+               {
+                       strlcpy(user->host, newip, 16);
+                       strlcpy(user->dhost, newip, 16);
+                       strlcpy(user->ident, "~cgiirc", 8);
+
+                       bool cached;
+                       CGIResolver* r = new CGIResolver(this, ServerInstance, NotifyOpers, newip, false, user, user->GetFd(), "IDENT", cached);
+                       ServerInstance->AddResolver(r, cached);
+               }
+               catch (...)
+               {
+                       strlcpy(user->host, newip, 16);
+                       strlcpy(user->dhost, newip, 16);
+                       strlcpy(user->ident, "~cgiirc", 8);
+                       user->InvalidateCache();
+
+                       if(NotifyOpers)
+                                ServerInstance->WriteOpers("*** Connecting user %s detected as using CGI:IRC (%s), but i could not resolve their hostname!", user->nick, user->host);
+               }
+               /*strlcpy(user->host, newip, 16);
+               strlcpy(user->dhost, newip, 16);
+               strlcpy(user->ident, "~cgiirc", 8);*/
+
+               return true;
+       }
+       
+       bool IsValidHost(const std::string &host)
+       {
+               if(!host.size())
+                       return false;
+       
+               for(unsigned int i = 0; i < host.size(); i++)
+               {
+                       if(     ((host[i] >= '0') && (host[i] <= '9')) ||
+                                       ((host[i] >= 'A') && (host[i] <= 'Z')) ||
+                                       ((host[i] >= 'a') && (host[i] <= 'z')) ||
+                                       ((host[i] == '-') && (i > 0) && (i+1 < host.size()) && (host[i-1] != '.') && (host[i+1] != '.')) ||
+                                       ((host[i] == '.') && (i > 0) && (i+1 < host.size())) )
+                                       
+                               continue;
+                       else
+                               return false;
+               }
+               
+               return true;
+       }
+
+       bool IsValidIP(const std::string &ip)
+       {
+               if(ip.size() < 7 || ip.size() > 15)
+                       return false;
+       
+               short sincedot = 0;
+               short dots = 0;
+       
+               for(unsigned int i = 0; i < ip.size(); i++)
+               {
+                       if((dots <= 3) && (sincedot <= 3))
+                       {
+                               if((ip[i] >= '0') && (ip[i] <= '9'))
+                               {
+                                       sincedot++;
+                               }
+                               else if(ip[i] == '.')
+                               {
+                                       sincedot = 0;
+                                       dots++;
+                               }
+                       }
+                       else
+                       {
+                               return false;
+                       
+                       }
+               }
+               
+               if(dots != 3)
+                       return false;
+               
+               return true;
+       }
+       
+       bool HexToInt(int &out, const char* in)
+       {
+               char ip[3];
+               ip[0] = in[0];
+               ip[1] = in[1];
+               ip[2] = 0;
+               out = strtol(ip, NULL, 16);
+               
+               if(out > 255 || out < 0)
+                       return false;
+
+               return true;
+       }
+       
+       virtual ~ModuleCgiIRC()
+       {
+       }
+        
+       virtual Version GetVersion()
+       {
+               return Version(1,1,0,0,VF_VENDOR,API_VERSION);
+       }
+       
+};
+
+MODULE_INIT(ModuleCgiIRC)
index 8837db9c59bf4751cf8f871d0a1582a4d12e4838..915e7c8cbad99106e6de3a8e5f61be392425a7b1 100644 (file)
@@ -1 +1,55 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r\r/* $ModDesc: Creates a snomask with notices whenever a new channel is created */\r\rclass ModuleChanCreate : public Module\r{\r private:\r public:\r        ModuleChanCreate(InspIRCd* Me)\r         : Module(Me)\r   {\r              ServerInstance->SNO->EnableSnomask('j', "CHANCREATE");\r }\r      \r       virtual ~ModuleChanCreate()\r    {\r              ServerInstance->SNO->DisableSnomask('j');\r      }\r      \r       virtual Version GetVersion()\r   {\r              return Version(1,1,0,0,VF_VENDOR,API_VERSION);\r }\r\r     void Implements(char* List)\r    {\r              List[I_OnUserJoin] = 1;\r        }\r      \r       virtual void OnUserJoin(userrec* user, chanrec* channel, bool &silent)\r {\r              if (channel->GetUserCounter() == 1)\r            {\r                      ServerInstance->SNO->WriteToSnoMask('j', "Channel %s created by %s!%s@%s", channel->name, user->nick, user->ident, user->host);\r                }\r      }\r};\r\rMODULE_INIT(ModuleChanCreate)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+
+/* $ModDesc: Creates a snomask with notices whenever a new channel is created */
+
+class ModuleChanCreate : public Module
+{
+ private:
+ public:
+       ModuleChanCreate(InspIRCd* Me)
+               : Module(Me)
+       {
+               ServerInstance->SNO->EnableSnomask('j', "CHANCREATE");
+       }
+       
+       virtual ~ModuleChanCreate()
+       {
+               ServerInstance->SNO->DisableSnomask('j');
+       }
+       
+       virtual Version GetVersion()
+       {
+               return Version(1,1,0,0,VF_VENDOR,API_VERSION);
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnUserJoin] = 1;
+       }
+       
+       virtual void OnUserJoin(userrec* user, chanrec* channel, bool &silent)
+       {
+               if (channel->GetUserCounter() == 1)
+               {
+                       ServerInstance->SNO->WriteToSnoMask('j', "Channel %s created by %s!%s@%s", channel->name, user->nick, user->ident, user->host);
+               }
+       }
+};
+
+MODULE_INIT(ModuleChanCreate)
index 44aac9daee846c38fa4fa9523d3ad76316a138e7..375fbce9c5fdecd39e2b2329d6a60af32ccfae21 100644 (file)
@@ -1 +1,155 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#define _CRT_SECURE_NO_DEPRECATE\r#define _SCL_SECURE_NO_DEPRECATE\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r#include "hashcomp.h"\r#include "u_listmode.h"\r\r/* $ModDesc: Provides channel-specific censor lists (like mode +G but varies from channel to channel) */\r/* $ModDep: ../../include/u_listmode.h */\r\r/** Handles channel mode +g\r */\rclass ChanFilter : public ListModeBase\r{\r public:\r       ChanFilter(InspIRCd* Instance) : ListModeBase(Instance, 'g', "End of channel spamfilter list", "941", "940", false, "chanfilter") { }\r  \r       virtual bool ValidateParam(userrec* user, chanrec* chan, std::string &word)\r    {\r              if ((word.length() > 35) || (word.empty()))\r            {\r                      user->WriteServ("935 %s %s %s :word is too %s for censor list",user->nick, chan->name,word.c_str(), (word.empty() ? "short" : "long"));\r                        return false;\r          }\r              \r               return true;\r   }\r      \r       virtual bool TellListTooLong(userrec* user, chanrec* chan, std::string &word)\r  {\r              user->WriteServ("939 %s %s %s :Channel spamfilter list is full",user->nick, chan->name, word.c_str());\r         return true;\r   }\r      \r       virtual void TellAlreadyOnList(userrec* user, chanrec* chan, std::string &word)\r        {\r              user->WriteServ("937 %s %s :The word %s is already on the spamfilter list",user->nick, chan->name,word.c_str());\r       }\r      \r       virtual void TellNotSet(userrec* user, chanrec* chan, std::string &word)\r       {\r              user->WriteServ("938 %s %s :No such spamfilter word is set",user->nick, chan->name);\r   }\r};\r\rclass ModuleChanFilter : public Module\r{\r \r       ChanFilter* cf;\r        \r public:\r \r    ModuleChanFilter(InspIRCd* Me)\r         : Module(Me)\r   {\r              cf = new ChanFilter(ServerInstance);\r           if (!ServerInstance->AddMode(cf, 'g'))\r                 throw ModuleException("Could not add new modes!");\r     }\r\r     void Implements(char* List) \r   { \r             cf->DoImplements(List);\r                List[I_OnCleanup] = List[I_OnChannelDelete] = List[I_OnRehash] = List[I_OnUserPreMessage] = List[I_OnUserPreNotice] = List[I_OnSyncChannel] = 1;\r       }\r\r     virtual void OnChannelDelete(chanrec* chan)\r    {\r              cf->DoChannelDelete(chan);\r     }\r\r     virtual void OnRehash(userrec* user, const std::string &parameter)\r     {\r              cf->DoRehash();\r        }\r\r     virtual int ProcessMessages(userrec* user,chanrec* chan,std::string &text)\r     {\r              if (!IS_LOCAL(user) || CHANOPS_EXEMPT(ServerInstance, 'g') && chan->GetStatus(user) == STATUS_OP)\r                      return 0;\r\r             // Create a copy of the string in irc::string\r          irc::string line = text.c_str();\r\r              modelist* list;\r                chan->GetExt(cf->GetInfoKey(), list);\r\r         if (list)\r              {\r                      for (modelist::iterator i = list->begin(); i != list->end(); i++)\r                      {\r                              if (line.find(i->mask.c_str()) != std::string::npos)\r                           {\r                                      user->WriteServ("936 %s %s %s :Your message contained a censored word, and was blocked",user->nick, chan->name, i->mask.c_str());\r                                      return 1;\r                              }\r                      }\r              }\r\r             return 0;\r      }\r\r     virtual int OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)\r    {\r              if (target_type == TYPE_CHANNEL)\r               {\r                      return ProcessMessages(user,(chanrec*)dest,text);\r              }\r              else return 0;\r }\r\r     virtual void OnCleanup(int target_type, void* item)\r    {\r              cf->DoCleanup(target_type, item);\r      }\r      \r       virtual int OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)\r     {\r              return OnUserPreMessage(user,dest,target_type,text,status,exempt_list);\r        }\r      \r       virtual void OnSyncChannel(chanrec* chan, Module* proto, void* opaque)\r {\r              cf->DoSyncChannel(chan, proto, opaque);\r        }\r\r     virtual Version GetVersion()\r   {\r              return Version(1, 1, 0, 0, VF_COMMON | VF_VENDOR, API_VERSION);\r        }\r      \r       virtual ~ModuleChanFilter()\r    {\r              ServerInstance->Modes->DelMode(cf);\r            DELETE(cf);\r    }\r};\r\rMODULE_INIT(ModuleChanFilter)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#define _CRT_SECURE_NO_DEPRECATE
+#define _SCL_SECURE_NO_DEPRECATE
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+#include "hashcomp.h"
+#include "u_listmode.h"
+
+/* $ModDesc: Provides channel-specific censor lists (like mode +G but varies from channel to channel) */
+/* $ModDep: ../../include/u_listmode.h */
+
+/** Handles channel mode +g
+ */
+class ChanFilter : public ListModeBase
+{
+ public:
+       ChanFilter(InspIRCd* Instance) : ListModeBase(Instance, 'g', "End of channel spamfilter list", "941", "940", false, "chanfilter") { }
+       
+       virtual bool ValidateParam(userrec* user, chanrec* chan, std::string &word)
+       {
+               if ((word.length() > 35) || (word.empty()))
+               {
+                       user->WriteServ("935 %s %s %s :word is too %s for censor list",user->nick, chan->name,word.c_str(), (word.empty() ? "short" : "long"));
+                       return false;
+               }
+               
+               return true;
+       }
+       
+       virtual bool TellListTooLong(userrec* user, chanrec* chan, std::string &word)
+       {
+               user->WriteServ("939 %s %s %s :Channel spamfilter list is full",user->nick, chan->name, word.c_str());
+               return true;
+       }
+       
+       virtual void TellAlreadyOnList(userrec* user, chanrec* chan, std::string &word)
+       {
+               user->WriteServ("937 %s %s :The word %s is already on the spamfilter list",user->nick, chan->name,word.c_str());
+       }
+       
+       virtual void TellNotSet(userrec* user, chanrec* chan, std::string &word)
+       {
+               user->WriteServ("938 %s %s :No such spamfilter word is set",user->nick, chan->name);
+       }
+};
+
+class ModuleChanFilter : public Module
+{
+       
+       ChanFilter* cf;
+       
+ public:
+       ModuleChanFilter(InspIRCd* Me)
+               : Module(Me)
+       {
+               cf = new ChanFilter(ServerInstance);
+               if (!ServerInstance->AddMode(cf, 'g'))
+                       throw ModuleException("Could not add new modes!");
+       }
+
+       void Implements(char* List) 
+       { 
+               cf->DoImplements(List);
+               List[I_OnCleanup] = List[I_OnChannelDelete] = List[I_OnRehash] = List[I_OnUserPreMessage] = List[I_OnUserPreNotice] = List[I_OnSyncChannel] = 1;
+       }
+
+       virtual void OnChannelDelete(chanrec* chan)
+       {
+               cf->DoChannelDelete(chan);
+       }
+
+       virtual void OnRehash(userrec* user, const std::string &parameter)
+       {
+               cf->DoRehash();
+       }
+
+       virtual int ProcessMessages(userrec* user,chanrec* chan,std::string &text)
+       {
+               if (!IS_LOCAL(user) || CHANOPS_EXEMPT(ServerInstance, 'g') && chan->GetStatus(user) == STATUS_OP)
+                       return 0;
+
+               // Create a copy of the string in irc::string
+               irc::string line = text.c_str();
+
+               modelist* list;
+               chan->GetExt(cf->GetInfoKey(), list);
+
+               if (list)
+               {
+                       for (modelist::iterator i = list->begin(); i != list->end(); i++)
+                       {
+                               if (line.find(i->mask.c_str()) != std::string::npos)
+                               {
+                                       user->WriteServ("936 %s %s %s :Your message contained a censored word, and was blocked",user->nick, chan->name, i->mask.c_str());
+                                       return 1;
+                               }
+                       }
+               }
+
+               return 0;
+       }
+
+       virtual int OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
+       {
+               if (target_type == TYPE_CHANNEL)
+               {
+                       return ProcessMessages(user,(chanrec*)dest,text);
+               }
+               else return 0;
+       }
+
+       virtual void OnCleanup(int target_type, void* item)
+       {
+               cf->DoCleanup(target_type, item);
+       }
+       
+       virtual int OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
+       {
+               return OnUserPreMessage(user,dest,target_type,text,status,exempt_list);
+       }
+       
+       virtual void OnSyncChannel(chanrec* chan, Module* proto, void* opaque)
+       {
+               cf->DoSyncChannel(chan, proto, opaque);
+       }
+
+       virtual Version GetVersion()
+       {
+               return Version(1, 1, 0, 0, VF_COMMON | VF_VENDOR, API_VERSION);
+       }
+       
+       virtual ~ModuleChanFilter()
+       {
+               ServerInstance->Modes->DelMode(cf);
+               DELETE(cf);
+       }
+};
+
+MODULE_INIT(ModuleChanFilter)
index 74640fe524a5e108dfa64f9ed69d4add58e463a8..87bc1ca4c5299b8148e693216f8021e04a90dca3 100644 (file)
@@ -1 +1,531 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r\r/* $ModDesc: Provides channel modes +a and +q */\r/* $ModDep: ../../include/u_listmode.h */\r\r#define PROTECT_VALUE 40000\r#define FOUNDER_VALUE 50000\r\rconst char* fakevalue = "on";\r\r/* When this is set to true, no restrictions apply to setting or\r * removal of +qa. This is used while unloading so that the server\r * can freely clear all of its users of the modes.\r */\rbool unload_kludge = false;\r\r/** Handles basic operation of +qa channel modes\r */\rclass FounderProtectBase\r{\r private:\r        InspIRCd* MyInstance;\r  std::string extend;\r    std::string type;\r      int list;\r      int end;\r       char* dummyptr;\r protected:\r    bool& remove_own_privs;\r        bool& remove_other_privs;\r public:\r     FounderProtectBase(InspIRCd* Instance, const std::string &ext, const std::string &mtype, int l, int e, bool &remove_own, bool &remove_others) :\r                MyInstance(Instance), extend(ext), type(mtype), list(l), end(e), remove_own_privs(remove_own), remove_other_privs(remove_others)\r       {\r      }\r\r     ModePair ModeSet(userrec* source, userrec* dest, chanrec* channel, const std::string &parameter)\r       {\r              userrec* x = MyInstance->FindNick(parameter);\r          if (x)\r         {\r                      if (!channel->HasUser(x))\r                      {\r                              return std::make_pair(false, parameter);\r                       }\r                      else\r                   {\r                              std::string item = extend+std::string(channel->name);\r                          if (x->GetExt(item,dummyptr))\r                          {\r                                      return std::make_pair(true, x->nick);\r                          }\r                              else\r                           {\r                                      return std::make_pair(false, parameter);\r                               }\r                      }\r              }\r              return std::make_pair(false, parameter);\r       }\r\r     void RemoveMode(chanrec* channel, char mc)\r     {\r              unload_kludge = true;\r          CUList* cl = channel->GetUsers();\r              std::string item = extend + std::string(channel->name);\r                const char* mode_junk[MAXMODES+2];\r             userrec* n = new userrec(MyInstance);\r          n->SetFd(FD_MAGIC_NUMBER);\r             mode_junk[0] = channel->name;\r          irc::modestacker modestack(false);\r             std::deque<std::string> stackresult;                            \r               for (CUList::iterator i = cl->begin(); i != cl->end(); i++)\r            {\r                      if (i->first->GetExt(item, dummyptr))\r                  {\r                              modestack.Push(mc, i->first->nick);\r                    }\r              }\r\r             while (modestack.GetStackedLine(stackresult))\r          {\r                      for (size_t j = 0; j < stackresult.size(); j++)\r                        {\r                              mode_junk[j+1] = stackresult[j].c_str();\r                       }\r                      MyInstance->SendMode(mode_junk, stackresult.size() + 1, n);\r            }\r              \r               delete n;\r              unload_kludge = false;\r }\r\r     void DisplayList(userrec* user, chanrec* channel)\r      {\r              CUList* cl = channel->GetUsers();\r              std::string item = extend+std::string(channel->name);\r          for (CUList::reverse_iterator i = cl->rbegin(); i != cl->rend(); ++i)\r          {\r                      if (i->first->GetExt(item, dummyptr))\r                  {\r                              user->WriteServ("%d %s %s %s", list, user->nick, channel->name,i->first->nick);\r                        }\r              }\r              user->WriteServ("%d %s %s :End of channel %s list", end, user->nick, channel->name, type.c_str());\r     }\r\r     userrec* FindAndVerify(std::string &parameter, chanrec* channel)\r       {\r              userrec* theuser = MyInstance->FindNick(parameter);\r            if ((!theuser) || (!channel->HasUser(theuser)))\r                {\r                      parameter.clear();\r                     return NULL;\r           }\r              return theuser;\r        }\r\r     bool CanRemoveOthers(userrec* u1, userrec* u2, chanrec* c)\r     {\r              std::string item = extend+std::string(c->name);\r                return (u1->GetExt(item, dummyptr) && u2->GetExt(item, dummyptr));\r     }\r\r     ModeAction HandleChange(userrec* source, userrec* theuser, bool adding, chanrec* channel, std::string &parameter)\r      {\r              std::string item = extend+std::string(channel->name);\r\r         if (adding)\r            {\r                      if (!theuser->GetExt(item, dummyptr))\r                  {\r                              theuser->Extend(item, fakevalue);\r                              parameter = theuser->nick;\r                             return MODEACTION_ALLOW;\r                       }\r              }\r              else\r           {\r                      if (theuser->GetExt(item, dummyptr))\r                   {\r                              theuser->Shrink(item);\r                         parameter = theuser->nick;\r                             return MODEACTION_ALLOW;\r                       }\r              }\r              return MODEACTION_DENY;\r        }\r};\r\r/** Abstraction of FounderProtectBase for channel mode +q\r */\rclass ChanFounder : public ModeHandler, public FounderProtectBase\r{\r        char* dummyptr;\r public:\r       ChanFounder(InspIRCd* Instance, bool using_prefixes, bool &depriv_self, bool &depriv_others)\r           : ModeHandler(Instance, 'q', 1, 1, true, MODETYPE_CHANNEL, false, using_prefixes ? '~' : 0),\r             FounderProtectBase(Instance, "cm_founder_", "founder", 386, 387, depriv_self, depriv_others) { }\r\r    unsigned int GetPrefixRank()\r   {\r              return FOUNDER_VALUE;\r  }\r\r     ModePair ModeSet(userrec* source, userrec* dest, chanrec* channel, const std::string &parameter)\r       {\r              return FounderProtectBase::ModeSet(source, dest, channel, parameter);\r  }\r\r     void RemoveMode(chanrec* channel)\r      {\r              FounderProtectBase::RemoveMode(channel, this->GetModeChar());\r  }\r\r     void RemoveMode(userrec* user)\r {\r      }\r\r     ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)\r {\r              userrec* theuser = FounderProtectBase::FindAndVerify(parameter, channel);\r\r             if (!theuser)\r          {\r                      return MODEACTION_DENY;\r                }\r\r             if ((!adding) && FounderProtectBase::CanRemoveOthers(source, theuser, channel))\r                {\r                      return FounderProtectBase::HandleChange(source, theuser, adding, channel, parameter);\r          }\r               // source is a server, or ulined, we'll let them +-q the user.\r                if ((unload_kludge) || ((source == theuser) && (!adding) && (FounderProtectBase::remove_own_privs)) || (ServerInstance->ULine(source->nick)) || (ServerInstance->ULine(source->server)) || (!*source->server) || (!IS_LOCAL(source)))\r          {\r                      return FounderProtectBase::HandleChange(source, theuser, adding, channel, parameter);\r          }\r              else\r           {\r                      // whoops, someones being naughty!\r                     source->WriteServ("468 %s %s :Only servers may set channel mode +q",source->nick, channel->name);\r                      parameter.clear();\r                     return MODEACTION_DENY;\r                }\r      }\r\r     void DisplayList(userrec* user, chanrec* channel)\r      {\r              FounderProtectBase::DisplayList(user,channel);\r }\r};\r\r/** Abstraction of FounderProtectBase for channel mode +a\r */\rclass ChanProtect : public ModeHandler, public FounderProtectBase\r{\r        char* dummyptr;\r public:\r       ChanProtect(InspIRCd* Instance, bool using_prefixes, bool &depriv_self, bool &depriv_others)\r           : ModeHandler(Instance, 'a', 1, 1, true, MODETYPE_CHANNEL, false, using_prefixes ? '&' : 0),\r             FounderProtectBase(Instance,"cm_protect_","protected user", 388, 389, depriv_self, depriv_others) { }\r\r       unsigned int GetPrefixRank()\r   {\r              return PROTECT_VALUE;\r  }\r\r     ModePair ModeSet(userrec* source, userrec* dest, chanrec* channel, const std::string &parameter)\r       {\r              return FounderProtectBase::ModeSet(source, dest, channel, parameter);\r  }\r\r     void RemoveMode(chanrec* channel)\r      {\r              FounderProtectBase::RemoveMode(channel, this->GetModeChar());\r  }\r\r     void RemoveMode(userrec* user)\r {\r      }\r\r     ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)\r {\r              userrec* theuser = FounderProtectBase::FindAndVerify(parameter, channel);\r\r             if (!theuser)\r                  return MODEACTION_DENY;\r\r               std::string founder = "cm_founder_"+std::string(channel->name);\r\r               if ((!adding) && FounderProtectBase::CanRemoveOthers(source, theuser, channel))\r                {\r                      return FounderProtectBase::HandleChange(source, theuser, adding, channel, parameter);\r          }\r              // source has +q, is a server, or ulined, we'll let them +-a the user.\r         if ((unload_kludge) || ((source == theuser) && (!adding) && (FounderProtectBase::remove_own_privs)) || (ServerInstance->ULine(source->nick)) || (ServerInstance->ULine(source->server)) || (!*source->server) || (source->GetExt(founder,dummyptr)) || (!IS_LOCAL(source)))\r            {\r                      return FounderProtectBase::HandleChange(source, theuser, adding, channel, parameter);\r          }\r              else\r           {\r                      // bzzzt, wrong answer!\r                        source->WriteServ("482 %s %s :You are not a channel founder",source->nick, channel->name);\r                     return MODEACTION_DENY;\r                }\r      }\r\r     virtual void DisplayList(userrec* user, chanrec* channel)\r      {\r              FounderProtectBase::DisplayList(user, channel);\r        }\r\r};\r\rclass ModuleChanProtect : public Module\r{\r       \r       bool FirstInGetsFounder;\r       bool QAPrefixes;\r       bool DeprivSelf;\r       bool DeprivOthers;\r     bool booting;\r  ChanProtect* cp;\r       ChanFounder* cf;\r       char* dummyptr;\r        \r public:\r \r    ModuleChanProtect(InspIRCd* Me)\r                : Module(Me), FirstInGetsFounder(false), QAPrefixes(false), DeprivSelf(false), DeprivOthers(false), booting(true)\r      {       \r               /* Load config stuff */\r                OnRehash(NULL,"");\r             booting = false;\r\r              /* Initialise module variables */\r\r             cp = new ChanProtect(ServerInstance,QAPrefixes,DeprivSelf,DeprivOthers);\r               cf = new ChanFounder(ServerInstance,QAPrefixes,DeprivSelf,DeprivOthers);\r\r              if (!ServerInstance->AddMode(cp, 'a') || !ServerInstance->AddMode(cf, 'q'))\r                    throw ModuleException("Could not add new modes!");\r     }\r\r     void Implements(char* List)\r    {\r              List[I_OnUserKick] = List[I_OnUserPart] = List[I_OnRehash] = List[I_OnUserJoin] = List[I_OnAccessCheck] = List[I_OnSyncChannel] = 1;\r   }\r\r     virtual void OnUserKick(userrec* source, userrec* user, chanrec* chan, const std::string &reason, bool &silent)\r        {\r              // FIX: when someone gets kicked from a channel we must remove their Extensibles!\r              user->Shrink("cm_founder_"+std::string(chan->name));\r           user->Shrink("cm_protect_"+std::string(chan->name));\r   }\r\r     virtual void OnUserPart(userrec* user, chanrec* channel, const std::string &partreason, bool &silent)\r  {\r              // FIX: when someone parts a channel we must remove their Extensibles!\r         user->Shrink("cm_founder_"+std::string(channel->name));\r                user->Shrink("cm_protect_"+std::string(channel->name));\r        }\r\r     virtual void OnRehash(userrec* user, const std::string &parameter)\r     {\r              /* Create a configreader class and read our flag,\r               * in old versions this was heap-allocated and the\r              * object was kept between rehashes...now we just\r               * stack-allocate it locally.\r           */\r            ConfigReader Conf(ServerInstance);\r\r            bool old_qa = QAPrefixes;\r\r             FirstInGetsFounder = Conf.ReadFlag("options","noservices",0);\r          QAPrefixes = Conf.ReadFlag("options","qaprefixes",0);\r          DeprivSelf = Conf.ReadFlag("options","deprotectself",0);\r               DeprivOthers = Conf.ReadFlag("options","deprotectothers",0);\r\r          /* Did the user change the QA prefixes on the fly?\r              * If so, remove all instances of the mode, and reinit\r          * the module with prefixes enabled.\r            */\r            if ((old_qa != QAPrefixes) && (!booting))\r              {\r                      ServerInstance->Modes->DelMode(cp);\r                    ServerInstance->Modes->DelMode(cf);\r                    DELETE(cp);\r                    DELETE(cf);\r                    cp = new ChanProtect(ServerInstance,QAPrefixes,DeprivSelf,DeprivOthers);\r                       cf = new ChanFounder(ServerInstance,QAPrefixes,DeprivSelf,DeprivOthers);\r                       /* These wont fail, we already owned the mode characters before */\r                     ServerInstance->AddMode(cp, 'a');\r                      ServerInstance->AddMode(cf, 'q');\r                      ServerInstance->WriteOpers("*** WARNING: +qa prefixes were enabled or disabled via a REHASH. Clients will probably need to reconnect to pick up this change.");\r                }\r      }\r      \r       virtual void OnUserJoin(userrec* user, chanrec* channel, bool &silent)\r {\r              // if the user is the first user into the channel, mark them as the founder, but only if\r               // the config option for it is set\r             if (FirstInGetsFounder)\r                {\r                      if (channel->GetUserCounter() == 1)\r                    {\r                              // we're using Extensible::Extend to add data into user objects.\r                               // this way is best as it adds data thats accessible to other modules\r                          // (so long as you document your code properly) without breaking anything\r                              // because its encapsulated neatly in a map.\r\r                          // Change requested by katsklaw... when the first in is set to get founder,\r                            // to make it clearer that +q has been given, send that one user the +q notice\r                         // so that their client's syncronization and their sanity are left intact.\r                             user->WriteServ("MODE %s +q %s",channel->name,user->nick);\r                             user->Extend("cm_founder_"+std::string(channel->name),fakevalue);\r                      }\r              }\r      }\r      \r       virtual int OnAccessCheck(userrec* source,userrec* dest,chanrec* channel,int access_type)\r      {\r              // here we perform access checks, this is the important bit that actually stops kicking/deopping\r               // etc of protected users. There are many types of access check, we're going to handle\r         // a relatively small number of them relevent to our module using a switch statement.\r          // don't allow action if:\r              // (A) Theyre founder (no matter what)\r         // (B) Theyre protected, and you're not\r                // always allow the action if:\r         // (A) The source is ulined\r            \r               \r               // firstly, if a ulined nick, or a server, is setting the mode, then allow them to set the mode\r                // without any access checks, we're not worthy :p\r              if ((ServerInstance->ULine(source->nick)) || (ServerInstance->ULine(source->server)) || (!*source->server))\r                    return ACR_ALLOW;\r\r             std::string founder = "cm_founder_"+std::string(channel->name);\r                std::string protect = "cm_protect_"+std::string(channel->name);\r\r               switch (access_type)\r           {\r                      // a user has been deopped. Do we let them? hmmm...\r                    case AC_DEOP:\r                          if (dest->GetExt(founder,dummyptr))\r                            {\r                                      source->WriteServ("484 "+std::string(source->nick)+" "+std::string(channel->name)+" :Can't deop "+std::string(dest->nick)+" as they're a channel founder");\r                                    return ACR_DENY;\r                               }\r                              if ((dest->GetExt(protect,dummyptr)) && (!source->GetExt(protect,dummyptr)))\r                           {\r                                      source->WriteServ("484 "+std::string(source->nick)+" "+std::string(channel->name)+" :Can't deop "+std::string(dest->nick)+" as they're protected (+a)");\r                                       return ACR_DENY;\r                               }\r                      break;\r\r                        // a user is being kicked. do we chop off the end of the army boot?\r                    case AC_KICK:\r                          if (dest->GetExt(founder,dummyptr))\r                            {\r                                      source->WriteServ("484 "+std::string(source->nick)+" "+std::string(channel->name)+" :Can't kick "+std::string(dest->nick)+" as they're a channel founder");\r                                    return ACR_DENY;\r                               }\r                              if ((dest->GetExt(protect,dummyptr)) && (!source->GetExt(protect,dummyptr)))\r                           {\r                                      source->WriteServ("484 "+std::string(source->nick)+" "+std::string(channel->name)+" :Can't kick "+std::string(dest->nick)+" as they're protected (+a)");\r                                       return ACR_DENY;\r                               }\r                      break;\r\r                        // a user is being dehalfopped. Yes, we do disallow -h of a +ha user\r                   case AC_DEHALFOP:\r                              if (dest->GetExt(founder,dummyptr))\r                            {\r                                      source->WriteServ("484 "+std::string(source->nick)+" "+std::string(channel->name)+" :Can't de-halfop "+std::string(dest->nick)+" as they're a channel founder");\r                                       return ACR_DENY;\r                               }\r                              if ((dest->GetExt(protect,dummyptr)) && (!source->GetExt(protect,dummyptr)))\r                           {\r                                      source->WriteServ("484 "+std::string(source->nick)+" "+std::string(channel->name)+" :Can't de-halfop "+std::string(dest->nick)+" as they're protected (+a)");\r                                  return ACR_DENY;\r                               }\r                      break;\r\r                        // same with devoice.\r                  case AC_DEVOICE:\r                               if (dest->GetExt(founder,dummyptr))\r                            {\r                                      source->WriteServ("484 "+std::string(source->nick)+" "+std::string(channel->name)+" :Can't devoice "+std::string(dest->nick)+" as they're a channel founder");\r                                 return ACR_DENY;\r                               }\r                              if ((dest->GetExt(protect,dummyptr)) && (!source->GetExt(protect,dummyptr)))\r                           {\r                                      source->WriteServ("484 "+std::string(source->nick)+" "+std::string(channel->name)+" :Can't devoice "+std::string(dest->nick)+" as they're protected (+a)");\r                                    return ACR_DENY;\r                               }\r                      break;\r         }\r              \r               // we dont know what this access check is, or dont care. just carry on, nothing to see here.\r           return ACR_DEFAULT;\r    }\r      \r       virtual ~ModuleChanProtect()\r   {\r              ServerInstance->Modes->DelMode(cp);\r            ServerInstance->Modes->DelMode(cf);\r            DELETE(cp);\r            DELETE(cf);\r    }\r      \r       virtual Version GetVersion()\r   {\r              return Version(1, 1, 0, 0, VF_COMMON | VF_VENDOR, API_VERSION);\r        }\r      \r       virtual void OnSyncChannel(chanrec* chan, Module* proto, void* opaque)\r {\r              /* NOTE: If +qa prefix is on, this is propogated by the channel join,\r           * so we dont need to propogate it manually\r             */\r            if (!QAPrefixes)\r               {\r                      // this is called when the server is linking into a net and wants to sync channel data.\r                        // we should send our mode changes for the channel here to ensure that other servers\r                   // know whos +q/+a on the channel.\r                     CUList* cl = chan->GetUsers();\r                 string_list commands;\r                  std::string founder = "cm_founder_"+std::string(chan->name);\r                   std::string protect = "cm_protect_"+std::string(chan->name);\r                   irc::modestacker modestack(true);\r                      std::deque<std::string> stackresult;\r                   for (CUList::iterator i = cl->begin(); i != cl->end(); i++)\r                    {\r                              if (i->first->GetExt(founder,dummyptr))\r                                {\r                                      modestack.Push('q',i->first->nick);\r                            }\r                              if (i->first->GetExt(protect,dummyptr))\r                                {\r                                      modestack.Push('a',i->first->nick);\r                            }\r                      }\r                      while (modestack.GetStackedLine(stackresult))\r                  {\r                              irc::stringjoiner mode_join(" ", stackresult, 0, stackresult.size() - 1);\r                              std::string line = mode_join.GetJoined();\r                              proto->ProtoSendMode(opaque,TYPE_CHANNEL,chan, line);\r                  }\r              }\r      }\r\r};\r\rMODULE_INIT(ModuleChanProtect)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+
+/* $ModDesc: Provides channel modes +a and +q */
+/* $ModDep: ../../include/u_listmode.h */
+
+#define PROTECT_VALUE 40000
+#define FOUNDER_VALUE 50000
+
+const char* fakevalue = "on";
+
+/* When this is set to true, no restrictions apply to setting or
+ * removal of +qa. This is used while unloading so that the server
+ * can freely clear all of its users of the modes.
+ */
+bool unload_kludge = false;
+
+/** Handles basic operation of +qa channel modes
+ */
+class FounderProtectBase
+{
+ private:
+       InspIRCd* MyInstance;
+       std::string extend;
+       std::string type;
+       int list;
+       int end;
+       char* dummyptr;
+ protected:
+       bool& remove_own_privs;
+       bool& remove_other_privs;
+ public:
+       FounderProtectBase(InspIRCd* Instance, const std::string &ext, const std::string &mtype, int l, int e, bool &remove_own, bool &remove_others) :
+               MyInstance(Instance), extend(ext), type(mtype), list(l), end(e), remove_own_privs(remove_own), remove_other_privs(remove_others)
+       {
+       }
+
+       ModePair ModeSet(userrec* source, userrec* dest, chanrec* channel, const std::string &parameter)
+       {
+               userrec* x = MyInstance->FindNick(parameter);
+               if (x)
+               {
+                       if (!channel->HasUser(x))
+                       {
+                               return std::make_pair(false, parameter);
+                       }
+                       else
+                       {
+                               std::string item = extend+std::string(channel->name);
+                               if (x->GetExt(item,dummyptr))
+                               {
+                                       return std::make_pair(true, x->nick);
+                               }
+                               else
+                               {
+                                       return std::make_pair(false, parameter);
+                               }
+                       }
+               }
+               return std::make_pair(false, parameter);
+       }
+
+       void RemoveMode(chanrec* channel, char mc)
+       {
+               unload_kludge = true;
+               CUList* cl = channel->GetUsers();
+               std::string item = extend + std::string(channel->name);
+               const char* mode_junk[MAXMODES+2];
+               userrec* n = new userrec(MyInstance);
+               n->SetFd(FD_MAGIC_NUMBER);
+               mode_junk[0] = channel->name;
+               irc::modestacker modestack(false);
+               std::deque<std::string> stackresult;                            
+               for (CUList::iterator i = cl->begin(); i != cl->end(); i++)
+               {
+                       if (i->first->GetExt(item, dummyptr))
+                       {
+                               modestack.Push(mc, i->first->nick);
+                       }
+               }
+
+               while (modestack.GetStackedLine(stackresult))
+               {
+                       for (size_t j = 0; j < stackresult.size(); j++)
+                       {
+                               mode_junk[j+1] = stackresult[j].c_str();
+                       }
+                       MyInstance->SendMode(mode_junk, stackresult.size() + 1, n);
+               }
+               
+               delete n;
+               unload_kludge = false;
+       }
+
+       void DisplayList(userrec* user, chanrec* channel)
+       {
+               CUList* cl = channel->GetUsers();
+               std::string item = extend+std::string(channel->name);
+               for (CUList::reverse_iterator i = cl->rbegin(); i != cl->rend(); ++i)
+               {
+                       if (i->first->GetExt(item, dummyptr))
+                       {
+                               user->WriteServ("%d %s %s %s", list, user->nick, channel->name,i->first->nick);
+                       }
+               }
+               user->WriteServ("%d %s %s :End of channel %s list", end, user->nick, channel->name, type.c_str());
+       }
+
+       userrec* FindAndVerify(std::string &parameter, chanrec* channel)
+       {
+               userrec* theuser = MyInstance->FindNick(parameter);
+               if ((!theuser) || (!channel->HasUser(theuser)))
+               {
+                       parameter.clear();
+                       return NULL;
+               }
+               return theuser;
+       }
+
+       bool CanRemoveOthers(userrec* u1, userrec* u2, chanrec* c)
+       {
+               std::string item = extend+std::string(c->name);
+               return (u1->GetExt(item, dummyptr) && u2->GetExt(item, dummyptr));
+       }
+
+       ModeAction HandleChange(userrec* source, userrec* theuser, bool adding, chanrec* channel, std::string &parameter)
+       {
+               std::string item = extend+std::string(channel->name);
+
+               if (adding)
+               {
+                       if (!theuser->GetExt(item, dummyptr))
+                       {
+                               theuser->Extend(item, fakevalue);
+                               parameter = theuser->nick;
+                               return MODEACTION_ALLOW;
+                       }
+               }
+               else
+               {
+                       if (theuser->GetExt(item, dummyptr))
+                       {
+                               theuser->Shrink(item);
+                               parameter = theuser->nick;
+                               return MODEACTION_ALLOW;
+                       }
+               }
+               return MODEACTION_DENY;
+       }
+};
+
+/** Abstraction of FounderProtectBase for channel mode +q
+ */
+class ChanFounder : public ModeHandler, public FounderProtectBase
+{
+       char* dummyptr;
+ public:
+       ChanFounder(InspIRCd* Instance, bool using_prefixes, bool &depriv_self, bool &depriv_others)
+               : ModeHandler(Instance, 'q', 1, 1, true, MODETYPE_CHANNEL, false, using_prefixes ? '~' : 0),
+                 FounderProtectBase(Instance, "cm_founder_", "founder", 386, 387, depriv_self, depriv_others) { }
+
+       unsigned int GetPrefixRank()
+       {
+               return FOUNDER_VALUE;
+       }
+
+       ModePair ModeSet(userrec* source, userrec* dest, chanrec* channel, const std::string &parameter)
+       {
+               return FounderProtectBase::ModeSet(source, dest, channel, parameter);
+       }
+
+       void RemoveMode(chanrec* channel)
+       {
+               FounderProtectBase::RemoveMode(channel, this->GetModeChar());
+       }
+
+       void RemoveMode(userrec* user)
+       {
+       }
+
+       ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)
+       {
+               userrec* theuser = FounderProtectBase::FindAndVerify(parameter, channel);
+
+               if (!theuser)
+               {
+                       return MODEACTION_DENY;
+               }
+
+               if ((!adding) && FounderProtectBase::CanRemoveOthers(source, theuser, channel))
+               {
+                       return FounderProtectBase::HandleChange(source, theuser, adding, channel, parameter);
+               }
+                // source is a server, or ulined, we'll let them +-q the user.
+               if ((unload_kludge) || ((source == theuser) && (!adding) && (FounderProtectBase::remove_own_privs)) || (ServerInstance->ULine(source->nick)) || (ServerInstance->ULine(source->server)) || (!*source->server) || (!IS_LOCAL(source)))
+               {
+                       return FounderProtectBase::HandleChange(source, theuser, adding, channel, parameter);
+               }
+               else
+               {
+                       // whoops, someones being naughty!
+                       source->WriteServ("468 %s %s :Only servers may set channel mode +q",source->nick, channel->name);
+                       parameter.clear();
+                       return MODEACTION_DENY;
+               }
+       }
+
+       void DisplayList(userrec* user, chanrec* channel)
+       {
+               FounderProtectBase::DisplayList(user,channel);
+       }
+};
+
+/** Abstraction of FounderProtectBase for channel mode +a
+ */
+class ChanProtect : public ModeHandler, public FounderProtectBase
+{
+       char* dummyptr;
+ public:
+       ChanProtect(InspIRCd* Instance, bool using_prefixes, bool &depriv_self, bool &depriv_others)
+               : ModeHandler(Instance, 'a', 1, 1, true, MODETYPE_CHANNEL, false, using_prefixes ? '&' : 0),
+                 FounderProtectBase(Instance,"cm_protect_","protected user", 388, 389, depriv_self, depriv_others) { }
+
+       unsigned int GetPrefixRank()
+       {
+               return PROTECT_VALUE;
+       }
+
+       ModePair ModeSet(userrec* source, userrec* dest, chanrec* channel, const std::string &parameter)
+       {
+               return FounderProtectBase::ModeSet(source, dest, channel, parameter);
+       }
+
+       void RemoveMode(chanrec* channel)
+       {
+               FounderProtectBase::RemoveMode(channel, this->GetModeChar());
+       }
+
+       void RemoveMode(userrec* user)
+       {
+       }
+
+       ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)
+       {
+               userrec* theuser = FounderProtectBase::FindAndVerify(parameter, channel);
+
+               if (!theuser)
+                       return MODEACTION_DENY;
+
+               std::string founder = "cm_founder_"+std::string(channel->name);
+
+               if ((!adding) && FounderProtectBase::CanRemoveOthers(source, theuser, channel))
+               {
+                       return FounderProtectBase::HandleChange(source, theuser, adding, channel, parameter);
+               }
+               // source has +q, is a server, or ulined, we'll let them +-a the user.
+               if ((unload_kludge) || ((source == theuser) && (!adding) && (FounderProtectBase::remove_own_privs)) || (ServerInstance->ULine(source->nick)) || (ServerInstance->ULine(source->server)) || (!*source->server) || (source->GetExt(founder,dummyptr)) || (!IS_LOCAL(source)))
+               {
+                       return FounderProtectBase::HandleChange(source, theuser, adding, channel, parameter);
+               }
+               else
+               {
+                       // bzzzt, wrong answer!
+                       source->WriteServ("482 %s %s :You are not a channel founder",source->nick, channel->name);
+                       return MODEACTION_DENY;
+               }
+       }
+
+       virtual void DisplayList(userrec* user, chanrec* channel)
+       {
+               FounderProtectBase::DisplayList(user, channel);
+       }
+
+};
+
+class ModuleChanProtect : public Module
+{
+       
+       bool FirstInGetsFounder;
+       bool QAPrefixes;
+       bool DeprivSelf;
+       bool DeprivOthers;
+       bool booting;
+       ChanProtect* cp;
+       ChanFounder* cf;
+       char* dummyptr;
+       
+ public:
+       ModuleChanProtect(InspIRCd* Me)
+               : Module(Me), FirstInGetsFounder(false), QAPrefixes(false), DeprivSelf(false), DeprivOthers(false), booting(true)
+       {       
+               /* Load config stuff */
+               OnRehash(NULL,"");
+               booting = false;
+
+               /* Initialise module variables */
+
+               cp = new ChanProtect(ServerInstance,QAPrefixes,DeprivSelf,DeprivOthers);
+               cf = new ChanFounder(ServerInstance,QAPrefixes,DeprivSelf,DeprivOthers);
+
+               if (!ServerInstance->AddMode(cp, 'a') || !ServerInstance->AddMode(cf, 'q'))
+                       throw ModuleException("Could not add new modes!");
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnUserKick] = List[I_OnUserPart] = List[I_OnRehash] = List[I_OnUserJoin] = List[I_OnAccessCheck] = List[I_OnSyncChannel] = 1;
+       }
+
+       virtual void OnUserKick(userrec* source, userrec* user, chanrec* chan, const std::string &reason, bool &silent)
+       {
+               // FIX: when someone gets kicked from a channel we must remove their Extensibles!
+               user->Shrink("cm_founder_"+std::string(chan->name));
+               user->Shrink("cm_protect_"+std::string(chan->name));
+       }
+
+       virtual void OnUserPart(userrec* user, chanrec* channel, const std::string &partreason, bool &silent)
+       {
+               // FIX: when someone parts a channel we must remove their Extensibles!
+               user->Shrink("cm_founder_"+std::string(channel->name));
+               user->Shrink("cm_protect_"+std::string(channel->name));
+       }
+
+       virtual void OnRehash(userrec* user, const std::string &parameter)
+       {
+               /* Create a configreader class and read our flag,
+                * in old versions this was heap-allocated and the
+                * object was kept between rehashes...now we just
+                * stack-allocate it locally.
+                */
+               ConfigReader Conf(ServerInstance);
+
+               bool old_qa = QAPrefixes;
+
+               FirstInGetsFounder = Conf.ReadFlag("options","noservices",0);
+               QAPrefixes = Conf.ReadFlag("options","qaprefixes",0);
+               DeprivSelf = Conf.ReadFlag("options","deprotectself",0);
+               DeprivOthers = Conf.ReadFlag("options","deprotectothers",0);
+
+               /* Did the user change the QA prefixes on the fly?
+                * If so, remove all instances of the mode, and reinit
+                * the module with prefixes enabled.
+                */
+               if ((old_qa != QAPrefixes) && (!booting))
+               {
+                       ServerInstance->Modes->DelMode(cp);
+                       ServerInstance->Modes->DelMode(cf);
+                       DELETE(cp);
+                       DELETE(cf);
+                       cp = new ChanProtect(ServerInstance,QAPrefixes,DeprivSelf,DeprivOthers);
+                       cf = new ChanFounder(ServerInstance,QAPrefixes,DeprivSelf,DeprivOthers);
+                       /* These wont fail, we already owned the mode characters before */
+                       ServerInstance->AddMode(cp, 'a');
+                       ServerInstance->AddMode(cf, 'q');
+                       ServerInstance->WriteOpers("*** WARNING: +qa prefixes were enabled or disabled via a REHASH. Clients will probably need to reconnect to pick up this change.");
+               }
+       }
+       
+       virtual void OnUserJoin(userrec* user, chanrec* channel, bool &silent)
+       {
+               // if the user is the first user into the channel, mark them as the founder, but only if
+               // the config option for it is set
+               if (FirstInGetsFounder)
+               {
+                       if (channel->GetUserCounter() == 1)
+                       {
+                               // we're using Extensible::Extend to add data into user objects.
+                               // this way is best as it adds data thats accessible to other modules
+                               // (so long as you document your code properly) without breaking anything
+                               // because its encapsulated neatly in a map.
+
+                               // Change requested by katsklaw... when the first in is set to get founder,
+                               // to make it clearer that +q has been given, send that one user the +q notice
+                               // so that their client's syncronization and their sanity are left intact.
+                               user->WriteServ("MODE %s +q %s",channel->name,user->nick);
+                               user->Extend("cm_founder_"+std::string(channel->name),fakevalue);
+                       }
+               }
+       }
+       
+       virtual int OnAccessCheck(userrec* source,userrec* dest,chanrec* channel,int access_type)
+       {
+               // here we perform access checks, this is the important bit that actually stops kicking/deopping
+               // etc of protected users. There are many types of access check, we're going to handle
+               // a relatively small number of them relevent to our module using a switch statement.
+               // don't allow action if:
+               // (A) Theyre founder (no matter what)
+               // (B) Theyre protected, and you're not
+               // always allow the action if:
+               // (A) The source is ulined
+               
+               
+               // firstly, if a ulined nick, or a server, is setting the mode, then allow them to set the mode
+               // without any access checks, we're not worthy :p
+               if ((ServerInstance->ULine(source->nick)) || (ServerInstance->ULine(source->server)) || (!*source->server))
+                       return ACR_ALLOW;
+
+               std::string founder = "cm_founder_"+std::string(channel->name);
+               std::string protect = "cm_protect_"+std::string(channel->name);
+
+               switch (access_type)
+               {
+                       // a user has been deopped. Do we let them? hmmm...
+                       case AC_DEOP:
+                               if (dest->GetExt(founder,dummyptr))
+                               {
+                                       source->WriteServ("484 "+std::string(source->nick)+" "+std::string(channel->name)+" :Can't deop "+std::string(dest->nick)+" as they're a channel founder");
+                                       return ACR_DENY;
+                               }
+                               if ((dest->GetExt(protect,dummyptr)) && (!source->GetExt(protect,dummyptr)))
+                               {
+                                       source->WriteServ("484 "+std::string(source->nick)+" "+std::string(channel->name)+" :Can't deop "+std::string(dest->nick)+" as they're protected (+a)");
+                                       return ACR_DENY;
+                               }
+                       break;
+
+                       // a user is being kicked. do we chop off the end of the army boot?
+                       case AC_KICK:
+                               if (dest->GetExt(founder,dummyptr))
+                               {
+                                       source->WriteServ("484 "+std::string(source->nick)+" "+std::string(channel->name)+" :Can't kick "+std::string(dest->nick)+" as they're a channel founder");
+                                       return ACR_DENY;
+                               }
+                               if ((dest->GetExt(protect,dummyptr)) && (!source->GetExt(protect,dummyptr)))
+                               {
+                                       source->WriteServ("484 "+std::string(source->nick)+" "+std::string(channel->name)+" :Can't kick "+std::string(dest->nick)+" as they're protected (+a)");
+                                       return ACR_DENY;
+                               }
+                       break;
+
+                       // a user is being dehalfopped. Yes, we do disallow -h of a +ha user
+                       case AC_DEHALFOP:
+                               if (dest->GetExt(founder,dummyptr))
+                               {
+                                       source->WriteServ("484 "+std::string(source->nick)+" "+std::string(channel->name)+" :Can't de-halfop "+std::string(dest->nick)+" as they're a channel founder");
+                                       return ACR_DENY;
+                               }
+                               if ((dest->GetExt(protect,dummyptr)) && (!source->GetExt(protect,dummyptr)))
+                               {
+                                       source->WriteServ("484 "+std::string(source->nick)+" "+std::string(channel->name)+" :Can't de-halfop "+std::string(dest->nick)+" as they're protected (+a)");
+                                       return ACR_DENY;
+                               }
+                       break;
+
+                       // same with devoice.
+                       case AC_DEVOICE:
+                               if (dest->GetExt(founder,dummyptr))
+                               {
+                                       source->WriteServ("484 "+std::string(source->nick)+" "+std::string(channel->name)+" :Can't devoice "+std::string(dest->nick)+" as they're a channel founder");
+                                       return ACR_DENY;
+                               }
+                               if ((dest->GetExt(protect,dummyptr)) && (!source->GetExt(protect,dummyptr)))
+                               {
+                                       source->WriteServ("484 "+std::string(source->nick)+" "+std::string(channel->name)+" :Can't devoice "+std::string(dest->nick)+" as they're protected (+a)");
+                                       return ACR_DENY;
+                               }
+                       break;
+               }
+               
+               // we dont know what this access check is, or dont care. just carry on, nothing to see here.
+               return ACR_DEFAULT;
+       }
+       
+       virtual ~ModuleChanProtect()
+       {
+               ServerInstance->Modes->DelMode(cp);
+               ServerInstance->Modes->DelMode(cf);
+               DELETE(cp);
+               DELETE(cf);
+       }
+       
+       virtual Version GetVersion()
+       {
+               return Version(1, 1, 0, 0, VF_COMMON | VF_VENDOR, API_VERSION);
+       }
+       
+       virtual void OnSyncChannel(chanrec* chan, Module* proto, void* opaque)
+       {
+               /* NOTE: If +qa prefix is on, this is propogated by the channel join,
+                * so we dont need to propogate it manually
+                */
+               if (!QAPrefixes)
+               {
+                       // this is called when the server is linking into a net and wants to sync channel data.
+                       // we should send our mode changes for the channel here to ensure that other servers
+                       // know whos +q/+a on the channel.
+                       CUList* cl = chan->GetUsers();
+                       string_list commands;
+                       std::string founder = "cm_founder_"+std::string(chan->name);
+                       std::string protect = "cm_protect_"+std::string(chan->name);
+                       irc::modestacker modestack(true);
+                       std::deque<std::string> stackresult;
+                       for (CUList::iterator i = cl->begin(); i != cl->end(); i++)
+                       {
+                               if (i->first->GetExt(founder,dummyptr))
+                               {
+                                       modestack.Push('q',i->first->nick);
+                               }
+                               if (i->first->GetExt(protect,dummyptr))
+                               {
+                                       modestack.Push('a',i->first->nick);
+                               }
+                       }
+                       while (modestack.GetStackedLine(stackresult))
+                       {
+                               irc::stringjoiner mode_join(" ", stackresult, 0, stackresult.size() - 1);
+                               std::string line = mode_join.GetJoined();
+                               proto->ProtoSendMode(opaque,TYPE_CHANNEL,chan, line);
+                       }
+               }
+       }
+
+};
+
+MODULE_INIT(ModuleChanProtect)
index c99e985cc3dab16c3c00b1a07eb17f26a9615bc3..643af8e15d0d955713d2444acda716fe1944e554 100644 (file)
@@ -1 +1,188 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r#include "wildcard.h"\r\r/* $ModDesc: Provides the /check command to retrieve information on a user, channel, or IP address */\r\r/** Handle /CHECK\r */\rclass cmd_check : public command_t\r{\r public:\r     cmd_check (InspIRCd* Instance) : command_t(Instance,"CHECK", 'o', 1)\r   {\r              this->source = "m_check.so";\r           syntax = "<nickname>|<ip>|<hostmask>|<channel>";\r       }\r\r     CmdResult Handle (const char** parameters, int pcnt, userrec *user)\r    {\r              userrec *targuser;\r             chanrec *targchan;\r             std::string checkstr;\r          std::string chliststr;\r\r                char timebuf[60];\r              struct tm *mytime;\r\r\r           checkstr = "304 " + std::string(user->nick) + " :CHECK";\r\r              targuser = ServerInstance->FindNick(parameters[0]);\r            targchan = ServerInstance->FindChan(parameters[0]);\r\r           /*\r              * Syntax of a /check reply:\r            *  :server.name 304 target :CHECK START <target>\r               *  :server.name 304 target :CHECK <field> <value>\r              *  :server.name 304 target :CHECK END\r          */\r\r           user->WriteServ(checkstr + " START " + parameters[0]);\r\r                if (targuser)\r          {\r                      /* /check on a user */\r                 user->WriteServ(checkstr + " nuh " + targuser->GetFullHost());\r                 user->WriteServ(checkstr + " realnuh " + targuser->GetFullRealHost());\r                 user->WriteServ(checkstr + " realname " + targuser->fullname);\r                 user->WriteServ(checkstr + " modes +" + targuser->FormatModes());\r                      user->WriteServ(checkstr + " snomasks +" + targuser->FormatNoticeMasks());\r                     user->WriteServ(checkstr + " server " + targuser->server);\r\r                    if (IS_AWAY(targuser))\r                 {\r                              /* user is away */\r                             user->WriteServ(checkstr + " awaymsg " + targuser->awaymsg);\r                   }\r\r                     if (IS_OPER(targuser))\r                 {\r                              /* user is an oper of type ____ */\r                             user->WriteServ(checkstr + " opertype " + irc::Spacify(targuser->oper));\r                       }\r\r                     if (IS_LOCAL(targuser))\r                        {\r                              /* port information is only held for a local user! */\r                          user->WriteServ(checkstr + " onport " + ConvToStr(targuser->GetPort()));\r                       }\r\r                     chliststr = targuser->ChannelList(targuser);\r                   std::stringstream dump(chliststr);\r\r                    ServerInstance->DumpText(user,checkstr + " onchans ", dump);\r           }\r              else if (targchan)\r             {\r                      /* /check on a channel */\r                      time_t creation_time = targchan->created;\r                      time_t topic_time = targchan->topicset;\r\r                       mytime = gmtime(&creation_time);\r                       strftime(timebuf, 59, "%Y/%m/%d - %H:%M:%S", mytime);\r                  user->WriteServ(checkstr + " created " + timebuf);\r\r                    if (targchan->topic[0] != 0)\r                   {\r                              /* there is a topic, assume topic related information exists */\r                                user->WriteServ(checkstr + " topic " + targchan->topic);\r                               user->WriteServ(checkstr + " topic_setby " + targchan->setby);\r                         mytime = gmtime(&topic_time);\r                          strftime(timebuf, 59, "%Y/%m/%d - %H:%M:%S", mytime);\r                          user->WriteServ(checkstr + " topic_setat " + timebuf);\r                 }\r\r                     user->WriteServ(checkstr + " modes " + targchan->ChanModes(true));\r                     user->WriteServ(checkstr + " membercount " + ConvToStr(targchan->GetUserCounter()));\r                   \r                       /* now the ugly bit, spool current members of a channel. :| */\r\r                        CUList *ulist= targchan->GetUsers();\r\r                  /* note that unlike /names, we do NOT check +i vs in the channel */\r                    for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)\r                      {\r                              char tmpbuf[MAXBUF];\r                           /*\r                              * Unlike Asuka, I define a clone as coming from the same host. --w00t\r                          */\r                            snprintf(tmpbuf, MAXBUF, "%lu    %s%s (%s@%s) %s ", i->first->GlobalCloneCount(), targchan->GetAllPrefixChars(i->first), i->first->nick, i->first->ident, i->first->dhost, i->first->fullname);\r                                user->WriteServ(checkstr + " member " + tmpbuf);\r                       }\r              }\r              else\r           {\r                      /*  /check on an IP address, or something that doesn't exist */\r                        long x = 0;\r\r                   /* hostname or other */\r                        for (user_hash::const_iterator a = ServerInstance->clientlist->begin(); a != ServerInstance->clientlist->end(); a++)\r                   {\r                              if (match(a->second->host, parameters[0]) || match(a->second->dhost, parameters[0]))\r                           {\r                                      /* host or vhost matches mask */\r                                       user->WriteServ(checkstr + " match " + ConvToStr(++x) + " " + a->second->GetFullRealHost());\r                           }\r                              /* IP address */\r                               else if (match(a->second->GetIPString(), parameters[0], true))\r                         {\r                                      /* same IP. */\r                                 user->WriteServ(checkstr + " match " + ConvToStr(++x) + " " + a->second->GetFullRealHost());\r                           }\r                      }\r\r                     user->WriteServ(checkstr + " matches " + ConvToStr(x));\r                }\r\r             user->WriteServ(checkstr + " END " + std::string(parameters[0]));\r\r             return CMD_LOCALONLY;\r  }\r};\r\r\rclass ModuleCheck : public Module\r{\r private:\r   cmd_check *mycommand;\r public:\r ModuleCheck(InspIRCd* Me) : Module(Me)\r {\r              \r               mycommand = new cmd_check(ServerInstance);\r             ServerInstance->AddCommand(mycommand);\r }\r      \r       virtual ~ModuleCheck()\r {\r      }\r      \r       virtual Version GetVersion()\r   {\r              return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION);\r    }\r\r     void Implements(char* List)\r    {\r              /* we don't hook anything, nothing required */\r }\r      \r};\r\rMODULE_INIT(ModuleCheck)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+#include "wildcard.h"
+
+/* $ModDesc: Provides the /check command to retrieve information on a user, channel, or IP address */
+
+/** Handle /CHECK
+ */
+class cmd_check : public command_t
+{
+ public:
+       cmd_check (InspIRCd* Instance) : command_t(Instance,"CHECK", 'o', 1)
+       {
+               this->source = "m_check.so";
+               syntax = "<nickname>|<ip>|<hostmask>|<channel>";
+       }
+
+       CmdResult Handle (const char** parameters, int pcnt, userrec *user)
+       {
+               userrec *targuser;
+               chanrec *targchan;
+               std::string checkstr;
+               std::string chliststr;
+
+               char timebuf[60];
+               struct tm *mytime;
+
+
+               checkstr = "304 " + std::string(user->nick) + " :CHECK";
+
+               targuser = ServerInstance->FindNick(parameters[0]);
+               targchan = ServerInstance->FindChan(parameters[0]);
+
+               /*
+                * Syntax of a /check reply:
+                *  :server.name 304 target :CHECK START <target>
+                *  :server.name 304 target :CHECK <field> <value>
+                *  :server.name 304 target :CHECK END
+                */
+
+               user->WriteServ(checkstr + " START " + parameters[0]);
+
+               if (targuser)
+               {
+                       /* /check on a user */
+                       user->WriteServ(checkstr + " nuh " + targuser->GetFullHost());
+                       user->WriteServ(checkstr + " realnuh " + targuser->GetFullRealHost());
+                       user->WriteServ(checkstr + " realname " + targuser->fullname);
+                       user->WriteServ(checkstr + " modes +" + targuser->FormatModes());
+                       user->WriteServ(checkstr + " snomasks +" + targuser->FormatNoticeMasks());
+                       user->WriteServ(checkstr + " server " + targuser->server);
+
+                       if (IS_AWAY(targuser))
+                       {
+                               /* user is away */
+                               user->WriteServ(checkstr + " awaymsg " + targuser->awaymsg);
+                       }
+
+                       if (IS_OPER(targuser))
+                       {
+                               /* user is an oper of type ____ */
+                               user->WriteServ(checkstr + " opertype " + irc::Spacify(targuser->oper));
+                       }
+
+                       if (IS_LOCAL(targuser))
+                       {
+                               /* port information is only held for a local user! */
+                               user->WriteServ(checkstr + " onport " + ConvToStr(targuser->GetPort()));
+                       }
+
+                       chliststr = targuser->ChannelList(targuser);
+                       std::stringstream dump(chliststr);
+
+                       ServerInstance->DumpText(user,checkstr + " onchans ", dump);
+               }
+               else if (targchan)
+               {
+                       /* /check on a channel */
+                       time_t creation_time = targchan->created;
+                       time_t topic_time = targchan->topicset;
+
+                       mytime = gmtime(&creation_time);
+                       strftime(timebuf, 59, "%Y/%m/%d - %H:%M:%S", mytime);
+                       user->WriteServ(checkstr + " created " + timebuf);
+
+                       if (targchan->topic[0] != 0)
+                       {
+                               /* there is a topic, assume topic related information exists */
+                               user->WriteServ(checkstr + " topic " + targchan->topic);
+                               user->WriteServ(checkstr + " topic_setby " + targchan->setby);
+                               mytime = gmtime(&topic_time);
+                               strftime(timebuf, 59, "%Y/%m/%d - %H:%M:%S", mytime);
+                               user->WriteServ(checkstr + " topic_setat " + timebuf);
+                       }
+
+                       user->WriteServ(checkstr + " modes " + targchan->ChanModes(true));
+                       user->WriteServ(checkstr + " membercount " + ConvToStr(targchan->GetUserCounter()));
+                       
+                       /* now the ugly bit, spool current members of a channel. :| */
+
+                       CUList *ulist= targchan->GetUsers();
+
+                       /* note that unlike /names, we do NOT check +i vs in the channel */
+                       for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
+                       {
+                               char tmpbuf[MAXBUF];
+                               /*
+                                * Unlike Asuka, I define a clone as coming from the same host. --w00t
+                                */
+                               snprintf(tmpbuf, MAXBUF, "%lu    %s%s (%s@%s) %s ", i->first->GlobalCloneCount(), targchan->GetAllPrefixChars(i->first), i->first->nick, i->first->ident, i->first->dhost, i->first->fullname);
+                               user->WriteServ(checkstr + " member " + tmpbuf);
+                       }
+               }
+               else
+               {
+                       /*  /check on an IP address, or something that doesn't exist */
+                       long x = 0;
+
+                       /* hostname or other */
+                       for (user_hash::const_iterator a = ServerInstance->clientlist->begin(); a != ServerInstance->clientlist->end(); a++)
+                       {
+                               if (match(a->second->host, parameters[0]) || match(a->second->dhost, parameters[0]))
+                               {
+                                       /* host or vhost matches mask */
+                                       user->WriteServ(checkstr + " match " + ConvToStr(++x) + " " + a->second->GetFullRealHost());
+                               }
+                               /* IP address */
+                               else if (match(a->second->GetIPString(), parameters[0], true))
+                               {
+                                       /* same IP. */
+                                       user->WriteServ(checkstr + " match " + ConvToStr(++x) + " " + a->second->GetFullRealHost());
+                               }
+                       }
+
+                       user->WriteServ(checkstr + " matches " + ConvToStr(x));
+               }
+
+               user->WriteServ(checkstr + " END " + std::string(parameters[0]));
+
+               return CMD_LOCALONLY;
+       }
+};
+
+
+class ModuleCheck : public Module
+{
+ private:
+       cmd_check *mycommand;
+ public:
+       ModuleCheck(InspIRCd* Me) : Module(Me)
+       {
+               
+               mycommand = new cmd_check(ServerInstance);
+               ServerInstance->AddCommand(mycommand);
+       }
+       
+       virtual ~ModuleCheck()
+       {
+       }
+       
+       virtual Version GetVersion()
+       {
+               return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION);
+       }
+
+       void Implements(char* List)
+       {
+               /* we don't hook anything, nothing required */
+       }
+       
+};
+
+MODULE_INIT(ModuleCheck)
index 9fb751b8e0e586d76054a5203c15da72fd514770..0ec88d7e1e11d74f27025e4c6917a41a044bb2a5 100644 (file)
@@ -1 +1,120 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r\r/* $ModDesc: Provides support for the CHGHOST command */\r\r/** Handle /CHGHOST\r */\rclass cmd_chghost : public command_t\r{\r private:\r   char* hostmap;\r public:\r        cmd_chghost (InspIRCd* Instance, char* hmap) : command_t(Instance,"CHGHOST",'o',2), hostmap(hmap)\r      {\r              this->source = "m_chghost.so";\r         syntax = "<nick> <newhost>";\r   }\r \r    CmdResult Handle(const char** parameters, int pcnt, userrec *user)\r     {\r              const char * x = parameters[1];\r\r               for (; *x; x++)\r                {\r                      if (!hostmap[(unsigned char)*x])\r                       {\r                              user->WriteServ("NOTICE "+std::string(user->nick)+" :*** CHGHOST: Invalid characters in hostname");\r                            return CMD_FAILURE;\r                    }\r              }\r              if (!*parameters[0])\r           {\r                      user->WriteServ("NOTICE %s :*** CHGHOST: Host must be specified", user->nick);\r                 return CMD_FAILURE;\r            }\r              \r               if ((parameters[1] - x) > 63)\r          {\r                      user->WriteServ("NOTICE %s :*** CHGHOST: Host too long", user->nick);\r                  return CMD_FAILURE;\r            }\r              userrec* dest = ServerInstance->FindNick(parameters[0]);\r\r              if (!dest)\r             {\r                      user->WriteServ("401 %s %s :No such nick/channel", user->nick, parameters[0]);\r                 return CMD_FAILURE;\r            }\r\r             if ((dest->ChangeDisplayedHost(parameters[1])) && (!ServerInstance->ULine(user->server)))\r              {\r                      // fix by brain - ulines set hosts silently\r                    ServerInstance->WriteOpers(std::string(user->nick)+" used CHGHOST to make the displayed host of "+dest->nick+" become "+dest->dhost);\r          }\r\r             /* route it! */\r                return CMD_SUCCESS;\r\r   }\r};\r\r\rclass ModuleChgHost : public Module\r{\r   cmd_chghost* mycommand;\r        char hostmap[256];\r public:\r    ModuleChgHost(InspIRCd* Me)\r            : Module(Me)\r   {\r              OnRehash(NULL,"");\r             mycommand = new cmd_chghost(ServerInstance, hostmap);\r          ServerInstance->AddCommand(mycommand);\r }\r\r     void Implements(char* List)\r    {\r              List[I_OnRehash] = 1;\r  }\r      \r       void OnRehash(userrec* user, const std::string &parameter)\r     {\r              ConfigReader Conf(ServerInstance);\r             std::string hmap = Conf.ReadValue("hostname", "charmap", 0);\r\r          if (hmap.empty())\r                      hmap = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.-_/0123456789";\r\r          memset(&hostmap, 0, 255);\r              for (std::string::iterator n = hmap.begin(); n != hmap.end(); n++)\r                     hostmap[(unsigned char)*n] = 1;\r        }\r\r     ~ModuleChgHost()\r       {\r      }\r      \r       Version GetVersion()\r   {\r              return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION);\r    }\r      \r};\r\rMODULE_INIT(ModuleChgHost)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+
+/* $ModDesc: Provides support for the CHGHOST command */
+
+/** Handle /CHGHOST
+ */
+class cmd_chghost : public command_t
+{
+ private:
+       char* hostmap;
+ public:
+       cmd_chghost (InspIRCd* Instance, char* hmap) : command_t(Instance,"CHGHOST",'o',2), hostmap(hmap)
+       {
+               this->source = "m_chghost.so";
+               syntax = "<nick> <newhost>";
+       }
+       CmdResult Handle(const char** parameters, int pcnt, userrec *user)
+       {
+               const char * x = parameters[1];
+
+               for (; *x; x++)
+               {
+                       if (!hostmap[(unsigned char)*x])
+                       {
+                               user->WriteServ("NOTICE "+std::string(user->nick)+" :*** CHGHOST: Invalid characters in hostname");
+                               return CMD_FAILURE;
+                       }
+               }
+               if (!*parameters[0])
+               {
+                       user->WriteServ("NOTICE %s :*** CHGHOST: Host must be specified", user->nick);
+                       return CMD_FAILURE;
+               }
+               
+               if ((parameters[1] - x) > 63)
+               {
+                       user->WriteServ("NOTICE %s :*** CHGHOST: Host too long", user->nick);
+                       return CMD_FAILURE;
+               }
+               userrec* dest = ServerInstance->FindNick(parameters[0]);
+
+               if (!dest)
+               {
+                       user->WriteServ("401 %s %s :No such nick/channel", user->nick, parameters[0]);
+                       return CMD_FAILURE;
+               }
+
+               if ((dest->ChangeDisplayedHost(parameters[1])) && (!ServerInstance->ULine(user->server)))
+               {
+                       // fix by brain - ulines set hosts silently
+                       ServerInstance->WriteOpers(std::string(user->nick)+" used CHGHOST to make the displayed host of "+dest->nick+" become "+dest->dhost);
+               }
+
+               /* route it! */
+               return CMD_SUCCESS;
+
+       }
+};
+
+
+class ModuleChgHost : public Module
+{
+       cmd_chghost* mycommand;
+       char hostmap[256];
+ public:
+       ModuleChgHost(InspIRCd* Me)
+               : Module(Me)
+       {
+               OnRehash(NULL,"");
+               mycommand = new cmd_chghost(ServerInstance, hostmap);
+               ServerInstance->AddCommand(mycommand);
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnRehash] = 1;
+       }
+       
+       void OnRehash(userrec* user, const std::string &parameter)
+       {
+               ConfigReader Conf(ServerInstance);
+               std::string hmap = Conf.ReadValue("hostname", "charmap", 0);
+
+               if (hmap.empty())
+                       hmap = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.-_/0123456789";
+
+               memset(&hostmap, 0, 255);
+               for (std::string::iterator n = hmap.begin(); n != hmap.end(); n++)
+                       hostmap[(unsigned char)*n] = 1;
+       }
+
+       ~ModuleChgHost()
+       {
+       }
+       
+       Version GetVersion()
+       {
+               return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION);
+       }
+       
+};
+
+MODULE_INIT(ModuleChgHost)
index fb909b7ff1b000a67585aa4223b547034d596c60..168adcc93c2f571c2ca129953c7de2f3e2541dc2 100644 (file)
@@ -1 +1,92 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "modules.h"\r\r/* $ModDesc: Provides support for the CHGIDENT command */\r\r/** Handle /CHGIDENT\r */\rclass cmd_chgident : public command_t\r{\r public:\r       cmd_chgident (InspIRCd* Instance) : command_t(Instance,"CHGIDENT", 'o', 2)\r     {\r              this->source = "m_chgident.so";\r                syntax = "<nick> <newident>";\r  }\r      \r       CmdResult Handle(const char** parameters, int pcnt, userrec *user)\r     {\r              userrec* dest = ServerInstance->FindNick(parameters[0]);\r\r              if (!dest)\r             {\r                      user->WriteServ("401 %s %s :No such nick/channel", user->nick, parameters[0]);\r                 return CMD_FAILURE;\r            }\r\r             if (!*parameters[1])\r           {\r                      user->WriteServ("NOTICE %s :*** CHGIDENT: Ident must be specified", user->nick);\r                       return CMD_FAILURE;\r            }\r              \r               if (strlen(parameters[1]) > IDENTMAX)\r          {\r                      user->WriteServ("NOTICE %s :*** CHGIDENT: Ident is too long", user->nick);\r                     return CMD_FAILURE;\r            }\r              \r               if (!ServerInstance->IsIdent(parameters[1]))\r           {\r                      user->WriteServ("NOTICE %s :*** CHGIDENT: Invalid characters in ident", user->nick);\r                   return CMD_FAILURE;\r            }\r\r             dest->ChangeIdent(parameters[1]);\r              ServerInstance->WriteOpers("%s used CHGIDENT to change %s's ident to '%s'", user->nick, dest->nick, dest->ident);\r\r             /* route it! */\r                return CMD_SUCCESS;\r    }\r};\r\r\rclass ModuleChgIdent : public Module\r{\r  cmd_chgident* mycommand;\r       \r       \rpublic:\r       ModuleChgIdent(InspIRCd* Me) : Module(Me)\r      {\r              mycommand = new cmd_chgident(ServerInstance);\r          ServerInstance->AddCommand(mycommand);\r }\r      \r       virtual ~ModuleChgIdent()\r      {\r      }\r      \r       virtual Version GetVersion()\r   {\r              return Version(1,1,0,0,VF_VENDOR,API_VERSION);\r }\r      \r};\r\rMODULE_INIT(ModuleChgIdent)\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "modules.h"
+
+/* $ModDesc: Provides support for the CHGIDENT command */
+
+/** Handle /CHGIDENT
+ */
+class cmd_chgident : public command_t
+{
+ public:
+       cmd_chgident (InspIRCd* Instance) : command_t(Instance,"CHGIDENT", 'o', 2)
+       {
+               this->source = "m_chgident.so";
+               syntax = "<nick> <newident>";
+       }
+       
+       CmdResult Handle(const char** parameters, int pcnt, userrec *user)
+       {
+               userrec* dest = ServerInstance->FindNick(parameters[0]);
+
+               if (!dest)
+               {
+                       user->WriteServ("401 %s %s :No such nick/channel", user->nick, parameters[0]);
+                       return CMD_FAILURE;
+               }
+
+               if (!*parameters[1])
+               {
+                       user->WriteServ("NOTICE %s :*** CHGIDENT: Ident must be specified", user->nick);
+                       return CMD_FAILURE;
+               }
+               
+               if (strlen(parameters[1]) > IDENTMAX)
+               {
+                       user->WriteServ("NOTICE %s :*** CHGIDENT: Ident is too long", user->nick);
+                       return CMD_FAILURE;
+               }
+               
+               if (!ServerInstance->IsIdent(parameters[1]))
+               {
+                       user->WriteServ("NOTICE %s :*** CHGIDENT: Invalid characters in ident", user->nick);
+                       return CMD_FAILURE;
+               }
+
+               dest->ChangeIdent(parameters[1]);
+               ServerInstance->WriteOpers("%s used CHGIDENT to change %s's ident to '%s'", user->nick, dest->nick, dest->ident);
+
+               /* route it! */
+               return CMD_SUCCESS;
+       }
+};
+
+
+class ModuleChgIdent : public Module
+{
+       cmd_chgident* mycommand;
+       
+       
+public:
+       ModuleChgIdent(InspIRCd* Me) : Module(Me)
+       {
+               mycommand = new cmd_chgident(ServerInstance);
+               ServerInstance->AddCommand(mycommand);
+       }
+       
+       virtual ~ModuleChgIdent()
+       {
+       }
+       
+       virtual Version GetVersion()
+       {
+               return Version(1,1,0,0,VF_VENDOR,API_VERSION);
+       }
+       
+};
+
+MODULE_INIT(ModuleChgIdent)
+
index 0bf9004dd981e4f145c8d1521328f06bf0f5d2a3..a4a31714b1bf367ee25f41b92e75d90b06f0ce1d 100644 (file)
@@ -1 +1,89 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "modules.h"\r\r/* $ModDesc: Provides support for the CHGNAME command */\r\r/** Handle /CHGNAME\r */\rclass cmd_chgname : public command_t\r{\r public:\r  cmd_chgname (InspIRCd* Instance) : command_t(Instance,"CHGNAME", 'o', 2)\r       {\r              this->source = "m_chgname.so";\r         syntax = "<nick> <newname>";\r   }\r      \r       CmdResult Handle(const char** parameters, int pcnt, userrec *user)\r     {\r              userrec* dest = ServerInstance->FindNick(parameters[0]);\r\r              if (!dest)\r             {\r                      user->WriteServ("401 %s %s :No such nick/channel", user->nick, parameters[0]);\r                 return CMD_FAILURE;\r            }\r              \r               if (!*parameters[1])\r           {\r                      user->WriteServ("NOTICE %s :*** GECOS must be specified", user->nick);\r                 return CMD_FAILURE;\r            }\r              \r               if (strlen(parameters[1]) > MAXGECOS)\r          {\r                      user->WriteServ("NOTICE %s :*** GECOS too long", user->nick);\r                  return CMD_FAILURE;\r            }\r              \r               if (IS_LOCAL(dest))\r            {\r                      dest->ChangeName(parameters[1]);\r                       ServerInstance->WriteOpers("%s used CHGNAME to change %s's real name to '%s'", user->nick, dest->nick, dest->fullname);\r                        return CMD_LOCALONLY; /* name change routed by FNAME in spanningtree now */\r            }\r\r             /* route it! */\r                return CMD_SUCCESS;\r    }\r};\r\r\rclass ModuleChgName : public Module\r{\r   cmd_chgname* mycommand;\r        \r       \rpublic:\r       ModuleChgName(InspIRCd* Me) : Module(Me)\r       {\r              mycommand = new cmd_chgname(ServerInstance);\r           ServerInstance->AddCommand(mycommand);\r }\r      \r       virtual ~ModuleChgName()\r       {\r      }\r      \r       virtual Version GetVersion()\r   {\r              return Version(1,1,0,0,VF_VENDOR,API_VERSION);\r }\r      \r};\r\rMODULE_INIT(ModuleChgName)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "modules.h"
+
+/* $ModDesc: Provides support for the CHGNAME command */
+
+/** Handle /CHGNAME
+ */
+class cmd_chgname : public command_t
+{
+ public:
+       cmd_chgname (InspIRCd* Instance) : command_t(Instance,"CHGNAME", 'o', 2)
+       {
+               this->source = "m_chgname.so";
+               syntax = "<nick> <newname>";
+       }
+       
+       CmdResult Handle(const char** parameters, int pcnt, userrec *user)
+       {
+               userrec* dest = ServerInstance->FindNick(parameters[0]);
+
+               if (!dest)
+               {
+                       user->WriteServ("401 %s %s :No such nick/channel", user->nick, parameters[0]);
+                       return CMD_FAILURE;
+               }
+               
+               if (!*parameters[1])
+               {
+                       user->WriteServ("NOTICE %s :*** GECOS must be specified", user->nick);
+                       return CMD_FAILURE;
+               }
+               
+               if (strlen(parameters[1]) > MAXGECOS)
+               {
+                       user->WriteServ("NOTICE %s :*** GECOS too long", user->nick);
+                       return CMD_FAILURE;
+               }
+               
+               if (IS_LOCAL(dest))
+               {
+                       dest->ChangeName(parameters[1]);
+                       ServerInstance->WriteOpers("%s used CHGNAME to change %s's real name to '%s'", user->nick, dest->nick, dest->fullname);
+                       return CMD_LOCALONLY; /* name change routed by FNAME in spanningtree now */
+               }
+
+               /* route it! */
+               return CMD_SUCCESS;
+       }
+};
+
+
+class ModuleChgName : public Module
+{
+       cmd_chgname* mycommand;
+       
+       
+public:
+       ModuleChgName(InspIRCd* Me) : Module(Me)
+       {
+               mycommand = new cmd_chgname(ServerInstance);
+               ServerInstance->AddCommand(mycommand);
+       }
+       
+       virtual ~ModuleChgName()
+       {
+       }
+       
+       virtual Version GetVersion()
+       {
+               return Version(1,1,0,0,VF_VENDOR,API_VERSION);
+       }
+       
+};
+
+MODULE_INIT(ModuleChgName)
index d7992301cfa26390af033eec29a1a417d6974291..dfa5ee4e8b45603afa3041111ec178cf9ab17832 100644 (file)
@@ -1 +1,315 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r#include "m_hash.h"\r\r/* $ModDesc: Provides masking of user hostnames */\r/* $ModDep: m_hash.h */\r\r/* Used to vary the output a little more depending on the cloak keys */\rstatic const char* xtab[] = {"F92E45D871BCA630", "A1B9D80C72E653F4", "1ABC078934DEF562", "ABCDEF5678901234"};\r\r/** Handles user mode +x\r */\rclass CloakUser : public ModeHandler\r{\r   \r       std::string prefix;\r    unsigned int key1;\r     unsigned int key2;\r     unsigned int key3;\r     unsigned int key4;\r     Module* Sender;\r        Module* HashProvider;\r\r /** This function takes a domain name string and returns just the last two domain parts,\r        * or the last domain part if only two are available. Failing that it just returns what it was given.\r   *\r      * For example, if it is passed "svn.inspircd.org" it will return ".inspircd.org".\r      * If it is passed "brainbox.winbot.co.uk" it will return ".co.uk",\r     * and if it is passed "localhost.localdomain" it will return ".localdomain".\r   * \r     * This is used to ensure a significant part of the host is always cloaked (see Bug #216)\r       */\r    std::string LastTwoDomainParts(const std::string &host)\r        {\r              int dots = 0;\r          std::string::size_type splitdot = host.length();\r\r              for (std::string::size_type x = host.length() - 1; x; --x)\r             {\r                      if (host[x] == '.')\r                    {\r                              splitdot = x;\r                          dots++;\r                        }\r                      if (dots >= 3)\r                         break;\r         }\r\r             if (splitdot == host.length())\r                 return host;\r           else\r                   return host.substr(splitdot);\r  }\r      \r public:\r      CloakUser(InspIRCd* Instance, Module* Source, Module* Hash) : ModeHandler(Instance, 'x', 0, 0, false, MODETYPE_USER, false), Sender(Source), HashProvider(Hash)\r        {\r      }\r\r     ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)\r {\r              if (source != dest)\r                    return MODEACTION_DENY;\r\r               /* For remote clients, we dont take any action, we just allow it.\r               * The local server where they are will set their cloak instead.\r                */\r            if (!IS_LOCAL(dest))\r                   return MODEACTION_ALLOW;\r\r              if (adding)\r            {\r                      if(!dest->IsModeSet('x'))\r                      {\r                              /* The mode is being turned on - so attempt to\r                          * allocate the user a cloaked host using a non-reversible\r                              * algorithm (its simple, but its non-reversible so the\r                                 * simplicity doesnt really matter). This algorithm\r                             * will not work if the user has only one level of domain\r                               * naming in their hostname (e.g. if they are on a lan or\r                               * are connecting via localhost) -- this doesnt matter much.\r                            */\r\r                           char* n1 = strchr(dest->host,'.');\r                             char* n2 = strchr(dest->host,':');\r                     \r                               if (n1 || n2)\r                          {\r                                      /* InspIRCd users have two hostnames; A displayed\r                                       * hostname which can be modified by modules (e.g.\r                                      * to create vhosts, implement chghost, etc) and a\r                                      * 'real' hostname which you shouldnt write to.\r                                         */\r\r                                   unsigned int iv[] = { key1, key2, key3, key4 };\r                                        std::string a = LastTwoDomainParts(dest->host);\r                                        std::string b;\r\r                                        /** Reset the Hash module, and send it our IV and hex table */\r                                 HashResetRequest(Sender, HashProvider).Send();\r                                 HashKeyRequest(Sender, HashProvider, iv).Send();\r                                       HashHexRequest(Sender, HashProvider, xtab[(*dest->host) % 4]);\r\r                                        /* Generate a cloak using specialized Hash */\r                                  std::string hostcloak = prefix + "-" + std::string(HashSumRequest(Sender, HashProvider, dest->host).Send()).substr(0,8) + a;\r\r                                  /* Fix by brain - if the cloaked host is > the max length of a host (64 bytes\r                                   * according to the DNS RFC) then tough titty, they get cloaked as an IP. \r                                      * Their ISP shouldnt go to town on subdomains, or they shouldnt have a kiddie\r                                  * vhost.\r                                       */\r#ifdef IPV6\r                                        in6_addr testaddr;\r                                     in_addr testaddr2;\r                                     if ((dest->GetProtocolFamily() == AF_INET6) && (inet_pton(AF_INET6,dest->host,&testaddr) < 1) && (hostcloak.length() <= 64))\r                                           /* Invalid ipv6 address, and ipv6 user (resolved host) */\r                                              b = hostcloak;\r                                 else if ((dest->GetProtocolFamily() == AF_INET) && (inet_aton(dest->host,&testaddr2) < 1) && (hostcloak.length() <= 64))\r                                               /* Invalid ipv4 address, and ipv4 user (resolved host) */\r                                              b = hostcloak;\r                                 else\r                                           /* Valid ipv6 or ipv4 address (not resolved) ipv4 or ipv6 user */\r                                              b = ((!strchr(dest->host,':')) ? Cloak4(dest->host) : Cloak6(dest->host));\r#else\r                                       in_addr testaddr;\r                                      if ((inet_aton(dest->host,&testaddr) < 1) && (hostcloak.length() <= 64))\r                                               /* Invalid ipv4 address, and ipv4 user (resolved host) */\r                                              b = hostcloak;\r                                 else\r                                           /* Valid ipv4 address (not resolved) ipv4 user */\r                                              b = Cloak4(dest->host);\r#endif\r\r                                        dest->ChangeDisplayedHost(b.c_str());\r                          }\r                              \r                               dest->SetMode('x',true);\r                               return MODEACTION_ALLOW;\r                       }\r              }\r              else\r           {\r                      if (dest->IsModeSet('x'))\r                      {\r                              /* User is removing the mode, so just restore their real host\r                                   * and make it match the displayed one.\r                                 */\r                            dest->ChangeDisplayedHost(dest->host);\r                         dest->SetMode('x',false);\r                              return MODEACTION_ALLOW;\r                       }\r              }\r\r             return MODEACTION_DENY;\r        }\r\r     std::string Cloak4(const char* ip)\r     {\r              unsigned int iv[] = { key1, key2, key3, key4 };\r                irc::sepstream seps(ip, '.');\r          std::string ra[4];;\r            std::string octet[4];\r          int i[4];\r\r             for (int j = 0; j < 4; j++)\r            {\r                      octet[j] = seps.GetToken();\r                    i[j] = atoi(octet[j].c_str());\r         }\r\r             octet[3] = octet[0] + "." + octet[1] + "." + octet[2] + "." + octet[3];\r                octet[2] = octet[0] + "." + octet[1] + "." + octet[2];\r         octet[1] = octet[0] + "." + octet[1];\r\r         /* Reset the Hash module and send it our IV */\r         HashResetRequest(Sender, HashProvider).Send();\r         HashKeyRequest(Sender, HashProvider, iv).Send();\r\r              /* Send the Hash module a different hex table for each octet group's Hash sum */\r               for (int k = 0; k < 4; k++)\r            {\r                      HashHexRequest(Sender, HashProvider, xtab[(iv[k]+i[k]) % 4]).Send();\r                   ra[k] = std::string(HashSumRequest(Sender, HashProvider, octet[k]).Send()).substr(0,6);\r                }\r              /* Stick them all together */\r          return std::string().append(ra[0]).append(".").append(ra[1]).append(".").append(ra[2]).append(".").append(ra[3]);\r      }\r\r     std::string Cloak6(const char* ip)\r     {\r              /* Theyre using 4in6 (YUCK). Translate as ipv4 cloak */\r                if (!strncmp(ip, "0::ffff:", 8))\r                       return Cloak4(ip + 8);\r\r                /* If we get here, yes it really is an ipv6 ip */\r              unsigned int iv[] = { key1, key2, key3, key4 };\r                std::vector<std::string> hashies;\r              std::string item;\r              int rounds = 0;\r\r               /* Reset the Hash module and send it our IV */\r         HashResetRequest(Sender, HashProvider).Send();\r         HashKeyRequest(Sender, HashProvider, iv).Send();\r\r              for (const char* input = ip; *input; input++)\r          {\r                      item += *input;\r                        if (item.length() > 7)\r                 {\r                              /* Send the Hash module a different hex table for each octet group's Hash sum */\r                               HashHexRequest(Sender, HashProvider, xtab[(key1+rounds) % 4]).Send();\r                          hashies.push_back(std::string(HashSumRequest(Sender, HashProvider, item).Send()).substr(0,8));\r                         item.clear();\r                  }\r                      rounds++;\r              }\r              if (!item.empty())\r             {\r                      /* Send the Hash module a different hex table for each octet group's Hash sum */\r                       HashHexRequest(Sender, HashProvider, xtab[(key1+rounds) % 4]).Send();\r                  hashies.push_back(std::string(HashSumRequest(Sender, HashProvider, item).Send()).substr(0,8));\r                 item.clear();\r          }\r              /* Stick them all together */\r          return irc::stringjoiner(":", hashies, 0, hashies.size() - 1).GetJoined();\r     }\r      \r       void DoRehash()\r        {\r              ConfigReader Conf(ServerInstance);\r             key1 = key2 = key3 = key4 = 0;\r         key1 = Conf.ReadInteger("cloak","key1",0,true);\r                key2 = Conf.ReadInteger("cloak","key2",0,true);\r                key3 = Conf.ReadInteger("cloak","key3",0,true);\r                key4 = Conf.ReadInteger("cloak","key4",0,true);\r                prefix = Conf.ReadValue("cloak","prefix",0);\r\r          if (prefix.empty())\r                    prefix = ServerInstance->Config->Network;\r\r             if (!key1 && !key2 && !key3 && !key4)\r                  throw ModuleException("You have not defined cloak keys for m_cloaking!!! THIS IS INSECURE AND SHOULD BE CHECKED!");\r    }\r};\r\r\rclass ModuleCloaking : public Module\r{\r private:\r        \r       CloakUser* cu;\r Module* HashModule;\r\r public:\r  ModuleCloaking(InspIRCd* Me)\r           : Module(Me)\r   {\r              ServerInstance->UseInterface("HashRequest");\r\r          /* Attempt to locate the md5 service provider, bail if we can't find it */\r             HashModule = ServerInstance->FindModule("m_md5.so");\r           if (!HashModule)\r                       throw ModuleException("Can't find m_md5.so. Please load m_md5.so before m_cloaking.so.");\r\r             /* Create new mode handler object */\r           cu = new CloakUser(ServerInstance, this, HashModule);\r\r         /* Register it with the core */         \r               if (!ServerInstance->AddMode(cu, 'x'))\r                 throw ModuleException("Could not add new modes!");\r\r            OnRehash(NULL,"");\r     }\r      \r       virtual ~ModuleCloaking()\r      {\r              ServerInstance->Modes->DelMode(cu);\r            DELETE(cu);\r            ServerInstance->DoneWithInterface("HashRequest");\r      }\r      \r       virtual Version GetVersion()\r   {\r              // returns the version number of the module to be\r              // listed in /MODULES\r          return Version(1,1,0,2,VF_COMMON|VF_VENDOR,API_VERSION);\r       }\r\r     virtual void OnRehash(userrec* user, const std::string &parameter)\r     {\r              cu->DoRehash();\r        }\r\r     void Implements(char* List)\r    {\r              List[I_OnRehash] = 1;\r  }\r};\r\rMODULE_INIT(ModuleCloaking)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+#include "m_hash.h"
+
+/* $ModDesc: Provides masking of user hostnames */
+/* $ModDep: m_hash.h */
+
+/* Used to vary the output a little more depending on the cloak keys */
+static const char* xtab[] = {"F92E45D871BCA630", "A1B9D80C72E653F4", "1ABC078934DEF562", "ABCDEF5678901234"};
+
+/** Handles user mode +x
+ */
+class CloakUser : public ModeHandler
+{
+       
+       std::string prefix;
+       unsigned int key1;
+       unsigned int key2;
+       unsigned int key3;
+       unsigned int key4;
+       Module* Sender;
+       Module* HashProvider;
+
+       /** This function takes a domain name string and returns just the last two domain parts,
+        * or the last domain part if only two are available. Failing that it just returns what it was given.
+        *
+        * For example, if it is passed "svn.inspircd.org" it will return ".inspircd.org".
+        * If it is passed "brainbox.winbot.co.uk" it will return ".co.uk",
+        * and if it is passed "localhost.localdomain" it will return ".localdomain".
+        * 
+        * This is used to ensure a significant part of the host is always cloaked (see Bug #216)
+        */
+       std::string LastTwoDomainParts(const std::string &host)
+       {
+               int dots = 0;
+               std::string::size_type splitdot = host.length();
+
+               for (std::string::size_type x = host.length() - 1; x; --x)
+               {
+                       if (host[x] == '.')
+                       {
+                               splitdot = x;
+                               dots++;
+                       }
+                       if (dots >= 3)
+                               break;
+               }
+
+               if (splitdot == host.length())
+                       return host;
+               else
+                       return host.substr(splitdot);
+       }
+       
+ public:
+       CloakUser(InspIRCd* Instance, Module* Source, Module* Hash) : ModeHandler(Instance, 'x', 0, 0, false, MODETYPE_USER, false), Sender(Source), HashProvider(Hash)
+       {
+       }
+
+       ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)
+       {
+               if (source != dest)
+                       return MODEACTION_DENY;
+
+               /* For remote clients, we dont take any action, we just allow it.
+                * The local server where they are will set their cloak instead.
+                */
+               if (!IS_LOCAL(dest))
+                       return MODEACTION_ALLOW;
+
+               if (adding)
+               {
+                       if(!dest->IsModeSet('x'))
+                       {
+                               /* The mode is being turned on - so attempt to
+                                * allocate the user a cloaked host using a non-reversible
+                                * algorithm (its simple, but its non-reversible so the
+                                * simplicity doesnt really matter). This algorithm
+                                * will not work if the user has only one level of domain
+                                * naming in their hostname (e.g. if they are on a lan or
+                                * are connecting via localhost) -- this doesnt matter much.
+                                */
+
+                               char* n1 = strchr(dest->host,'.');
+                               char* n2 = strchr(dest->host,':');
+                       
+                               if (n1 || n2)
+                               {
+                                       /* InspIRCd users have two hostnames; A displayed
+                                        * hostname which can be modified by modules (e.g.
+                                        * to create vhosts, implement chghost, etc) and a
+                                        * 'real' hostname which you shouldnt write to.
+                                        */
+
+                                       unsigned int iv[] = { key1, key2, key3, key4 };
+                                       std::string a = LastTwoDomainParts(dest->host);
+                                       std::string b;
+
+                                       /** Reset the Hash module, and send it our IV and hex table */
+                                       HashResetRequest(Sender, HashProvider).Send();
+                                       HashKeyRequest(Sender, HashProvider, iv).Send();
+                                       HashHexRequest(Sender, HashProvider, xtab[(*dest->host) % 4]);
+
+                                       /* Generate a cloak using specialized Hash */
+                                       std::string hostcloak = prefix + "-" + std::string(HashSumRequest(Sender, HashProvider, dest->host).Send()).substr(0,8) + a;
+
+                                       /* Fix by brain - if the cloaked host is > the max length of a host (64 bytes
+                                        * according to the DNS RFC) then tough titty, they get cloaked as an IP. 
+                                        * Their ISP shouldnt go to town on subdomains, or they shouldnt have a kiddie
+                                        * vhost.
+                                        */
+#ifdef IPV6
+                                       in6_addr testaddr;
+                                       in_addr testaddr2;
+                                       if ((dest->GetProtocolFamily() == AF_INET6) && (inet_pton(AF_INET6,dest->host,&testaddr) < 1) && (hostcloak.length() <= 64))
+                                               /* Invalid ipv6 address, and ipv6 user (resolved host) */
+                                               b = hostcloak;
+                                       else if ((dest->GetProtocolFamily() == AF_INET) && (inet_aton(dest->host,&testaddr2) < 1) && (hostcloak.length() <= 64))
+                                               /* Invalid ipv4 address, and ipv4 user (resolved host) */
+                                               b = hostcloak;
+                                       else
+                                               /* Valid ipv6 or ipv4 address (not resolved) ipv4 or ipv6 user */
+                                               b = ((!strchr(dest->host,':')) ? Cloak4(dest->host) : Cloak6(dest->host));
+#else
+                                       in_addr testaddr;
+                                       if ((inet_aton(dest->host,&testaddr) < 1) && (hostcloak.length() <= 64))
+                                               /* Invalid ipv4 address, and ipv4 user (resolved host) */
+                                               b = hostcloak;
+                                       else
+                                               /* Valid ipv4 address (not resolved) ipv4 user */
+                                               b = Cloak4(dest->host);
+#endif
+
+                                       dest->ChangeDisplayedHost(b.c_str());
+                               }
+                               
+                               dest->SetMode('x',true);
+                               return MODEACTION_ALLOW;
+                       }
+               }
+               else
+               {
+                       if (dest->IsModeSet('x'))
+                       {
+                               /* User is removing the mode, so just restore their real host
+                                * and make it match the displayed one.
+                                */
+                               dest->ChangeDisplayedHost(dest->host);
+                               dest->SetMode('x',false);
+                               return MODEACTION_ALLOW;
+                       }
+               }
+
+               return MODEACTION_DENY;
+       }
+
+       std::string Cloak4(const char* ip)
+       {
+               unsigned int iv[] = { key1, key2, key3, key4 };
+               irc::sepstream seps(ip, '.');
+               std::string ra[4];;
+               std::string octet[4];
+               int i[4];
+
+               for (int j = 0; j < 4; j++)
+               {
+                       octet[j] = seps.GetToken();
+                       i[j] = atoi(octet[j].c_str());
+               }
+
+               octet[3] = octet[0] + "." + octet[1] + "." + octet[2] + "." + octet[3];
+               octet[2] = octet[0] + "." + octet[1] + "." + octet[2];
+               octet[1] = octet[0] + "." + octet[1];
+
+               /* Reset the Hash module and send it our IV */
+               HashResetRequest(Sender, HashProvider).Send();
+               HashKeyRequest(Sender, HashProvider, iv).Send();
+
+               /* Send the Hash module a different hex table for each octet group's Hash sum */
+               for (int k = 0; k < 4; k++)
+               {
+                       HashHexRequest(Sender, HashProvider, xtab[(iv[k]+i[k]) % 4]).Send();
+                       ra[k] = std::string(HashSumRequest(Sender, HashProvider, octet[k]).Send()).substr(0,6);
+               }
+               /* Stick them all together */
+               return std::string().append(ra[0]).append(".").append(ra[1]).append(".").append(ra[2]).append(".").append(ra[3]);
+       }
+
+       std::string Cloak6(const char* ip)
+       {
+               /* Theyre using 4in6 (YUCK). Translate as ipv4 cloak */
+               if (!strncmp(ip, "0::ffff:", 8))
+                       return Cloak4(ip + 8);
+
+               /* If we get here, yes it really is an ipv6 ip */
+               unsigned int iv[] = { key1, key2, key3, key4 };
+               std::vector<std::string> hashies;
+               std::string item;
+               int rounds = 0;
+
+               /* Reset the Hash module and send it our IV */
+               HashResetRequest(Sender, HashProvider).Send();
+               HashKeyRequest(Sender, HashProvider, iv).Send();
+
+               for (const char* input = ip; *input; input++)
+               {
+                       item += *input;
+                       if (item.length() > 7)
+                       {
+                               /* Send the Hash module a different hex table for each octet group's Hash sum */
+                               HashHexRequest(Sender, HashProvider, xtab[(key1+rounds) % 4]).Send();
+                               hashies.push_back(std::string(HashSumRequest(Sender, HashProvider, item).Send()).substr(0,8));
+                               item.clear();
+                       }
+                       rounds++;
+               }
+               if (!item.empty())
+               {
+                       /* Send the Hash module a different hex table for each octet group's Hash sum */
+                       HashHexRequest(Sender, HashProvider, xtab[(key1+rounds) % 4]).Send();
+                       hashies.push_back(std::string(HashSumRequest(Sender, HashProvider, item).Send()).substr(0,8));
+                       item.clear();
+               }
+               /* Stick them all together */
+               return irc::stringjoiner(":", hashies, 0, hashies.size() - 1).GetJoined();
+       }
+       
+       void DoRehash()
+       {
+               ConfigReader Conf(ServerInstance);
+               key1 = key2 = key3 = key4 = 0;
+               key1 = Conf.ReadInteger("cloak","key1",0,true);
+               key2 = Conf.ReadInteger("cloak","key2",0,true);
+               key3 = Conf.ReadInteger("cloak","key3",0,true);
+               key4 = Conf.ReadInteger("cloak","key4",0,true);
+               prefix = Conf.ReadValue("cloak","prefix",0);
+
+               if (prefix.empty())
+                       prefix = ServerInstance->Config->Network;
+
+               if (!key1 && !key2 && !key3 && !key4)
+                       throw ModuleException("You have not defined cloak keys for m_cloaking!!! THIS IS INSECURE AND SHOULD BE CHECKED!");
+       }
+};
+
+
+class ModuleCloaking : public Module
+{
+ private:
+       
+       CloakUser* cu;
+       Module* HashModule;
+
+ public:
+       ModuleCloaking(InspIRCd* Me)
+               : Module(Me)
+       {
+               ServerInstance->UseInterface("HashRequest");
+
+               /* Attempt to locate the md5 service provider, bail if we can't find it */
+               HashModule = ServerInstance->FindModule("m_md5.so");
+               if (!HashModule)
+                       throw ModuleException("Can't find m_md5.so. Please load m_md5.so before m_cloaking.so.");
+
+               /* Create new mode handler object */
+               cu = new CloakUser(ServerInstance, this, HashModule);
+
+               /* Register it with the core */         
+               if (!ServerInstance->AddMode(cu, 'x'))
+                       throw ModuleException("Could not add new modes!");
+
+               OnRehash(NULL,"");
+       }
+       
+       virtual ~ModuleCloaking()
+       {
+               ServerInstance->Modes->DelMode(cu);
+               DELETE(cu);
+               ServerInstance->DoneWithInterface("HashRequest");
+       }
+       
+       virtual Version GetVersion()
+       {
+               // returns the version number of the module to be
+               // listed in /MODULES
+               return Version(1,1,0,2,VF_COMMON|VF_VENDOR,API_VERSION);
+       }
+
+       virtual void OnRehash(userrec* user, const std::string &parameter)
+       {
+               cu->DoRehash();
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnRehash] = 1;
+       }
+};
+
+MODULE_INIT(ModuleCloaking)
index 429b9c2b900b693c0b877f8712201007ce3abea5..72a7ca7e832abc643480967e225139c182d055a3 100644 (file)
@@ -1 +1,100 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r#include "wildcard.h"\r\r/* $ModDesc: Provides the /clones command to retrieve information on a user, channel, or IP address */\r\r/** Handle /CHECK\r */\rclass cmd_clones : public command_t\r{\r public:\r   cmd_clones (InspIRCd* Instance) : command_t(Instance,"CLONES", 'o', 1)\r {\r              this->source = "m_clones.so";\r          syntax = "<limit>";\r    }\r\r     std::string FindMatchingIP(const irc::string &ipaddr)\r  {\r              std::string n = assign(ipaddr);\r                for (user_hash::const_iterator a = ServerInstance->clientlist->begin(); a != ServerInstance->clientlist->end(); a++)\r                   if (a->second->GetIPString() == n)\r                             return a->second->GetFullRealHost();\r           return "<?>";\r  }\r\r     CmdResult Handle (const char** parameters, int pcnt, userrec *user)\r    {\r\r             std::string clonesstr = "304 " + std::string(user->nick) + " :CLONES";\r\r                unsigned long limit = atoi(parameters[0]);\r\r            /*\r              * Syntax of a /clones reply:\r           *  :server.name 304 target :CLONES START\r               *  :server.name 304 target :CLONES <count> <ip> <fullhost>\r             *  :server.name 304 target :CHECK END\r          */\r\r           user->WriteServ(clonesstr + " START");\r\r                /* hostname or other */\r                for (clonemap::iterator x = ServerInstance->global_clones.begin(); x != ServerInstance->global_clones.end(); x++)\r              {\r                      if (x->second >= limit)\r                                user->WriteServ(clonesstr + " "+ ConvToStr(x->second) + " " + assign(x->first) + " " + FindMatchingIP(x->first));\r              }\r\r             user->WriteServ(clonesstr + " END");\r\r          return CMD_LOCALONLY;\r  }\r};\r\r\rclass ModuleClones : public Module\r{\r private:\r  cmd_clones *mycommand;\r public:\r        ModuleClones(InspIRCd* Me) : Module(Me)\r        {\r              \r               mycommand = new cmd_clones(ServerInstance);\r            ServerInstance->AddCommand(mycommand);\r }\r      \r       virtual ~ModuleClones()\r        {\r      }\r      \r       virtual Version GetVersion()\r   {\r              return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION);\r    }\r\r     void Implements(char* List)\r    {\r              /* we don't hook anything, nothing required */\r }\r      \r};\r\rMODULE_INIT(ModuleClones)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+#include "wildcard.h"
+
+/* $ModDesc: Provides the /clones command to retrieve information on a user, channel, or IP address */
+
+/** Handle /CHECK
+ */
+class cmd_clones : public command_t
+{
+ public:
+       cmd_clones (InspIRCd* Instance) : command_t(Instance,"CLONES", 'o', 1)
+       {
+               this->source = "m_clones.so";
+               syntax = "<limit>";
+       }
+
+       std::string FindMatchingIP(const irc::string &ipaddr)
+       {
+               std::string n = assign(ipaddr);
+               for (user_hash::const_iterator a = ServerInstance->clientlist->begin(); a != ServerInstance->clientlist->end(); a++)
+                       if (a->second->GetIPString() == n)
+                               return a->second->GetFullRealHost();
+               return "<?>";
+       }
+
+       CmdResult Handle (const char** parameters, int pcnt, userrec *user)
+       {
+
+               std::string clonesstr = "304 " + std::string(user->nick) + " :CLONES";
+
+               unsigned long limit = atoi(parameters[0]);
+
+               /*
+                * Syntax of a /clones reply:
+                *  :server.name 304 target :CLONES START
+                *  :server.name 304 target :CLONES <count> <ip> <fullhost>
+                *  :server.name 304 target :CHECK END
+                */
+
+               user->WriteServ(clonesstr + " START");
+
+               /* hostname or other */
+               for (clonemap::iterator x = ServerInstance->global_clones.begin(); x != ServerInstance->global_clones.end(); x++)
+               {
+                       if (x->second >= limit)
+                               user->WriteServ(clonesstr + " "+ ConvToStr(x->second) + " " + assign(x->first) + " " + FindMatchingIP(x->first));
+               }
+
+               user->WriteServ(clonesstr + " END");
+
+               return CMD_LOCALONLY;
+       }
+};
+
+
+class ModuleClones : public Module
+{
+ private:
+       cmd_clones *mycommand;
+ public:
+       ModuleClones(InspIRCd* Me) : Module(Me)
+       {
+               
+               mycommand = new cmd_clones(ServerInstance);
+               ServerInstance->AddCommand(mycommand);
+       }
+       
+       virtual ~ModuleClones()
+       {
+       }
+       
+       virtual Version GetVersion()
+       {
+               return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION);
+       }
+
+       void Implements(char* List)
+       {
+               /* we don't hook anything, nothing required */
+       }
+       
+};
+
+MODULE_INIT(ModuleClones)
index a8e81fcd8c2f0bd7beba56f386f94a4da823a9ef..2d639f310fd39cda8a243d3aff296c5ac0bd3b0d 100644 (file)
@@ -1 +1,96 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r\r/* $ModDesc: Forces users to join the specified channel(s) on connect */\r\rclass ModuleConnJoin : public Module\r{\r     private:\r               std::string JoinChan;\r          std::vector<std::string> Joinchans;\r            \r\r              int tokenize(const string &str, std::vector<std::string> &tokens)\r              {\r                      // skip delimiters at beginning.\r                       string::size_type lastPos = str.find_first_not_of(",", 0);\r                     // find first "non-delimiter".\r                 string::size_type pos = str.find_first_of(",", lastPos);\r\r                      while (string::npos != pos || string::npos != lastPos)\r                 {\r                              // found a token, add it to the vector.\r                                tokens.push_back(str.substr(lastPos, pos - lastPos));\r                          // skip delimiters. Note the "not_of"\r                          lastPos = str.find_first_not_of(",", pos);\r                             // find next "non-delimiter"\r                           pos = str.find_first_of(",", lastPos);\r                 }\r                      return tokens.size();\r          }\r\r     public:\r                ModuleConnJoin(InspIRCd* Me)\r                   : Module(Me)\r           {\r                      OnRehash(NULL, "");\r            }\r\r             Priority Prioritize()\r          {\r                      return PRIORITY_LAST;\r          }\r\r             void Implements(char* List)\r            {\r                      List[I_OnPostConnect] = List[I_OnRehash] = 1;\r          }\r\r             virtual void OnRehash(userrec* user, const std::string &parameter)\r             {\r                      ConfigReader* conf = new ConfigReader(ServerInstance);\r                 JoinChan = conf->ReadValue("autojoin", "channel", 0);\r                  Joinchans.clear();\r                     if (!JoinChan.empty())\r                         tokenize(JoinChan,Joinchans);\r                  DELETE(conf);\r          }\r\r             virtual ~ModuleConnJoin()\r              {\r              }\r\r             virtual Version GetVersion()\r           {\r                      return Version(1,1,0,1,VF_VENDOR,API_VERSION);\r         }\r\r             virtual void OnPostConnect(userrec* user)\r              {\r                      if (!IS_LOCAL(user))\r                           return;\r\r                       for(std::vector<std::string>::iterator it = Joinchans.begin(); it != Joinchans.end(); it++)\r                            if (ServerInstance->IsChannel(it->c_str()))\r                                    chanrec::JoinUser(ServerInstance, user, it->c_str(), false, "", ServerInstance->Time(true));\r           }\r\r};\r\r\rMODULE_INIT(ModuleConnJoin)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+
+/* $ModDesc: Forces users to join the specified channel(s) on connect */
+
+class ModuleConnJoin : public Module
+{
+       private:
+               std::string JoinChan;
+               std::vector<std::string> Joinchans;
+               
+
+               int tokenize(const string &str, std::vector<std::string> &tokens)
+               {
+                       // skip delimiters at beginning.
+                       string::size_type lastPos = str.find_first_not_of(",", 0);
+                       // find first "non-delimiter".
+                       string::size_type pos = str.find_first_of(",", lastPos);
+
+                       while (string::npos != pos || string::npos != lastPos)
+                       {
+                               // found a token, add it to the vector.
+                               tokens.push_back(str.substr(lastPos, pos - lastPos));
+                               // skip delimiters. Note the "not_of"
+                               lastPos = str.find_first_not_of(",", pos);
+                               // find next "non-delimiter"
+                               pos = str.find_first_of(",", lastPos);
+                       }
+                       return tokens.size();
+               }
+
+       public:
+               ModuleConnJoin(InspIRCd* Me)
+                       : Module(Me)
+               {
+                       OnRehash(NULL, "");
+               }
+
+               Priority Prioritize()
+               {
+                       return PRIORITY_LAST;
+               }
+
+               void Implements(char* List)
+               {
+                       List[I_OnPostConnect] = List[I_OnRehash] = 1;
+               }
+
+               virtual void OnRehash(userrec* user, const std::string &parameter)
+               {
+                       ConfigReader* conf = new ConfigReader(ServerInstance);
+                       JoinChan = conf->ReadValue("autojoin", "channel", 0);
+                       Joinchans.clear();
+                       if (!JoinChan.empty())
+                               tokenize(JoinChan,Joinchans);
+                       DELETE(conf);
+               }
+
+               virtual ~ModuleConnJoin()
+               {
+               }
+
+               virtual Version GetVersion()
+               {
+                       return Version(1,1,0,1,VF_VENDOR,API_VERSION);
+               }
+
+               virtual void OnPostConnect(userrec* user)
+               {
+                       if (!IS_LOCAL(user))
+                               return;
+
+                       for(std::vector<std::string>::iterator it = Joinchans.begin(); it != Joinchans.end(); it++)
+                               if (ServerInstance->IsChannel(it->c_str()))
+                                       chanrec::JoinUser(ServerInstance, user, it->c_str(), false, "", ServerInstance->Time(true));
+               }
+
+};
+
+
+MODULE_INIT(ModuleConnJoin)
index f9118a384482bdbb95416db7cf07d751d8a263d8..3f27eeff5fed8eb1d46435f07a78abc361d621bb 100644 (file)
@@ -1 +1,104 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r#include "wildcard.h"\r\r/* $ModDesc: Sets (and unsets) modes on users when they connect */\r\rclass ModuleModesOnConnect : public Module\r{\r private:\r\r    ConfigReader *Conf;\r\r public:\r  ModuleModesOnConnect(InspIRCd* Me)\r             : Module(Me)\r   {\r              \r               Conf = new ConfigReader(ServerInstance);\r       }\r\r     void Implements(char* List)\r    {\r              List[I_OnPostConnect] = List[I_OnRehash] = 1;\r  }\r\r     virtual void OnRehash(userrec* user, const std::string &parameter)\r     {\r              DELETE(Conf);\r          Conf = new ConfigReader(ServerInstance);\r       }\r      \r       virtual ~ModuleModesOnConnect()\r        {\r              DELETE(Conf);\r  }\r      \r       virtual Version GetVersion()\r   {\r              return Version(1,1,0,1,VF_VENDOR,API_VERSION);\r }\r      \r       virtual void OnPostConnect(userrec* user)\r      {\r              if (!IS_LOCAL(user))\r                   return;\r\r               for (int j = 0; j < Conf->Enumerate("connect"); j++)\r           {\r                      std::string hostn = Conf->ReadValue("connect","allow",j);\r                      if ((match(user->GetIPString(),hostn.c_str(),true)) || (match(user->host,hostn.c_str())))\r                      {\r                              std::string ThisModes = Conf->ReadValue("connect","modes",j);\r                          if (!ThisModes.empty())\r                                {\r                                      std::string buf;\r                                       stringstream ss(ThisModes);\r\r                                   vector<string> tokens;\r\r                                        // split ThisUserModes into modes and mode params\r                                      while (ss >> buf)\r                                              tokens.push_back(buf);\r\r                                        int size = tokens.size() + 1;\r                                  const char** modes = new const char*[size];\r                                    modes[0] = user->nick;\r                                 modes[1] = tokens[0].c_str();\r\r                                 if (tokens.size() > 1)\r                                 {\r                                              // process mode params\r                                         int i = 2;\r                                             for (unsigned int k = 1; k < tokens.size(); k++)\r                                               {\r                                                      modes[i] = tokens[k].c_str();\r                                                  i++;\r                                           }\r                                      }\r\r                                     ServerInstance->Parser->CallHandler("MODE", modes, size, user);\r                                        delete [] modes;\r                               }\r                              break;\r                 }\r              }\r      }\r};\r\rMODULE_INIT(ModuleModesOnConnect)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+#include "wildcard.h"
+
+/* $ModDesc: Sets (and unsets) modes on users when they connect */
+
+class ModuleModesOnConnect : public Module
+{
+ private:
+
+       ConfigReader *Conf;
+
+ public:
+       ModuleModesOnConnect(InspIRCd* Me)
+               : Module(Me)
+       {
+               
+               Conf = new ConfigReader(ServerInstance);
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnPostConnect] = List[I_OnRehash] = 1;
+       }
+
+       virtual void OnRehash(userrec* user, const std::string &parameter)
+       {
+               DELETE(Conf);
+               Conf = new ConfigReader(ServerInstance);
+       }
+       
+       virtual ~ModuleModesOnConnect()
+       {
+               DELETE(Conf);
+       }
+       
+       virtual Version GetVersion()
+       {
+               return Version(1,1,0,1,VF_VENDOR,API_VERSION);
+       }
+       
+       virtual void OnPostConnect(userrec* user)
+       {
+               if (!IS_LOCAL(user))
+                       return;
+
+               for (int j = 0; j < Conf->Enumerate("connect"); j++)
+               {
+                       std::string hostn = Conf->ReadValue("connect","allow",j);
+                       if ((match(user->GetIPString(),hostn.c_str(),true)) || (match(user->host,hostn.c_str())))
+                       {
+                               std::string ThisModes = Conf->ReadValue("connect","modes",j);
+                               if (!ThisModes.empty())
+                               {
+                                       std::string buf;
+                                       stringstream ss(ThisModes);
+
+                                       vector<string> tokens;
+
+                                       // split ThisUserModes into modes and mode params
+                                       while (ss >> buf)
+                                               tokens.push_back(buf);
+
+                                       int size = tokens.size() + 1;
+                                       const char** modes = new const char*[size];
+                                       modes[0] = user->nick;
+                                       modes[1] = tokens[0].c_str();
+
+                                       if (tokens.size() > 1)
+                                       {
+                                               // process mode params
+                                               int i = 2;
+                                               for (unsigned int k = 1; k < tokens.size(); k++)
+                                               {
+                                                       modes[i] = tokens[k].c_str();
+                                                       i++;
+                                               }
+                                       }
+
+                                       ServerInstance->Parser->CallHandler("MODE", modes, size, user);
+                                       delete [] modes;
+                               }
+                               break;
+                       }
+               }
+       }
+};
+
+MODULE_INIT(ModuleModesOnConnect)
index b84533f88cd57ed8fa3437e57bfc44b8d8647117..0dd27ddbd4f196494f7b02f8629aedc2ceefb722 100644 (file)
@@ -1 +1,148 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r\r/* $ModDesc: Forces connecting clients to send a PONG message back to the server before they can complete their connection */\r\rclass ModuleWaitPong : public Module\r{\r        bool sendsnotice;\r      bool killonbadreply;\r   const char* extenstr;\r\r public:\r        ModuleWaitPong(InspIRCd* Me)\r    : Module(Me), extenstr("waitpong_pingstr")\r    {\r              OnRehash(NULL,"");\r     }\r      \r       virtual void OnRehash(userrec* user, const std::string &param)\r {\r              ConfigReader Conf(ServerInstance);\r             \r               sendsnotice = Conf.ReadFlag("waitpong", "sendsnotice", 0);\r             \r               if(Conf.GetError() == CONF_VALUE_NOT_FOUND)\r                    sendsnotice = true;\r            \r               killonbadreply = Conf.ReadFlag("waitpong", "killonbadreply", 0);\r\r              if(Conf.GetError() == CONF_VALUE_NOT_FOUND)\r                    killonbadreply = true;\r }\r\r     void Implements(char* List)\r    {\r              List[I_OnUserRegister] = List[I_OnCheckReady] = List[I_OnPreCommand] = List[I_OnRehash] = List[I_OnUserDisconnect] = List[I_OnCleanup] = 1;\r    }\r\r     char* RandString(unsigned int length)\r  {\r              unsigned char* out = new unsigned char[length+1];\r              for(unsigned int i = 0; i < length; i++)\r                       out[i] = ((rand() % 26) + 65);\r         out[length] = '\0';\r    \r               return (char*)out;\r     }\r      \r       virtual int OnUserRegister(userrec* user)\r      {\r              char* pingrpl = RandString(10);\r                \r               user->Write("PING :%s", pingrpl);\r              \r               if(sendsnotice)\r                        user->WriteServ("NOTICE %s :*** If you are having problems connecting due to ping timeouts, please type /quote PONG %s or /raw PONG %s now.", user->nick, pingrpl, pingrpl);\r                   \r               user->Extend(extenstr, pingrpl);\r               return 0;\r      }\r      \r       virtual int OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec* user, bool validated, const std::string &original_line)\r       {\r              if(command == "PONG")\r          {\r                      char* pingrpl;\r                 user->GetExt(extenstr, pingrpl);\r                       \r                       if(pingrpl)\r                    {\r                              if(strcmp(pingrpl, parameters[0]) == 0)\r                                {\r                                      DELETE(pingrpl);\r                                       user->Shrink(extenstr);\r                                        return 1;\r                              }\r                              else\r                           {\r                                      if(killonbadreply)\r                                             userrec::QuitUser(ServerInstance, user, "Incorrect ping reply for registration");\r                                      return 1;\r                              }\r                      }\r              }\r              return 0;\r      }\r\r     virtual bool OnCheckReady(userrec* user)\r       {\r              char* pingrpl;\r         return (!user->GetExt(extenstr, pingrpl));\r     }\r      \r       virtual void OnUserDisconnect(userrec* user)\r   {\r              char* pingrpl;\r         user->GetExt(extenstr, pingrpl);\r\r              if(pingrpl)\r            {\r                      DELETE(pingrpl);\r                       user->Shrink(extenstr);\r                }\r      }\r      \r       virtual void OnCleanup(int target_type, void* item)\r    {\r              if(target_type == TYPE_USER)\r           {\r                      userrec* user = (userrec*)item;\r                        char* pingrpl;\r                 user->GetExt(extenstr, pingrpl);\r                       \r                       if(pingrpl)\r                    {\r                              DELETE(pingrpl);\r                               user->Shrink(extenstr);\r                        } \r             }\r      }\r      \r       virtual ~ModuleWaitPong()\r      {\r      }\r      \r       virtual Version GetVersion()\r   {\r              return Version(1, 1, 0, 1, VF_VENDOR, API_VERSION);\r    }\r      \r};\r\rMODULE_INIT(ModuleWaitPong)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+
+/* $ModDesc: Forces connecting clients to send a PONG message back to the server before they can complete their connection */
+
+class ModuleWaitPong : public Module
+{
+       bool sendsnotice;
+       bool killonbadreply;
+       const char* extenstr;
+
+ public:
+       ModuleWaitPong(InspIRCd* Me)
+        : Module(Me), extenstr("waitpong_pingstr")
+       {
+               OnRehash(NULL,"");
+       }
+       
+       virtual void OnRehash(userrec* user, const std::string &param)
+       {
+               ConfigReader Conf(ServerInstance);
+               
+               sendsnotice = Conf.ReadFlag("waitpong", "sendsnotice", 0);
+               
+               if(Conf.GetError() == CONF_VALUE_NOT_FOUND)
+                       sendsnotice = true;
+               
+               killonbadreply = Conf.ReadFlag("waitpong", "killonbadreply", 0);
+
+               if(Conf.GetError() == CONF_VALUE_NOT_FOUND)
+                       killonbadreply = true;
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnUserRegister] = List[I_OnCheckReady] = List[I_OnPreCommand] = List[I_OnRehash] = List[I_OnUserDisconnect] = List[I_OnCleanup] = 1;
+       }
+
+       char* RandString(unsigned int length)
+       {
+               unsigned char* out = new unsigned char[length+1];
+               for(unsigned int i = 0; i < length; i++)
+                       out[i] = ((rand() % 26) + 65);
+               out[length] = '\0';
+       
+               return (char*)out;
+       }
+       
+       virtual int OnUserRegister(userrec* user)
+       {
+               char* pingrpl = RandString(10);
+               
+               user->Write("PING :%s", pingrpl);
+               
+               if(sendsnotice)
+                       user->WriteServ("NOTICE %s :*** If you are having problems connecting due to ping timeouts, please type /quote PONG %s or /raw PONG %s now.", user->nick, pingrpl, pingrpl);
+                       
+               user->Extend(extenstr, pingrpl);
+               return 0;
+       }
+       
+       virtual int OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec* user, bool validated, const std::string &original_line)
+       {
+               if(command == "PONG")
+               {
+                       char* pingrpl;
+                       user->GetExt(extenstr, pingrpl);
+                       
+                       if(pingrpl)
+                       {
+                               if(strcmp(pingrpl, parameters[0]) == 0)
+                               {
+                                       DELETE(pingrpl);
+                                       user->Shrink(extenstr);
+                                       return 1;
+                               }
+                               else
+                               {
+                                       if(killonbadreply)
+                                               userrec::QuitUser(ServerInstance, user, "Incorrect ping reply for registration");
+                                       return 1;
+                               }
+                       }
+               }
+               return 0;
+       }
+
+       virtual bool OnCheckReady(userrec* user)
+       {
+               char* pingrpl;
+               return (!user->GetExt(extenstr, pingrpl));
+       }
+       
+       virtual void OnUserDisconnect(userrec* user)
+       {
+               char* pingrpl;
+               user->GetExt(extenstr, pingrpl);
+
+               if(pingrpl)
+               {
+                       DELETE(pingrpl);
+                       user->Shrink(extenstr);
+               }
+       }
+       
+       virtual void OnCleanup(int target_type, void* item)
+       {
+               if(target_type == TYPE_USER)
+               {
+                       userrec* user = (userrec*)item;
+                       char* pingrpl;
+                       user->GetExt(extenstr, pingrpl);
+                       
+                       if(pingrpl)
+                       {
+                               DELETE(pingrpl);
+                               user->Shrink(extenstr);
+                       } 
+               }
+       }
+       
+       virtual ~ModuleWaitPong()
+       {
+       }
+       
+       virtual Version GetVersion()
+       {
+               return Version(1, 1, 0, 1, VF_VENDOR, API_VERSION);
+       }
+       
+};
+
+MODULE_INIT(ModuleWaitPong)
index 71e52fd01ad8b1e134968d32567b2b1031deebc8..47b19fdf4e7920636236c8199056ee51010ed3e4 100644 (file)
@@ -1 +1,120 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "modules.h"\r\r/* $ModDesc: Connection throttle */\r\rint conns = 0, throttled = 0;\r\rclass ModuleConnFlood : public Module\r{\rprivate:\r       int seconds, maxconns, timeout, boot_wait;\r     time_t first;\r  std::string quitmsg;\r\r  ConfigReader* conf;\r    \r\rpublic:\r      ModuleConnFlood(InspIRCd* Me) : Module(Me)\r     {\r              \r               InitConf();\r    }\r\r     virtual ~ModuleConnFlood()\r     {\r      }\r\r     virtual Version GetVersion()\r   {\r              return Version(1,1,0,0,VF_VENDOR,API_VERSION);\r }\r\r     void Implements(char* List)\r    {\r              List[I_OnRehash] = List[I_OnUserRegister] = 1;\r }\r   \r  void InitConf()\r        {\r              /* read configuration variables */\r             conf = new ConfigReader(ServerInstance);\r               /* throttle configuration */\r           seconds = conf->ReadInteger("connflood", "seconds", 0, true);\r          maxconns = conf->ReadInteger("connflood", "maxconns", 0, true);\r                timeout = conf->ReadInteger("connflood", "timeout", 0, true);\r          quitmsg = conf->ReadValue("connflood", "quitmsg", 0);\r\r         /* seconds to wait when the server just booted */\r              boot_wait = conf->ReadInteger("connflood", "bootwait", 0, true);\r\r              first = ServerInstance->Time();\r        }\r \r    virtual int OnUserRegister(userrec* user)\r      {\r              time_t next = ServerInstance->Time();\r          \r               if ((ServerInstance->startup_time + boot_wait) > next)\r                 return 0;\r              \r               /* time difference between first and latest connection */\r              time_t tdiff = next - first;\r\r          /* increase connection count */\r                conns++;\r\r              if (throttled == 1)\r            {\r                      if (tdiff > seconds + timeout)\r                 {\r                              /* expire throttle */\r                          throttled = 0;\r                         ServerInstance->WriteOpers("*** Connection throttle deactivated");\r                             return 0;\r                      }\r                      userrec::QuitUser(ServerInstance, user, quitmsg);\r                      return 1;\r              }\r\r             if (tdiff <= seconds)\r          {\r                      if (conns >= maxconns)\r                 {\r                              throttled = 1;\r                         ServerInstance->WriteOpers("*** Connection throttle activated");\r                               userrec::QuitUser(ServerInstance, user, quitmsg);\r                              return 1;\r                      }\r              }\r              else\r           {\r                      conns = 1;\r                     first = next;\r          }\r              return 0;\r      }\r\r     virtual void OnRehash(userrec* user, const std::string &parameter)\r     {\r              InitConf();\r    }\r\r};\r\rMODULE_INIT(ModuleConnFlood)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "modules.h"
+
+/* $ModDesc: Connection throttle */
+
+int conns = 0, throttled = 0;
+
+class ModuleConnFlood : public Module
+{
+private:
+       int seconds, maxconns, timeout, boot_wait;
+       time_t first;
+       std::string quitmsg;
+
+       ConfigReader* conf;
+       
+
+public:
+       ModuleConnFlood(InspIRCd* Me) : Module(Me)
+       {
+               
+               InitConf();
+       }
+
+       virtual ~ModuleConnFlood()
+       {
+       }
+
+       virtual Version GetVersion()
+       {
+               return Version(1,1,0,0,VF_VENDOR,API_VERSION);
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnRehash] = List[I_OnUserRegister] = 1;
+       }
+   
+       void InitConf()
+       {
+               /* read configuration variables */
+               conf = new ConfigReader(ServerInstance);
+               /* throttle configuration */
+               seconds = conf->ReadInteger("connflood", "seconds", 0, true);
+               maxconns = conf->ReadInteger("connflood", "maxconns", 0, true);
+               timeout = conf->ReadInteger("connflood", "timeout", 0, true);
+               quitmsg = conf->ReadValue("connflood", "quitmsg", 0);
+
+               /* seconds to wait when the server just booted */
+               boot_wait = conf->ReadInteger("connflood", "bootwait", 0, true);
+
+               first = ServerInstance->Time();
+       }
+       virtual int OnUserRegister(userrec* user)
+       {
+               time_t next = ServerInstance->Time();
+               
+               if ((ServerInstance->startup_time + boot_wait) > next)
+                       return 0;
+               
+               /* time difference between first and latest connection */
+               time_t tdiff = next - first;
+
+               /* increase connection count */
+               conns++;
+
+               if (throttled == 1)
+               {
+                       if (tdiff > seconds + timeout)
+                       {
+                               /* expire throttle */
+                               throttled = 0;
+                               ServerInstance->WriteOpers("*** Connection throttle deactivated");
+                               return 0;
+                       }
+                       userrec::QuitUser(ServerInstance, user, quitmsg);
+                       return 1;
+               }
+
+               if (tdiff <= seconds)
+               {
+                       if (conns >= maxconns)
+                       {
+                               throttled = 1;
+                               ServerInstance->WriteOpers("*** Connection throttle activated");
+                               userrec::QuitUser(ServerInstance, user, quitmsg);
+                               return 1;
+                       }
+               }
+               else
+               {
+                       conns = 1;
+                       first = next;
+               }
+               return 0;
+       }
+
+       virtual void OnRehash(userrec* user, const std::string &parameter)
+       {
+               InitConf();
+       }
+
+};
+
+MODULE_INIT(ModuleConnFlood)
index b1a22941d12a4ac15d9e75953e0b056d4d8a8296..eb20f4f9938e4f4e779e6a28075ed2bbc16291f8 100644 (file)
@@ -1 +1,99 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r\r/* $ModDesc: Provides support for unreal-style CYCLE command. */\r\r/** Handle /CYCLE\r */\rclass cmd_cycle : public command_t\r{\r public:\r        cmd_cycle (InspIRCd* Instance) : command_t(Instance,"CYCLE", 0, 1)\r     {\r              this->source = "m_cycle.so";\r           syntax = "<channel> :[reason]";\r        }\r\r     CmdResult Handle (const char** parameters, int pcnt, userrec *user)\r    {\r              chanrec* channel = ServerInstance->FindChan(parameters[0]);\r            std::string reason = ConvToStr("Cycling");\r                     \r               if (pcnt > 1)\r          {\r                      /* reason provided, use it */\r                  reason = reason + ": " + parameters[1];\r                }\r              \r               if (channel)\r           {\r                      /*\r                      * technically, this is only ever sent locally, but pays to be safe ;p\r                  */\r                    if (IS_LOCAL(user))\r                    {\r                              if (channel->GetStatus(user) < STATUS_VOICE && channel->IsBanned(user))\r                                {\r                                      /* banned, boned. drop the message. */\r                                 user->WriteServ("NOTICE "+std::string(user->nick)+" :*** You may not cycle, as you are banned on channel " + channel->name);\r                                   return CMD_FAILURE;\r                            }\r                              \r                               /* XXX in the future, this may move to a static chanrec method (the delete.) -- w00t */\r                                if (!channel->PartUser(user, reason.c_str()))\r                                  delete channel;\r                                \r                               chanrec::JoinUser(ServerInstance, user, parameters[0], true, "", ServerInstance->Time(true));\r                  }\r\r                     return CMD_LOCALONLY;\r          }\r              else\r           {\r                      user->WriteServ("NOTICE %s :*** You are not on this channel", user->nick);\r             }\r\r             return CMD_FAILURE;\r    }\r};\r\r\rclass ModuleCycle : public Module\r{\r     cmd_cycle*      mycommand;\r public:\r    ModuleCycle(InspIRCd* Me)\r              : Module(Me)\r   {\r              \r               mycommand = new cmd_cycle(ServerInstance);\r             ServerInstance->AddCommand(mycommand);\r }\r      \r       virtual ~ModuleCycle()\r {\r      }\r      \r       virtual Version GetVersion()\r   {\r              return Version(1,1,0,1,VF_VENDOR,API_VERSION);\r }\r      \r};\r\rMODULE_INIT(ModuleCycle)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+
+/* $ModDesc: Provides support for unreal-style CYCLE command. */
+
+/** Handle /CYCLE
+ */
+class cmd_cycle : public command_t
+{
+ public:
+       cmd_cycle (InspIRCd* Instance) : command_t(Instance,"CYCLE", 0, 1)
+       {
+               this->source = "m_cycle.so";
+               syntax = "<channel> :[reason]";
+       }
+
+       CmdResult Handle (const char** parameters, int pcnt, userrec *user)
+       {
+               chanrec* channel = ServerInstance->FindChan(parameters[0]);
+               std::string reason = ConvToStr("Cycling");
+                       
+               if (pcnt > 1)
+               {
+                       /* reason provided, use it */
+                       reason = reason + ": " + parameters[1];
+               }
+               
+               if (channel)
+               {
+                       /*
+                        * technically, this is only ever sent locally, but pays to be safe ;p
+                        */
+                       if (IS_LOCAL(user))
+                       {
+                               if (channel->GetStatus(user) < STATUS_VOICE && channel->IsBanned(user))
+                               {
+                                       /* banned, boned. drop the message. */
+                                       user->WriteServ("NOTICE "+std::string(user->nick)+" :*** You may not cycle, as you are banned on channel " + channel->name);
+                                       return CMD_FAILURE;
+                               }
+                               
+                               /* XXX in the future, this may move to a static chanrec method (the delete.) -- w00t */
+                               if (!channel->PartUser(user, reason.c_str()))
+                                       delete channel;
+                               
+                               chanrec::JoinUser(ServerInstance, user, parameters[0], true, "", ServerInstance->Time(true));
+                       }
+
+                       return CMD_LOCALONLY;
+               }
+               else
+               {
+                       user->WriteServ("NOTICE %s :*** You are not on this channel", user->nick);
+               }
+
+               return CMD_FAILURE;
+       }
+};
+
+
+class ModuleCycle : public Module
+{
+       cmd_cycle*      mycommand;
+ public:
+       ModuleCycle(InspIRCd* Me)
+               : Module(Me)
+       {
+               
+               mycommand = new cmd_cycle(ServerInstance);
+               ServerInstance->AddCommand(mycommand);
+       }
+       
+       virtual ~ModuleCycle()
+       {
+       }
+       
+       virtual Version GetVersion()
+       {
+               return Version(1,1,0,1,VF_VENDOR,API_VERSION);
+       }
+       
+};
+
+MODULE_INIT(ModuleCycle)
index 61ef90d89f08def567dfa7a456e085dd77b12872..bfec3c5e107e219f099832084fb2e479180e8ba7 100644 (file)
@@ -1 +1,489 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r\r/* $ModDesc: Povides support for the /DCCALLOW command */\r\rstatic ConfigReader *Conf;\r\rclass BannedFileList\r{\r public:\r       std::string filemask;\r  std::string action;\r};\r\rclass DCCAllow\r{\r public:\r      std::string nickname;\r  std::string hostmask;\r  time_t set_on;\r long length;\r\r  DCCAllow() { }\r\r        DCCAllow(const std::string &nick, const std::string &hm, const time_t so, const long ln) : nickname(nick), hostmask(hm), set_on(so), length(ln) { }\r};\r\rtypedef std::vector<userrec *> userlist;\ruserlist ul;\rtypedef std::vector<DCCAllow> dccallowlist;\rdccallowlist* dl;\rtypedef std::vector<BannedFileList> bannedfilelist;\rbannedfilelist bfl;\r\rclass cmd_dccallow : public command_t\r{\r public:\r  cmd_dccallow(InspIRCd* Me) : command_t(Me, "DCCALLOW", 0, 0)\r   {\r              this->source = "m_dccallow.so";\r                syntax = "{[+|-]<nick> <time>|HELP|LIST}";\r     }\r\r     CmdResult Handle(const char **parameters, int pcnt, userrec *user)\r     {\r              /* syntax: DCCALLOW [+|-]<nick> (<time>) */\r            if (!pcnt)\r             {\r                      // display current DCCALLOW list\r                       DisplayDCCAllowList(user);\r                     return CMD_FAILURE;\r            }\r              else if (pcnt > 0)\r             {\r                      char action = *parameters[0];\r          \r                       // if they didn't specify an action, this is probably a command\r                        if (action != '+' && action != '-')\r                    {\r                              if (!strcasecmp(parameters[0], "LIST"))\r                                {\r                                      // list current DCCALLOW list\r                                  DisplayDCCAllowList(user);\r                                     return CMD_FAILURE;\r                            } \r                             else if (!strcasecmp(parameters[0], "HELP"))\r                           {\r                                      // display help\r                                        DisplayHelp(user);\r                                     return CMD_FAILURE;\r                            }\r                      }\r                      \r                       std::string nick = parameters[0] + 1;\r                  userrec *target = ServerInstance->FindNick(nick);\r      \r                       if (target)\r                    {\r                              \r                               if (action == '-')\r                             {\r                                      user->GetExt("dccallow_list", dl);\r                                     // check if it contains any entries\r                                    if (dl)\r                                        {\r                                              if (dl->size())\r                                                {\r                                                      for (dccallowlist::iterator i = dl->begin(); i != dl->end(); ++i)\r                                                      {\r                                                              // search through list\r                                                         if (i->nickname == target->nick)\r                                                               {\r                                                                      dl->erase(i);\r                                                                  user->WriteServ("995 %s %s :Removed %s from your DCCALLOW list", user->nick, user->nick, target->nick);\r                                                                        break;\r                                                         }\r                                                      }\r                                              }\r                                      }\r                                      else\r                                   {\r                                              DELETE(dl);\r                                            user->Shrink("dccallow_list");\r                         \r                                               // remove from userlist\r                                                for (userlist::iterator j = ul.begin(); j != ul.end(); ++j)\r                                            {\r                                                      userrec* u = (userrec*)(*j);\r                                                   if (u == user)\r                                                 {\r                                                              ul.erase(j);\r                                                           break;\r                                                 }\r                                              }\r                                      }\r                              }\r                              else if (action == '+')\r                                {\r                                      // fetch current DCCALLOW list\r                                 user->GetExt("dccallow_list", dl);\r                                     // they don't have one, create it\r                                      if (!dl)\r                                       {\r                                              dl = new dccallowlist;\r                                         user->Extend("dccallow_list", dl);\r                                             // add this user to the userlist\r                                               ul.push_back(user);\r                                    }\r                                      for (dccallowlist::const_iterator k = dl->begin(); k != dl->end(); ++k)\r                                        {\r                                              if (k->nickname == target->nick)\r                                               {\r                                                      user->WriteServ("996 %s %s :%s is already on your DCCALLOW list", user->nick, user->nick, target->nick);\r                                                       return CMD_FAILURE;\r                                            }\r                                              else if (ServerInstance->MatchText(user->GetFullHost(), k->hostmask))\r                                          {\r                                                      user->WriteServ("996 %s %s :You cannot add yourself to your own DCCALLOW list!", user->nick, user->nick);\r                                                      return CMD_FAILURE;\r                                            }\r                                      }\r                              \r                                       std::string mask = std::string(target->nick)+"!"+std::string(target->ident)+"@"+std::string(target->dhost);\r                                    std::string default_length = Conf->ReadValue("dccallow", "length", 0);\r         \r                                       long length;\r                                   if (pcnt < 2)\r                                  {\r                                              length = ServerInstance->Duration(default_length);\r                                     } \r                                     else if (!atoi(parameters[1]))\r                                 {\r                                              length = 0;\r                                    }\r                                      else\r                                   {\r                                              length = ServerInstance->Duration(parameters[1]);\r                                      }\r      \r                                       if (!ServerInstance->IsValidMask(mask.c_str()))\r                                        {\r                                              return CMD_FAILURE;\r                                    }\r                      \r                                       dl->push_back(DCCAllow(target->nick, mask, ServerInstance->Time(), length));\r                   \r                                       if (length > 0)\r                                        {\r                                              user->WriteServ("993 %s %s :Added %s to DCCALLOW list for %d seconds", user->nick, user->nick, target->nick, length);\r                                  }\r                                      else\r                                   {\r                                              user->WriteServ("994 %s %s :Added %s to DCCALLOW list for this session", user->nick, user->nick, target->nick);\r                                        }\r\r                                     /* route it. */\r                                        return CMD_SUCCESS;\r                            }\r                      }\r                      else\r                   {\r                              // nick doesn't exist\r                          user->WriteServ("401 %s %s :No such nick/channel", user->nick, nick.c_str());\r                          return CMD_FAILURE;\r                    }\r              }\r              return CMD_FAILURE;\r    }\r\r     void DisplayHelp(userrec* user)\r        {\r              user->WriteServ("998 %s :DCCALLOW [<+|->nick [time]] [list] [help]", user->nick);\r              user->WriteServ("998 %s :You may allow DCCs from specific users by specifying a", user->nick);\r         user->WriteServ("998 %s :DCC allow for the user you want to receive DCCs from.", user->nick);\r          user->WriteServ("998 %s :For example, to allow the user Brain to send you inspircd.exe", user->nick);\r          user->WriteServ("998 %s :you would type:", user->nick);\r                user->WriteServ("998 %s :/DCCALLOW +Brain", user->nick);\r               user->WriteServ("998 %s :Brain would then be able to send you files. They would have to", user->nick);\r         user->WriteServ("998 %s :resend the file again if the server gave them an error message", user->nick);\r         user->WriteServ("998 %s :before you added them to your DCCALLOW list.", user->nick);\r           user->WriteServ("998 %s :DCCALLOW entries will be temporary by default, if you want to add", user->nick);\r              user->WriteServ("998 %s :them to your DCCALLOW list until you leave IRC, type:", user->nick);\r          user->WriteServ("998 %s :/DCCALLOW +Brain 0", user->nick);\r             user->WriteServ("998 %s :To remove the user from your DCCALLOW list, type:", user->nick);\r              user->WriteServ("998 %s :/DCCALLOW -Brain", user->nick);\r               user->WriteServ("998 %s :To see the users in your DCCALLOW list, type:", user->nick);\r          user->WriteServ("998 %s :/DCCALLOW LIST", user->nick);\r         user->WriteServ("998 %s :NOTE: If the user leaves IRC or changes their nickname", user->nick);\r         user->WriteServ("998 %s :  they will be removed from your DCCALLOW list.", user->nick);\r                user->WriteServ("998 %s :  your DCCALLOW list will be deleted when you leave IRC.", user->nick);\r               user->WriteServ("999 %s :End of DCCALLOW HELP", user->nick);\r   }\r      \r       void DisplayDCCAllowList(userrec* user)\r        {\r               // display current DCCALLOW list\r              user->WriteServ("990 %s :Users on your DCCALLOW list:", user->nick);\r           user->GetExt("dccallow_list", dl);\r             \r               if (dl)\r                {\r                      for (dccallowlist::const_iterator c = dl->begin(); c != dl->end(); ++c)\r                        {\r                              user->WriteServ("991 %s %s :%s (%s)", user->nick, user->nick, c->nickname.c_str(), c->hostmask.c_str());\r                       }\r              }\r              \r               user->WriteServ("992 %s :End of DCCALLOW list", user->nick);\r   }                       \r\r};\r   \rclass ModuleDCCAllow : public Module\r{\r        cmd_dccallow* mycommand;\r public:\r\r     ModuleDCCAllow(InspIRCd* Me)\r           : Module(Me)\r   {\r              Conf = new ConfigReader(ServerInstance);\r               mycommand = new cmd_dccallow(ServerInstance);\r          ServerInstance->AddCommand(mycommand);\r         ReadFileConf();\r        }\r\r     void Implements(char* List)\r    {\r              List[I_OnUserPreMessage] = List[I_OnUserPreNotice] = List[I_OnUserQuit] = List[I_OnUserPreNick] = List[I_OnRehash] = 1;\r        }\r\r     virtual void OnRehash(userrec* user, const std::string &parameter)\r     {\r              delete Conf;\r           Conf = new ConfigReader(ServerInstance);\r       }\r\r     virtual void OnUserQuit(userrec* user, const std::string &reason, const std::string &oper_message)\r     {\r              dccallowlist* dl;\r      \r               // remove their DCCALLOW list if they have one\r         user->GetExt("dccallow_list", dl);\r             if (dl)\r                {\r                      DELETE(dl);\r                    user->Shrink("dccallow_list");\r                 RemoveFromUserlist(user);\r              }\r              \r               // remove them from any DCCALLOW lists\r         // they are currently on\r               RemoveNick(user);\r      }\r\r\r    virtual int OnUserPreNick(userrec* user, const std::string &newnick)\r   {\r              RemoveNick(user);\r              return 0;\r      }\r\r     virtual int OnUserPreMessage(userrec* user, void* dest, int target_type, std::string &text, char status, CUList &exempt_list)\r  {\r              return OnUserPreNotice(user, dest, target_type, text, status, exempt_list);\r    }\r\r     virtual int OnUserPreNotice(userrec* user, void* dest, int target_type, std::string &text, char status, CUList &exempt_list)\r   {\r              if (!IS_LOCAL(user))\r                   return 0;\r\r             if (target_type == TYPE_USER)\r          {\r                      userrec* u = (userrec*)dest;\r\r                  /* Always allow a user to dcc themselves (although... why?) */\r                 if (user == u)\r                         return 0;\r              \r                       if ((text.length()) && (text[0] == '\1'))\r                      {\r                              Expire();\r\r                             // :jamie!jamie@test-D4457903BA652E0F.silverdream.org PRIVMSG eimaj :DCC SEND m_dnsbl.cpp 3232235786 52650 9676\r                                // :jamie!jamie@test-D4457903BA652E0F.silverdream.org PRIVMSG eimaj :VERSION\r                                   \r                               if (strncmp(text.c_str(), "\1DCC ", 5) == 0)\r                           {\r                                      u->GetExt("dccallow_list", dl);\r                \r                                       if (dl && dl->size())\r                                  {\r                                              for (dccallowlist::const_iterator iter = dl->begin(); iter != dl->end(); ++iter)\r                                                       if (ServerInstance->MatchText(user->GetFullHost(), iter->hostmask))\r                                                            return 0;\r                                      }\r              \r                                       // tokenize\r                                    std::stringstream ss(text);\r                                    std::string buf;\r                                       std::vector<std::string> tokens;\r               \r                                       while (ss >> buf)\r                                              tokens.push_back(buf);\r         \r                                       irc::string type = tokens[1].c_str();\r          \r                                       bool blockchat = Conf->ReadFlag("dccallow", "blockchat", 0);\r           \r                                       if (type == "SEND")\r                                    {\r                                              std::string defaultaction = Conf->ReadValue("dccallow", "action", 0);\r                                          std::string filename = tokens[2];\r                                      \r                                               if (defaultaction == "allow") \r                                                 return 0;\r                              \r                                               for (unsigned int i = 0; i < bfl.size(); i++)\r                                          {\r                                                      if (ServerInstance->MatchText(filename, bfl[i].filemask))\r                                                      {\r                                                              if (bfl[i].action == "allow")\r                                                                  return 0;\r                                                      }\r                                                      else\r                                                   {\r                                                              if (defaultaction == "allow")\r                                                                  return 0;\r                                                      }\r                                                      user->WriteServ("NOTICE %s :The user %s is not accepting DCC SENDs from you. Your file %s was not sent.", user->nick, u->nick, filename.c_str());\r                                                      u->WriteServ("NOTICE %s :%s (%s@%s) attempted to send you a file named %s, which was blocked.", u->nick, user->nick, user->ident, user->dhost, filename.c_str());\r                                                      u->WriteServ("NOTICE %s :If you trust %s and were expecting this, you can type /DCCALLOW HELP for information on the DCCALLOW system.", u->nick, user->nick);\r                                                  return 1;\r                                              }\r                                      }\r                                      else if ((type == "CHAT") && (blockchat))\r                                      {\r                                              user->WriteServ("NOTICE %s :The user %s is not accepting DCC CHAT requests from you.", user->nick, u->nick);\r                                           u->WriteServ("NOTICE %s :%s (%s@%s) attempted to initiate a DCC CHAT session, which was blocked.", u->nick, user->nick, user->ident, user->dhost);\r                                             u->WriteServ("NOTICE %s :If you trust %s and were expecting this, you can type /DCCALLOW HELP for information on the DCCALLOW system.", u->nick, user->nick);\r                                          return 1;\r                                      }\r                              }\r                      }\r              }\r              return 0;\r      }\r      \r       void Expire()\r  {\r              for (userlist::iterator iter = ul.begin(); iter != ul.end(); ++iter)\r           {\r                      userrec* u = (userrec*)(*iter);\r                        u->GetExt("dccallow_list", dl);\r        \r                       if (dl)\r                        {\r                              if (dl->size())\r                                {\r                                      dccallowlist::iterator iter = dl->begin();\r                                     while (iter != dl->end())\r                                      {\r                                              if ((iter->set_on + iter->length) <= ServerInstance->Time())\r                                           {\r                                                      u->WriteServ("997 %s %s :DCCALLOW entry for %s has expired", u->nick, u->nick, iter->nickname.c_str());\r                                                        iter = dl->erase(iter);\r                                                }\r                                              else\r                                           {\r                                                      ++iter;\r                                                }\r                                      }\r                              }\r                      }\r                      else\r                   {\r                              RemoveFromUserlist(u);\r                 }\r              }\r      }\r      \r       void RemoveNick(userrec* user)\r {\r              /* Iterate through all DCCALLOW lists and remove user */\r               for (userlist::iterator iter = ul.begin(); iter != ul.end(); ++iter)\r           {\r                      userrec *u = (userrec*)(*iter);\r                        u->GetExt("dccallow_list", dl);\r        \r                       if (dl)\r                        {\r                              if (dl->size())\r                                {\r                                      for (dccallowlist::iterator i = dl->begin(); i != dl->end(); ++i)\r                                      {\r                                              if (i->nickname == user->nick)\r                                         {\r                                      \r                                                       u->WriteServ("NOTICE %s :%s left the network or changed their nickname and has been removed from your DCCALLOW list", u->nick, i->nickname.c_str());\r                                                   u->WriteServ("995 %s %s :Removed %s from your DCCALLOW list", u->nick, u->nick, i->nickname.c_str());\r                                                  dl->erase(i);\r                                                  break;\r                                         }\r                                      }\r                              }\r                      }\r                      else\r                   {\r                              RemoveFromUserlist(u);\r                 }\r              }\r      }\r\r     void RemoveFromUserlist(userrec *user)\r {\r              // remove user from userlist\r           for (userlist::iterator j = ul.begin(); j != ul.end(); ++j)\r            {\r                      userrec* u = (userrec*)(*j);\r                   if (u == user)\r                 {\r                              ul.erase(j);\r                           break;\r                 }\r              }\r      }\r\r     void ReadFileConf()\r    {\r              bfl.clear();\r           for (int i = 0; i < Conf->Enumerate("banfile"); i++)\r           {\r                      BannedFileList bf;\r                     std::string fileglob = Conf->ReadValue("banfile", "pattern", i);\r                       std::string action = Conf->ReadValue("banfile", "action", i);\r                  bf.filemask = fileglob;\r                        bf.action = action;\r                    bfl.push_back(bf);\r             }\r      \r       }\r\r     virtual ~ModuleDCCAllow()\r      {\r      }\r\r     virtual Version GetVersion()\r   {\r              return Version(1,1,0,0,VF_COMMON|VF_VENDOR,API_VERSION);\r       }\r};\r\rMODULE_INIT(ModuleDCCAllow)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+
+/* $ModDesc: Povides support for the /DCCALLOW command */
+
+static ConfigReader *Conf;
+
+class BannedFileList
+{
+ public:
+       std::string filemask;
+       std::string action;
+};
+
+class DCCAllow
+{
+ public:
+       std::string nickname;
+       std::string hostmask;
+       time_t set_on;
+       long length;
+
+       DCCAllow() { }
+
+       DCCAllow(const std::string &nick, const std::string &hm, const time_t so, const long ln) : nickname(nick), hostmask(hm), set_on(so), length(ln) { }
+};
+
+typedef std::vector<userrec *> userlist;
+userlist ul;
+typedef std::vector<DCCAllow> dccallowlist;
+dccallowlist* dl;
+typedef std::vector<BannedFileList> bannedfilelist;
+bannedfilelist bfl;
+
+class cmd_dccallow : public command_t
+{
+ public:
+       cmd_dccallow(InspIRCd* Me) : command_t(Me, "DCCALLOW", 0, 0)
+       {
+               this->source = "m_dccallow.so";
+               syntax = "{[+|-]<nick> <time>|HELP|LIST}";
+       }
+
+       CmdResult Handle(const char **parameters, int pcnt, userrec *user)
+       {
+               /* syntax: DCCALLOW [+|-]<nick> (<time>) */
+               if (!pcnt)
+               {
+                       // display current DCCALLOW list
+                       DisplayDCCAllowList(user);
+                       return CMD_FAILURE;
+               }
+               else if (pcnt > 0)
+               {
+                       char action = *parameters[0];
+               
+                       // if they didn't specify an action, this is probably a command
+                       if (action != '+' && action != '-')
+                       {
+                               if (!strcasecmp(parameters[0], "LIST"))
+                               {
+                                       // list current DCCALLOW list
+                                       DisplayDCCAllowList(user);
+                                       return CMD_FAILURE;
+                               } 
+                               else if (!strcasecmp(parameters[0], "HELP"))
+                               {
+                                       // display help
+                                       DisplayHelp(user);
+                                       return CMD_FAILURE;
+                               }
+                       }
+                       
+                       std::string nick = parameters[0] + 1;
+                       userrec *target = ServerInstance->FindNick(nick);
+       
+                       if (target)
+                       {
+                               
+                               if (action == '-')
+                               {
+                                       user->GetExt("dccallow_list", dl);
+                                       // check if it contains any entries
+                                       if (dl)
+                                       {
+                                               if (dl->size())
+                                               {
+                                                       for (dccallowlist::iterator i = dl->begin(); i != dl->end(); ++i)
+                                                       {
+                                                               // search through list
+                                                               if (i->nickname == target->nick)
+                                                               {
+                                                                       dl->erase(i);
+                                                                       user->WriteServ("995 %s %s :Removed %s from your DCCALLOW list", user->nick, user->nick, target->nick);
+                                                                       break;
+                                                               }
+                                                       }
+                                               }
+                                       }
+                                       else
+                                       {
+                                               DELETE(dl);
+                                               user->Shrink("dccallow_list");
+                               
+                                               // remove from userlist
+                                               for (userlist::iterator j = ul.begin(); j != ul.end(); ++j)
+                                               {
+                                                       userrec* u = (userrec*)(*j);
+                                                       if (u == user)
+                                                       {
+                                                               ul.erase(j);
+                                                               break;
+                                                       }
+                                               }
+                                       }
+                               }
+                               else if (action == '+')
+                               {
+                                       // fetch current DCCALLOW list
+                                       user->GetExt("dccallow_list", dl);
+                                       // they don't have one, create it
+                                       if (!dl)
+                                       {
+                                               dl = new dccallowlist;
+                                               user->Extend("dccallow_list", dl);
+                                               // add this user to the userlist
+                                               ul.push_back(user);
+                                       }
+                                       for (dccallowlist::const_iterator k = dl->begin(); k != dl->end(); ++k)
+                                       {
+                                               if (k->nickname == target->nick)
+                                               {
+                                                       user->WriteServ("996 %s %s :%s is already on your DCCALLOW list", user->nick, user->nick, target->nick);
+                                                       return CMD_FAILURE;
+                                               }
+                                               else if (ServerInstance->MatchText(user->GetFullHost(), k->hostmask))
+                                               {
+                                                       user->WriteServ("996 %s %s :You cannot add yourself to your own DCCALLOW list!", user->nick, user->nick);
+                                                       return CMD_FAILURE;
+                                               }
+                                       }
+                               
+                                       std::string mask = std::string(target->nick)+"!"+std::string(target->ident)+"@"+std::string(target->dhost);
+                                       std::string default_length = Conf->ReadValue("dccallow", "length", 0);
+               
+                                       long length;
+                                       if (pcnt < 2)
+                                       {
+                                               length = ServerInstance->Duration(default_length);
+                                       } 
+                                       else if (!atoi(parameters[1]))
+                                       {
+                                               length = 0;
+                                       }
+                                       else
+                                       {
+                                               length = ServerInstance->Duration(parameters[1]);
+                                       }
+       
+                                       if (!ServerInstance->IsValidMask(mask.c_str()))
+                                       {
+                                               return CMD_FAILURE;
+                                       }
+                       
+                                       dl->push_back(DCCAllow(target->nick, mask, ServerInstance->Time(), length));
+                       
+                                       if (length > 0)
+                                       {
+                                               user->WriteServ("993 %s %s :Added %s to DCCALLOW list for %d seconds", user->nick, user->nick, target->nick, length);
+                                       }
+                                       else
+                                       {
+                                               user->WriteServ("994 %s %s :Added %s to DCCALLOW list for this session", user->nick, user->nick, target->nick);
+                                       }
+
+                                       /* route it. */
+                                       return CMD_SUCCESS;
+                               }
+                       }
+                       else
+                       {
+                               // nick doesn't exist
+                               user->WriteServ("401 %s %s :No such nick/channel", user->nick, nick.c_str());
+                               return CMD_FAILURE;
+                       }
+               }
+               return CMD_FAILURE;
+       }
+
+       void DisplayHelp(userrec* user)
+       {
+               user->WriteServ("998 %s :DCCALLOW [<+|->nick [time]] [list] [help]", user->nick);
+               user->WriteServ("998 %s :You may allow DCCs from specific users by specifying a", user->nick);
+               user->WriteServ("998 %s :DCC allow for the user you want to receive DCCs from.", user->nick);
+               user->WriteServ("998 %s :For example, to allow the user Brain to send you inspircd.exe", user->nick);
+               user->WriteServ("998 %s :you would type:", user->nick);
+               user->WriteServ("998 %s :/DCCALLOW +Brain", user->nick);
+               user->WriteServ("998 %s :Brain would then be able to send you files. They would have to", user->nick);
+               user->WriteServ("998 %s :resend the file again if the server gave them an error message", user->nick);
+               user->WriteServ("998 %s :before you added them to your DCCALLOW list.", user->nick);
+               user->WriteServ("998 %s :DCCALLOW entries will be temporary by default, if you want to add", user->nick);
+               user->WriteServ("998 %s :them to your DCCALLOW list until you leave IRC, type:", user->nick);
+               user->WriteServ("998 %s :/DCCALLOW +Brain 0", user->nick);
+               user->WriteServ("998 %s :To remove the user from your DCCALLOW list, type:", user->nick);
+               user->WriteServ("998 %s :/DCCALLOW -Brain", user->nick);
+               user->WriteServ("998 %s :To see the users in your DCCALLOW list, type:", user->nick);
+               user->WriteServ("998 %s :/DCCALLOW LIST", user->nick);
+               user->WriteServ("998 %s :NOTE: If the user leaves IRC or changes their nickname", user->nick);
+               user->WriteServ("998 %s :  they will be removed from your DCCALLOW list.", user->nick);
+               user->WriteServ("998 %s :  your DCCALLOW list will be deleted when you leave IRC.", user->nick);
+               user->WriteServ("999 %s :End of DCCALLOW HELP", user->nick);
+       }
+       
+       void DisplayDCCAllowList(userrec* user)
+       {
+                // display current DCCALLOW list
+               user->WriteServ("990 %s :Users on your DCCALLOW list:", user->nick);
+               user->GetExt("dccallow_list", dl);
+               
+               if (dl)
+               {
+                       for (dccallowlist::const_iterator c = dl->begin(); c != dl->end(); ++c)
+                       {
+                               user->WriteServ("991 %s %s :%s (%s)", user->nick, user->nick, c->nickname.c_str(), c->hostmask.c_str());
+                       }
+               }
+               
+               user->WriteServ("992 %s :End of DCCALLOW list", user->nick);
+       }                       
+
+};
+       
+class ModuleDCCAllow : public Module
+{
+       cmd_dccallow* mycommand;
+ public:
+
+       ModuleDCCAllow(InspIRCd* Me)
+               : Module(Me)
+       {
+               Conf = new ConfigReader(ServerInstance);
+               mycommand = new cmd_dccallow(ServerInstance);
+               ServerInstance->AddCommand(mycommand);
+               ReadFileConf();
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnUserPreMessage] = List[I_OnUserPreNotice] = List[I_OnUserQuit] = List[I_OnUserPreNick] = List[I_OnRehash] = 1;
+       }
+
+       virtual void OnRehash(userrec* user, const std::string &parameter)
+       {
+               delete Conf;
+               Conf = new ConfigReader(ServerInstance);
+       }
+
+       virtual void OnUserQuit(userrec* user, const std::string &reason, const std::string &oper_message)
+       {
+               dccallowlist* dl;
+       
+               // remove their DCCALLOW list if they have one
+               user->GetExt("dccallow_list", dl);
+               if (dl)
+               {
+                       DELETE(dl);
+                       user->Shrink("dccallow_list");
+                       RemoveFromUserlist(user);
+               }
+               
+               // remove them from any DCCALLOW lists
+               // they are currently on
+               RemoveNick(user);
+       }
+
+
+       virtual int OnUserPreNick(userrec* user, const std::string &newnick)
+       {
+               RemoveNick(user);
+               return 0;
+       }
+
+       virtual int OnUserPreMessage(userrec* user, void* dest, int target_type, std::string &text, char status, CUList &exempt_list)
+       {
+               return OnUserPreNotice(user, dest, target_type, text, status, exempt_list);
+       }
+
+       virtual int OnUserPreNotice(userrec* user, void* dest, int target_type, std::string &text, char status, CUList &exempt_list)
+       {
+               if (!IS_LOCAL(user))
+                       return 0;
+
+               if (target_type == TYPE_USER)
+               {
+                       userrec* u = (userrec*)dest;
+
+                       /* Always allow a user to dcc themselves (although... why?) */
+                       if (user == u)
+                               return 0;
+               
+                       if ((text.length()) && (text[0] == '\1'))
+                       {
+                               Expire();
+
+                               // :jamie!jamie@test-D4457903BA652E0F.silverdream.org PRIVMSG eimaj :DCC SEND m_dnsbl.cpp 3232235786 52650 9676
+                               // :jamie!jamie@test-D4457903BA652E0F.silverdream.org PRIVMSG eimaj :VERSION
+                                       
+                               if (strncmp(text.c_str(), "\1DCC ", 5) == 0)
+                               {
+                                       u->GetExt("dccallow_list", dl);
+               
+                                       if (dl && dl->size())
+                                       {
+                                               for (dccallowlist::const_iterator iter = dl->begin(); iter != dl->end(); ++iter)
+                                                       if (ServerInstance->MatchText(user->GetFullHost(), iter->hostmask))
+                                                               return 0;
+                                       }
+               
+                                       // tokenize
+                                       std::stringstream ss(text);
+                                       std::string buf;
+                                       std::vector<std::string> tokens;
+               
+                                       while (ss >> buf)
+                                               tokens.push_back(buf);
+               
+                                       irc::string type = tokens[1].c_str();
+               
+                                       bool blockchat = Conf->ReadFlag("dccallow", "blockchat", 0);
+               
+                                       if (type == "SEND")
+                                       {
+                                               std::string defaultaction = Conf->ReadValue("dccallow", "action", 0);
+                                               std::string filename = tokens[2];
+                                       
+                                               if (defaultaction == "allow") 
+                                                       return 0;
+                               
+                                               for (unsigned int i = 0; i < bfl.size(); i++)
+                                               {
+                                                       if (ServerInstance->MatchText(filename, bfl[i].filemask))
+                                                       {
+                                                               if (bfl[i].action == "allow")
+                                                                       return 0;
+                                                       }
+                                                       else
+                                                       {
+                                                               if (defaultaction == "allow")
+                                                                       return 0;
+                                                       }
+                                                       user->WriteServ("NOTICE %s :The user %s is not accepting DCC SENDs from you. Your file %s was not sent.", user->nick, u->nick, filename.c_str());
+                                                       u->WriteServ("NOTICE %s :%s (%s@%s) attempted to send you a file named %s, which was blocked.", u->nick, user->nick, user->ident, user->dhost, filename.c_str());
+                                                       u->WriteServ("NOTICE %s :If you trust %s and were expecting this, you can type /DCCALLOW HELP for information on the DCCALLOW system.", u->nick, user->nick);
+                                                       return 1;
+                                               }
+                                       }
+                                       else if ((type == "CHAT") && (blockchat))
+                                       {
+                                               user->WriteServ("NOTICE %s :The user %s is not accepting DCC CHAT requests from you.", user->nick, u->nick);
+                                               u->WriteServ("NOTICE %s :%s (%s@%s) attempted to initiate a DCC CHAT session, which was blocked.", u->nick, user->nick, user->ident, user->dhost);
+                                               u->WriteServ("NOTICE %s :If you trust %s and were expecting this, you can type /DCCALLOW HELP for information on the DCCALLOW system.", u->nick, user->nick);
+                                               return 1;
+                                       }
+                               }
+                       }
+               }
+               return 0;
+       }
+       
+       void Expire()
+       {
+               for (userlist::iterator iter = ul.begin(); iter != ul.end(); ++iter)
+               {
+                       userrec* u = (userrec*)(*iter);
+                       u->GetExt("dccallow_list", dl);
+       
+                       if (dl)
+                       {
+                               if (dl->size())
+                               {
+                                       dccallowlist::iterator iter = dl->begin();
+                                       while (iter != dl->end())
+                                       {
+                                               if ((iter->set_on + iter->length) <= ServerInstance->Time())
+                                               {
+                                                       u->WriteServ("997 %s %s :DCCALLOW entry for %s has expired", u->nick, u->nick, iter->nickname.c_str());
+                                                       iter = dl->erase(iter);
+                                               }
+                                               else
+                                               {
+                                                       ++iter;
+                                               }
+                                       }
+                               }
+                       }
+                       else
+                       {
+                               RemoveFromUserlist(u);
+                       }
+               }
+       }
+       
+       void RemoveNick(userrec* user)
+       {
+               /* Iterate through all DCCALLOW lists and remove user */
+               for (userlist::iterator iter = ul.begin(); iter != ul.end(); ++iter)
+               {
+                       userrec *u = (userrec*)(*iter);
+                       u->GetExt("dccallow_list", dl);
+       
+                       if (dl)
+                       {
+                               if (dl->size())
+                               {
+                                       for (dccallowlist::iterator i = dl->begin(); i != dl->end(); ++i)
+                                       {
+                                               if (i->nickname == user->nick)
+                                               {
+                                       
+                                                       u->WriteServ("NOTICE %s :%s left the network or changed their nickname and has been removed from your DCCALLOW list", u->nick, i->nickname.c_str());
+                                                       u->WriteServ("995 %s %s :Removed %s from your DCCALLOW list", u->nick, u->nick, i->nickname.c_str());
+                                                       dl->erase(i);
+                                                       break;
+                                               }
+                                       }
+                               }
+                       }
+                       else
+                       {
+                               RemoveFromUserlist(u);
+                       }
+               }
+       }
+
+       void RemoveFromUserlist(userrec *user)
+       {
+               // remove user from userlist
+               for (userlist::iterator j = ul.begin(); j != ul.end(); ++j)
+               {
+                       userrec* u = (userrec*)(*j);
+                       if (u == user)
+                       {
+                               ul.erase(j);
+                               break;
+                       }
+               }
+       }
+
+       void ReadFileConf()
+       {
+               bfl.clear();
+               for (int i = 0; i < Conf->Enumerate("banfile"); i++)
+               {
+                       BannedFileList bf;
+                       std::string fileglob = Conf->ReadValue("banfile", "pattern", i);
+                       std::string action = Conf->ReadValue("banfile", "action", i);
+                       bf.filemask = fileglob;
+                       bf.action = action;
+                       bfl.push_back(bf);
+               }
+       
+       }
+
+       virtual ~ModuleDCCAllow()
+       {
+       }
+
+       virtual Version GetVersion()
+       {
+               return Version(1,1,0,0,VF_COMMON|VF_VENDOR,API_VERSION);
+       }
+};
+
+MODULE_INIT(ModuleDCCAllow)
index d9681010d0cbbb3ae3e482dede6187a932dfdfdd..ad8b31714ee089e26f2633e846ec4b7e6b070295 100644 (file)
@@ -1 +1,135 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r\r/* $ModDesc: Provides support for ircu style usermode +d (deaf to channel messages and channel notices) */\r\r/** User mode +d - filter out channel messages and channel notices\r */\rclass User_d : public ModeHandler\r{\r public:\r      User_d(InspIRCd* Instance) : ModeHandler(Instance, 'd', 0, 0, false, MODETYPE_USER, false) { }\r\r        ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)\r {\r              if (adding)\r            {\r                      if (!dest->IsModeSet('d'))\r                     {\r                              dest->WriteServ("NOTICE %s :*** You have enabled usermode +d, deaf mode. This mode means you WILL NOT receive any messages from any channels you are in. If you did NOT mean to do this, use /mode %s -d.", dest->nick, dest->nick);\r                           dest->SetMode('d',true);\r                               return MODEACTION_ALLOW;\r                       }\r              }\r              else\r           {\r                      if (dest->IsModeSet('d'))\r                      {\r                              dest->SetMode('d',false);\r                              return MODEACTION_ALLOW;\r                       }\r              }\r              return MODEACTION_DENY;\r        }\r};\r\rclass ModuleDeaf : public Module\r{\r       User_d* m1;\r public:\r   ModuleDeaf(InspIRCd* Me)\r               : Module(Me)\r   {\r              m1 = new User_d(ServerInstance);\r               if (!ServerInstance->AddMode(m1, 'd'))\r                 throw ModuleException("Could not add new modes!");\r     }\r\r     void Implements(char* List)\r    {\r              List[I_OnUserPreMessage] = List[I_OnUserPreNotice] = List[I_OnBuildExemptList] = 1;\r    }\r\r     virtual int OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)\r     {\r              return PreText(user, dest, target_type, text, status, exempt_list);\r    }\r\r     virtual int OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)\r    {\r              return PreText(user, dest, target_type, text, status, exempt_list);\r    }\r\r     virtual void OnBuildExemptList(MessageType message_type, chanrec* chan, userrec* sender, char status, CUList &exempt_list)\r     {\r              CUList *ulist;\r         switch (status)\r                {\r                      case '@':\r                              ulist = chan->GetOppedUsers();\r                         break;\r                 case '%':\r                              ulist = chan->GetHalfoppedUsers();\r                             break;\r                 case '+':\r                              ulist = chan->GetVoicedUsers();\r                                break;\r                 default:\r                               ulist = chan->GetUsers();\r                              break;\r         }\r\r             for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)\r              {\r                      if (IS_LOCAL(i->first))\r                        {\r                              if (i->first->IsModeSet('d'))\r                          {\r                                      exempt_list[i->first] = i->first->nick;\r                                }\r                      }\r              }\r      }\r\r     virtual int PreText(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)\r     {\r              if ((target_type == TYPE_CHANNEL) & (IS_LOCAL(user)))\r          {\r                      chanrec* chan = (chanrec*)dest;\r                        if (chan)\r                      {\r                              this->OnBuildExemptList(MSG_PRIVMSG, chan, user, status, exempt_list);\r                 }\r              }\r              return 0;\r      }\r\r     virtual ~ModuleDeaf()\r  {\r              ServerInstance->Modes->DelMode(m1);\r            DELETE(m1);\r    }\r\r     virtual Version GetVersion()\r   {\r              return Version(1,1,0,0,VF_COMMON|VF_VENDOR,API_VERSION);\r       }\r\r};\r\rMODULE_INIT(ModuleDeaf)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+
+/* $ModDesc: Provides support for ircu style usermode +d (deaf to channel messages and channel notices) */
+
+/** User mode +d - filter out channel messages and channel notices
+ */
+class User_d : public ModeHandler
+{
+ public:
+       User_d(InspIRCd* Instance) : ModeHandler(Instance, 'd', 0, 0, false, MODETYPE_USER, false) { }
+
+       ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)
+       {
+               if (adding)
+               {
+                       if (!dest->IsModeSet('d'))
+                       {
+                               dest->WriteServ("NOTICE %s :*** You have enabled usermode +d, deaf mode. This mode means you WILL NOT receive any messages from any channels you are in. If you did NOT mean to do this, use /mode %s -d.", dest->nick, dest->nick);
+                               dest->SetMode('d',true);
+                               return MODEACTION_ALLOW;
+                       }
+               }
+               else
+               {
+                       if (dest->IsModeSet('d'))
+                       {
+                               dest->SetMode('d',false);
+                               return MODEACTION_ALLOW;
+                       }
+               }
+               return MODEACTION_DENY;
+       }
+};
+
+class ModuleDeaf : public Module
+{
+       User_d* m1;
+ public:
+       ModuleDeaf(InspIRCd* Me)
+               : Module(Me)
+       {
+               m1 = new User_d(ServerInstance);
+               if (!ServerInstance->AddMode(m1, 'd'))
+                       throw ModuleException("Could not add new modes!");
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnUserPreMessage] = List[I_OnUserPreNotice] = List[I_OnBuildExemptList] = 1;
+       }
+
+       virtual int OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
+       {
+               return PreText(user, dest, target_type, text, status, exempt_list);
+       }
+
+       virtual int OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
+       {
+               return PreText(user, dest, target_type, text, status, exempt_list);
+       }
+
+       virtual void OnBuildExemptList(MessageType message_type, chanrec* chan, userrec* sender, char status, CUList &exempt_list)
+       {
+               CUList *ulist;
+               switch (status)
+               {
+                       case '@':
+                               ulist = chan->GetOppedUsers();
+                               break;
+                       case '%':
+                               ulist = chan->GetHalfoppedUsers();
+                               break;
+                       case '+':
+                               ulist = chan->GetVoicedUsers();
+                               break;
+                       default:
+                               ulist = chan->GetUsers();
+                               break;
+               }
+
+               for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
+               {
+                       if (IS_LOCAL(i->first))
+                       {
+                               if (i->first->IsModeSet('d'))
+                               {
+                                       exempt_list[i->first] = i->first->nick;
+                               }
+                       }
+               }
+       }
+
+       virtual int PreText(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
+       {
+               if ((target_type == TYPE_CHANNEL) & (IS_LOCAL(user)))
+               {
+                       chanrec* chan = (chanrec*)dest;
+                       if (chan)
+                       {
+                               this->OnBuildExemptList(MSG_PRIVMSG, chan, user, status, exempt_list);
+                       }
+               }
+               return 0;
+       }
+
+       virtual ~ModuleDeaf()
+       {
+               ServerInstance->Modes->DelMode(m1);
+               DELETE(m1);
+       }
+
+       virtual Version GetVersion()
+       {
+               return Version(1,1,0,0,VF_COMMON|VF_VENDOR,API_VERSION);
+       }
+
+};
+
+MODULE_INIT(ModuleDeaf)
index d09e04766b19cfd0214f122326e47e80d492fc9e..4a01faa7c68559e24c283dafb1dd96bf968fa33e 100644 (file)
@@ -1 +1,80 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r#include "hashcomp.h"\r#include "wildcard.h"\r\r/* $ModDesc: Implements config tags which allow blocking of joins to channels */\r\rclass ModuleDenyChannels : public Module\r{\r private:\r\r  \r       ConfigReader *Conf;\r\r public:\r  ModuleDenyChannels(InspIRCd* Me) : Module(Me)\r  {\r              \r               Conf = new ConfigReader(ServerInstance);\r       }\r      \r       virtual void OnRehash(userrec* user, const std::string &param)\r {\r              DELETE(Conf);\r          Conf = new ConfigReader(ServerInstance);\r       }\r\r     virtual ~ModuleDenyChannels()\r  {\r              DELETE(Conf);\r  }\r      \r       virtual Version GetVersion()\r   {\r              return Version(1,1,0,1,VF_VENDOR,API_VERSION);\r }\r\r     void Implements(char* List)\r    {\r              List[I_OnUserPreJoin] = List[I_OnRehash] = 1;\r  }\r\r     virtual int OnUserPreJoin(userrec* user, chanrec* chan, const char* cname, std::string &privs)\r {\r              for (int j =0; j < Conf->Enumerate("badchan"); j++)\r            {\r                      if (match(cname, Conf->ReadValue("badchan","name",j).c_str()))\r                 {\r                              if (IS_OPER(user) && Conf->ReadFlag("badchan","allowopers",j))\r                         {\r                                      return 0;\r                              }\r                              else\r                           {\r                                      std::string reason = Conf->ReadValue("badchan","reason",j);\r                                    user->WriteServ("926 %s %s :Channel %s is forbidden: %s",user->nick,cname,cname,reason.c_str());\r                                       return 1;\r                              }\r                      }\r              }\r              return 0;\r      }\r};\r\rMODULE_INIT(ModuleDenyChannels)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+#include "hashcomp.h"
+#include "wildcard.h"
+
+/* $ModDesc: Implements config tags which allow blocking of joins to channels */
+
+class ModuleDenyChannels : public Module
+{
+ private:
+
+       
+       ConfigReader *Conf;
+
+ public:
+       ModuleDenyChannels(InspIRCd* Me) : Module(Me)
+       {
+               
+               Conf = new ConfigReader(ServerInstance);
+       }
+       
+       virtual void OnRehash(userrec* user, const std::string &param)
+       {
+               DELETE(Conf);
+               Conf = new ConfigReader(ServerInstance);
+       }
+
+       virtual ~ModuleDenyChannels()
+       {
+               DELETE(Conf);
+       }
+       
+       virtual Version GetVersion()
+       {
+               return Version(1,1,0,1,VF_VENDOR,API_VERSION);
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnUserPreJoin] = List[I_OnRehash] = 1;
+       }
+
+       virtual int OnUserPreJoin(userrec* user, chanrec* chan, const char* cname, std::string &privs)
+       {
+               for (int j =0; j < Conf->Enumerate("badchan"); j++)
+               {
+                       if (match(cname, Conf->ReadValue("badchan","name",j).c_str()))
+                       {
+                               if (IS_OPER(user) && Conf->ReadFlag("badchan","allowopers",j))
+                               {
+                                       return 0;
+                               }
+                               else
+                               {
+                                       std::string reason = Conf->ReadValue("badchan","reason",j);
+                                       user->WriteServ("926 %s %s :Channel %s is forbidden: %s",user->nick,cname,cname,reason.c_str());
+                                       return 1;
+                               }
+                       }
+               }
+               return 0;
+       }
+};
+
+MODULE_INIT(ModuleDenyChannels)
index e760db85958ca78191d5fe0ccd2ff2bbab493469..e2ada413b960b143ce1b5ca2cc771184345ddfd9 100644 (file)
@@ -1 +1,81 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r/*\r * DEVOICE module for InspIRCd\r *  Syntax: /DEVOICE <#chan>\r */\r\r/* $ModDesc: Provides voiced users with the ability to devoice themselves. */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r\r/** Handle /DEVOICE\r */\rclass cmd_devoice : public command_t\r{\r public:\r   cmd_devoice (InspIRCd* Instance) : command_t(Instance,"DEVOICE", 0, 1)\r {\r              this->source = "m_devoice.so";\r         syntax = "<channel>";\r  }\r\r     CmdResult Handle (const char** parameters, int pcnt, userrec *user)\r    {\r              chanrec* c = ServerInstance->FindChan(parameters[0]);\r          if (c && c->HasUser(user))\r             {\r                      const char* modes[3];\r                  modes[0] = parameters[0];\r                      modes[1] = "-v";\r                       modes[2] = user->nick;\r\r                        userrec* n = new userrec(ServerInstance);\r                      n->SetFd(FD_MAGIC_NUMBER);\r                     ServerInstance->SendMode(modes,3,n);\r                   delete n;\r\r                     /* route it */\r                 return CMD_SUCCESS;\r            }\r\r             return CMD_FAILURE;\r    }\r};\r\rclass ModuleDeVoice : public Module\r{\r    cmd_devoice *mycommand;\r public:\r       ModuleDeVoice(InspIRCd* Me) : Module(Me)\r       {\r\r             mycommand = new cmd_devoice(ServerInstance);\r           ServerInstance->AddCommand(mycommand);\r }\r\r     virtual ~ModuleDeVoice()\r       {\r      }\r\r     virtual Version GetVersion()\r   {\r              return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION);\r    }\r};\r\rMODULE_INIT(ModuleDeVoice)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+/*
+ * DEVOICE module for InspIRCd
+ *  Syntax: /DEVOICE <#chan>
+ */
+
+/* $ModDesc: Provides voiced users with the ability to devoice themselves. */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+
+/** Handle /DEVOICE
+ */
+class cmd_devoice : public command_t
+{
+ public:
+       cmd_devoice (InspIRCd* Instance) : command_t(Instance,"DEVOICE", 0, 1)
+       {
+               this->source = "m_devoice.so";
+               syntax = "<channel>";
+       }
+
+       CmdResult Handle (const char** parameters, int pcnt, userrec *user)
+       {
+               chanrec* c = ServerInstance->FindChan(parameters[0]);
+               if (c && c->HasUser(user))
+               {
+                       const char* modes[3];
+                       modes[0] = parameters[0];
+                       modes[1] = "-v";
+                       modes[2] = user->nick;
+
+                       userrec* n = new userrec(ServerInstance);
+                       n->SetFd(FD_MAGIC_NUMBER);
+                       ServerInstance->SendMode(modes,3,n);
+                       delete n;
+
+                       /* route it */
+                       return CMD_SUCCESS;
+               }
+
+               return CMD_FAILURE;
+       }
+};
+
+class ModuleDeVoice : public Module
+{
+       cmd_devoice *mycommand;
+ public:
+       ModuleDeVoice(InspIRCd* Me) : Module(Me)
+       {
+
+               mycommand = new cmd_devoice(ServerInstance);
+               ServerInstance->AddCommand(mycommand);
+       }
+
+       virtual ~ModuleDeVoice()
+       {
+       }
+
+       virtual Version GetVersion()
+       {
+               return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION);
+       }
+};
+
+MODULE_INIT(ModuleDeVoice)
index 87e9a2cbabea9ffd6877bdbb49fcbad0af66c545..d07b268f7bf4a4db4f9bdc48318fba97e7353c82 100644 (file)
@@ -1 +1,353 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "xline.h"\r#include "dns.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r\r#ifndef WINDOWS\r#include <sys/types.h>\r#include <sys/socket.h>\r#include <netinet/in.h>\r#include <arpa/inet.h>\r#endif\r\r/* $ModDesc: Provides handling of DNS blacklists */\r\r/* Class holding data for a single entry */\rclass DNSBLConfEntry\r{\r    public:\r                enum EnumBanaction { I_UNKNOWN, I_KILL, I_ZLINE, I_KLINE, I_GLINE };\r           std::string name, domain, reason;\r              EnumBanaction banaction;\r               long duration;\r         int bitmask;\r           unsigned long stats_hits, stats_misses;\r                DNSBLConfEntry(): duration(86400),bitmask(0),stats_hits(0), stats_misses(0) {}\r         ~DNSBLConfEntry() { }\r};\r\r\r/** Resolver for CGI:IRC hostnames encoded in ident/GECOS\r */\rclass DNSBLResolver : public Resolver\r{\r       int theirfd;\r   userrec* them;\r DNSBLConfEntry *ConfEntry;\r\r public:\r\r  DNSBLResolver(Module *me, InspIRCd *ServerInstance, const std::string &hostname, userrec* u, int userfd, DNSBLConfEntry *conf, bool &cached)\r           : Resolver(ServerInstance, hostname, DNS_QUERY_A, cached, me)\r  {\r              theirfd = userfd;\r              them = u;\r              ConfEntry = conf;\r      }\r\r     virtual void OnLookupComplete(const std::string &result, unsigned int ttl, bool cached)\r        {\r              /* Check the user still exists */\r              if ((them) && (them == ServerInstance->SE->GetRef(theirfd)))\r           {\r                      // Now we calculate the bitmask: 256*(256*(256*a+b)+c)+d\r                       if(result.length())\r                    {\r                              unsigned int bitmask = 0;\r                              bool show = false;\r                             in_addr resultip;\r\r                             /* Convert the result to an in_addr (we can gaurantee we got ipv4)\r                              * Whoever did the loop that was here before, I AM CONFISCATING\r                                 * YOUR CRACKPIPE. you know who you are. -- Brain\r                               */\r                            inet_aton(result.c_str(), &resultip);\r                          bitmask = resultip.s_addr >> 24; /* Last octet (network byte order */\r\r                         bitmask &= ConfEntry->bitmask;\r\r                                if (bitmask != 0)\r                              {\r                                      std::string reason = ConfEntry->reason;\r                                        std::string::size_type x = reason.find("%ip%");\r                                        while (x != std::string::npos)\r                                 {\r                                              reason.erase(x, 4);\r                                            reason.insert(x, them->GetIPString());\r                                         x = reason.find("%ip%");\r                                       }\r\r                                     ConfEntry->stats_hits++;\r\r                                      switch (ConfEntry->banaction)\r                                  {\r                                              case DNSBLConfEntry::I_KILL:\r                                           {\r                                                      userrec::QuitUser(ServerInstance, them, std::string("Killed (") + reason + ")");\r                                                       break;\r                                         }\r                                              case DNSBLConfEntry::I_KLINE:\r                                          {\r                                                      std::string ban = std::string("*@") + them->GetIPString();\r                                                     if (show)\r                                                              ServerInstance->XLines->apply_lines(APPLY_KLINES);                                                              \r                                                       show = ServerInstance->XLines->add_kline(ConfEntry->duration, ServerInstance->Config->ServerName, reason.c_str(), ban.c_str());\r                                                        FOREACH_MOD(I_OnAddKLine,OnAddKLine(ConfEntry->duration, NULL, reason, ban));\r                                                  break;\r                                         }\r                                              case DNSBLConfEntry::I_GLINE:\r                                          {\r                                                      std::string ban = std::string("*@") + them->GetIPString();\r                                                     show = ServerInstance->XLines->add_gline(ConfEntry->duration, ServerInstance->Config->ServerName, reason.c_str(), ban.c_str());\r                                                        if (show)\r                                                              ServerInstance->XLines->apply_lines(APPLY_GLINES);\r                                                     FOREACH_MOD(I_OnAddGLine,OnAddGLine(ConfEntry->duration, NULL, reason, ban));\r                                                  break;\r                                         }\r                                              case DNSBLConfEntry::I_ZLINE:\r                                          {\r                                                      show = ServerInstance->XLines->add_zline(ConfEntry->duration, ServerInstance->Config->ServerName, reason.c_str(), them->GetIPString());\r                                                        if (show)\r                                                              ServerInstance->XLines->apply_lines(APPLY_ZLINES);\r                                                     FOREACH_MOD(I_OnAddZLine,OnAddZLine(ConfEntry->duration, NULL, reason, them->GetIPString()));\r                                                  break;\r                                         }\r                                              case DNSBLConfEntry::I_UNKNOWN:\r                                                {\r                                                      break;\r                                         }\r                                              break;\r                                 }\r\r                                     if (show)\r                                      {\r                                              ServerInstance->WriteOpers("*** Connecting user %s detected as being on a DNS blacklist (%s) with result %d", them->GetFullRealHost(), ConfEntry->name.c_str(), bitmask);\r                                      }\r                              }\r                              else\r                                   ConfEntry->stats_misses++;\r                     }\r                      else\r                           ConfEntry->stats_misses++;\r             }\r      }\r\r     virtual void OnError(ResolverError e, const std::string &errormessage)\r {\r      }\r\r     virtual ~DNSBLResolver()\r       {\r      }\r};\r\rclass ModuleDNSBL : public Module\r{\r private:\r    std::vector<DNSBLConfEntry *> DNSBLConfEntries;\r\r       /*\r      *      Convert a string to EnumBanaction\r       */\r    DNSBLConfEntry::EnumBanaction str2banaction(const std::string &action)\r {\r              if(action.compare("KILL")==0)\r                  return DNSBLConfEntry::I_KILL;\r         if(action.compare("KLINE")==0)\r                 return DNSBLConfEntry::I_KLINE;\r                if(action.compare("ZLINE")==0)\r                 return DNSBLConfEntry::I_ZLINE;\r                if(action.compare("GLINE")==0)\r                 return DNSBLConfEntry::I_GLINE;\r\r               return DNSBLConfEntry::I_UNKNOWN;\r      }\r public:\r     ModuleDNSBL(InspIRCd *Me) : Module(Me)\r {\r              ReadConf();\r    }\r\r     virtual ~ModuleDNSBL()\r {\r              ClearEntries();\r        }\r\r     virtual Version GetVersion()\r   {\r              return Version(2, 0, 0, 1, VF_VENDOR, API_VERSION);\r    }\r\r     void Implements(char* List)\r    {\r              List[I_OnRehash] = List[I_OnUserRegister] = List[I_OnStats] = 1;\r       }\r\r     /** Clear entries and free the mem it was using\r         */\r    void ClearEntries()\r    {\r              std::vector<DNSBLConfEntry *>::iterator i;\r             for (std::vector<DNSBLConfEntry *>::iterator i = DNSBLConfEntries.begin(); i != DNSBLConfEntries.end(); i++)\r                   delete *i;\r             DNSBLConfEntries.clear();\r      }\r\r     /** Fill our conf vector with data\r      */\r    virtual void ReadConf()\r        {\r              ConfigReader *MyConf = new ConfigReader(ServerInstance);\r               ClearEntries();\r\r               for (int i=0; i< MyConf->Enumerate("dnsbl"); i++)\r              {\r                      DNSBLConfEntry *e = new DNSBLConfEntry();\r\r                     e->name = MyConf->ReadValue("dnsbl", "name", i);\r                       e->reason = MyConf->ReadValue("dnsbl", "reason", i);\r                   e->domain = MyConf->ReadValue("dnsbl", "domain", i);\r                   e->banaction = str2banaction(MyConf->ReadValue("dnsbl", "action", i));\r                 e->duration = ServerInstance->Duration(MyConf->ReadValue("dnsbl", "duration", i));\r                     e->bitmask = MyConf->ReadInteger("dnsbl", "bitmask", i, false);\r\r                       /* yeah, logic here is a little messy */\r                       if (e->bitmask <= 0)\r                   {\r                              ServerInstance->WriteOpers("*** DNSBL(#%d): invalid bitmask",i);\r                       }\r                      else if (e->name.empty())\r                      {\r                              ServerInstance->WriteOpers("*** DNSBL(#%d): Invalid name",i);\r                  }\r                      else if (e->domain.empty())\r                    {\r                              ServerInstance->WriteOpers("*** DNSBL(#%d): Invalid domain",i);\r                        }\r                      else if (e->banaction == DNSBLConfEntry::I_UNKNOWN)\r                    {\r                              ServerInstance->WriteOpers("*** DNSBL(#%d): Invalid banaction", i);\r                    }\r                      else\r                   {\r                              if (e->reason.empty())\r                         {\r                                      ServerInstance->WriteOpers("*** DNSBL(#%d): empty reason, using defaults",i);\r                                  e->reason = "Your IP has been blacklisted.";\r                           }\r\r                             /* add it, all is ok */\r                                DNSBLConfEntries.push_back(e);\r                         continue;\r                      }\r\r                     /* delete and drop it, error somewhere */\r                      delete e;\r              }\r\r             delete MyConf;\r }\r\r     virtual void OnRehash(userrec* user, const std::string &parameter)\r     {\r              ReadConf();\r    }\r\r     virtual int OnUserRegister(userrec* user)\r      {\r              /* only do lookups on local users */\r           if (IS_LOCAL(user))\r            {\r                      /* following code taken from bopm, reverses an IP address. */\r                  struct in_addr in;\r                     unsigned char a, b, c, d;\r                      char reversedipbuf[128];\r                       std::string reversedip;\r                        bool success = false;\r\r                 if (!inet_aton(user->GetIPString(), &in))\r                      {\r#ifdef IPV6\r                          /* We could have an ipv6 address here */\r                               std::string x = user->GetIPString();\r                           /* Is it a 4in6 address? (Compensate for this kernel kludge that people love) */\r                               if (x.find("0::ffff:") == 0)\r                           {\r                                      x.erase(x.begin(), x.begin() + 8);\r                                     if (inet_aton(x.c_str(), &in))\r                                         success = true;\r                                }\r#endif\r                       }\r                      else\r                   {\r                              success = true;\r                        }\r\r                     if (!success)\r                          return 0;\r\r                     d = (unsigned char) (in.s_addr >> 24) & 0xFF;\r                  c = (unsigned char) (in.s_addr >> 16) & 0xFF;\r                  b = (unsigned char) (in.s_addr >> 8) & 0xFF;\r                   a = (unsigned char) in.s_addr & 0xFF;\r\r                 snprintf(reversedipbuf, 128, "%d.%d.%d.%d", d, c, b, a);\r                       reversedip = std::string(reversedipbuf);\r\r                      // For each DNSBL, we will run through this lookup\r                     for (std::vector<DNSBLConfEntry *>::iterator i = DNSBLConfEntries.begin(); i != DNSBLConfEntries.end(); i++)\r                   {\r                              // Fill hostname with a dnsbl style host (d.c.b.a.domain.tld)\r                          std::string hostname = reversedip + "." + (*i)->domain;\r\r                               /* now we'd need to fire off lookups for `hostname'. */\r                                bool cached;\r                           DNSBLResolver *r = new DNSBLResolver(this, ServerInstance, hostname, user, user->GetFd(), *i, cached);\r                         ServerInstance->AddResolver(r, cached);\r                        }\r              }\r\r             /* don't do anything with this hot potato */\r           return 0;\r      }\r      \r       virtual int OnStats(char symbol, userrec* user, string_list &results)\r  {\r              if (symbol != 'd')\r                     return 0;\r              \r               unsigned long total_hits = 0, total_misses = 0;\r\r               for (std::vector<DNSBLConfEntry*>::iterator i = DNSBLConfEntries.begin(); i != DNSBLConfEntries.end(); i++)\r            {\r                      total_hits += (*i)->stats_hits;\r                        total_misses += (*i)->stats_misses;\r                    \r                       results.push_back(std::string(ServerInstance->Config->ServerName) + " 304 " + user->nick + " :DNSBLSTATS DNSbl \"" + (*i)->name + "\" had " +\r                                  ConvToStr((*i)->stats_hits) + " hits and " + ConvToStr((*i)->stats_misses) + " misses");\r               }\r              \r               results.push_back(std::string(ServerInstance->Config->ServerName) + " 304 " + user->nick + " :DNSBLSTATS Total hits: " + ConvToStr(total_hits));\r               results.push_back(std::string(ServerInstance->Config->ServerName) + " 304 " + user->nick + " :DNSBLSTATS Total misses: " + ConvToStr(total_misses));\r           \r               return 0;\r      }\r};\r\rMODULE_INIT(ModuleDNSBL)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "xline.h"
+#include "dns.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+
+#ifndef WINDOWS
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#endif
+
+/* $ModDesc: Provides handling of DNS blacklists */
+
+/* Class holding data for a single entry */
+class DNSBLConfEntry
+{
+       public:
+               enum EnumBanaction { I_UNKNOWN, I_KILL, I_ZLINE, I_KLINE, I_GLINE };
+               std::string name, domain, reason;
+               EnumBanaction banaction;
+               long duration;
+               int bitmask;
+               unsigned long stats_hits, stats_misses;
+               DNSBLConfEntry(): duration(86400),bitmask(0),stats_hits(0), stats_misses(0) {}
+               ~DNSBLConfEntry() { }
+};
+
+
+/** Resolver for CGI:IRC hostnames encoded in ident/GECOS
+ */
+class DNSBLResolver : public Resolver
+{
+       int theirfd;
+       userrec* them;
+       DNSBLConfEntry *ConfEntry;
+
+ public:
+
+       DNSBLResolver(Module *me, InspIRCd *ServerInstance, const std::string &hostname, userrec* u, int userfd, DNSBLConfEntry *conf, bool &cached)
+               : Resolver(ServerInstance, hostname, DNS_QUERY_A, cached, me)
+       {
+               theirfd = userfd;
+               them = u;
+               ConfEntry = conf;
+       }
+
+       virtual void OnLookupComplete(const std::string &result, unsigned int ttl, bool cached)
+       {
+               /* Check the user still exists */
+               if ((them) && (them == ServerInstance->SE->GetRef(theirfd)))
+               {
+                       // Now we calculate the bitmask: 256*(256*(256*a+b)+c)+d
+                       if(result.length())
+                       {
+                               unsigned int bitmask = 0;
+                               bool show = false;
+                               in_addr resultip;
+
+                               /* Convert the result to an in_addr (we can gaurantee we got ipv4)
+                                * Whoever did the loop that was here before, I AM CONFISCATING
+                                * YOUR CRACKPIPE. you know who you are. -- Brain
+                                */
+                               inet_aton(result.c_str(), &resultip);
+                               bitmask = resultip.s_addr >> 24; /* Last octet (network byte order */
+
+                               bitmask &= ConfEntry->bitmask;
+
+                               if (bitmask != 0)
+                               {
+                                       std::string reason = ConfEntry->reason;
+                                       std::string::size_type x = reason.find("%ip%");
+                                       while (x != std::string::npos)
+                                       {
+                                               reason.erase(x, 4);
+                                               reason.insert(x, them->GetIPString());
+                                               x = reason.find("%ip%");
+                                       }
+
+                                       ConfEntry->stats_hits++;
+
+                                       switch (ConfEntry->banaction)
+                                       {
+                                               case DNSBLConfEntry::I_KILL:
+                                               {
+                                                       userrec::QuitUser(ServerInstance, them, std::string("Killed (") + reason + ")");
+                                                       break;
+                                               }
+                                               case DNSBLConfEntry::I_KLINE:
+                                               {
+                                                       std::string ban = std::string("*@") + them->GetIPString();
+                                                       if (show)
+                                                               ServerInstance->XLines->apply_lines(APPLY_KLINES);                                                              
+                                                       show = ServerInstance->XLines->add_kline(ConfEntry->duration, ServerInstance->Config->ServerName, reason.c_str(), ban.c_str());
+                                                       FOREACH_MOD(I_OnAddKLine,OnAddKLine(ConfEntry->duration, NULL, reason, ban));
+                                                       break;
+                                               }
+                                               case DNSBLConfEntry::I_GLINE:
+                                               {
+                                                       std::string ban = std::string("*@") + them->GetIPString();
+                                                       show = ServerInstance->XLines->add_gline(ConfEntry->duration, ServerInstance->Config->ServerName, reason.c_str(), ban.c_str());
+                                                       if (show)
+                                                               ServerInstance->XLines->apply_lines(APPLY_GLINES);
+                                                       FOREACH_MOD(I_OnAddGLine,OnAddGLine(ConfEntry->duration, NULL, reason, ban));
+                                                       break;
+                                               }
+                                               case DNSBLConfEntry::I_ZLINE:
+                                               {
+                                                       show = ServerInstance->XLines->add_zline(ConfEntry->duration, ServerInstance->Config->ServerName, reason.c_str(), them->GetIPString());
+                                                       if (show)
+                                                               ServerInstance->XLines->apply_lines(APPLY_ZLINES);
+                                                       FOREACH_MOD(I_OnAddZLine,OnAddZLine(ConfEntry->duration, NULL, reason, them->GetIPString()));
+                                                       break;
+                                               }
+                                               case DNSBLConfEntry::I_UNKNOWN:
+                                               {
+                                                       break;
+                                               }
+                                               break;
+                                       }
+
+                                       if (show)
+                                       {
+                                               ServerInstance->WriteOpers("*** Connecting user %s detected as being on a DNS blacklist (%s) with result %d", them->GetFullRealHost(), ConfEntry->name.c_str(), bitmask);
+                                       }
+                               }
+                               else
+                                       ConfEntry->stats_misses++;
+                       }
+                       else
+                               ConfEntry->stats_misses++;
+               }
+       }
+
+       virtual void OnError(ResolverError e, const std::string &errormessage)
+       {
+       }
+
+       virtual ~DNSBLResolver()
+       {
+       }
+};
+
+class ModuleDNSBL : public Module
+{
+ private:
+       std::vector<DNSBLConfEntry *> DNSBLConfEntries;
+
+       /*
+        *      Convert a string to EnumBanaction
+        */
+       DNSBLConfEntry::EnumBanaction str2banaction(const std::string &action)
+       {
+               if(action.compare("KILL")==0)
+                       return DNSBLConfEntry::I_KILL;
+               if(action.compare("KLINE")==0)
+                       return DNSBLConfEntry::I_KLINE;
+               if(action.compare("ZLINE")==0)
+                       return DNSBLConfEntry::I_ZLINE;
+               if(action.compare("GLINE")==0)
+                       return DNSBLConfEntry::I_GLINE;
+
+               return DNSBLConfEntry::I_UNKNOWN;
+       }
+ public:
+       ModuleDNSBL(InspIRCd *Me) : Module(Me)
+       {
+               ReadConf();
+       }
+
+       virtual ~ModuleDNSBL()
+       {
+               ClearEntries();
+       }
+
+       virtual Version GetVersion()
+       {
+               return Version(2, 0, 0, 1, VF_VENDOR, API_VERSION);
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnRehash] = List[I_OnUserRegister] = List[I_OnStats] = 1;
+       }
+
+       /** Clear entries and free the mem it was using
+        */
+       void ClearEntries()
+       {
+               std::vector<DNSBLConfEntry *>::iterator i;
+               for (std::vector<DNSBLConfEntry *>::iterator i = DNSBLConfEntries.begin(); i != DNSBLConfEntries.end(); i++)
+                       delete *i;
+               DNSBLConfEntries.clear();
+       }
+
+       /** Fill our conf vector with data
+        */
+       virtual void ReadConf()
+       {
+               ConfigReader *MyConf = new ConfigReader(ServerInstance);
+               ClearEntries();
+
+               for (int i=0; i< MyConf->Enumerate("dnsbl"); i++)
+               {
+                       DNSBLConfEntry *e = new DNSBLConfEntry();
+
+                       e->name = MyConf->ReadValue("dnsbl", "name", i);
+                       e->reason = MyConf->ReadValue("dnsbl", "reason", i);
+                       e->domain = MyConf->ReadValue("dnsbl", "domain", i);
+                       e->banaction = str2banaction(MyConf->ReadValue("dnsbl", "action", i));
+                       e->duration = ServerInstance->Duration(MyConf->ReadValue("dnsbl", "duration", i));
+                       e->bitmask = MyConf->ReadInteger("dnsbl", "bitmask", i, false);
+
+                       /* yeah, logic here is a little messy */
+                       if (e->bitmask <= 0)
+                       {
+                               ServerInstance->WriteOpers("*** DNSBL(#%d): invalid bitmask",i);
+                       }
+                       else if (e->name.empty())
+                       {
+                               ServerInstance->WriteOpers("*** DNSBL(#%d): Invalid name",i);
+                       }
+                       else if (e->domain.empty())
+                       {
+                               ServerInstance->WriteOpers("*** DNSBL(#%d): Invalid domain",i);
+                       }
+                       else if (e->banaction == DNSBLConfEntry::I_UNKNOWN)
+                       {
+                               ServerInstance->WriteOpers("*** DNSBL(#%d): Invalid banaction", i);
+                       }
+                       else
+                       {
+                               if (e->reason.empty())
+                               {
+                                       ServerInstance->WriteOpers("*** DNSBL(#%d): empty reason, using defaults",i);
+                                       e->reason = "Your IP has been blacklisted.";
+                               }
+
+                               /* add it, all is ok */
+                               DNSBLConfEntries.push_back(e);
+                               continue;
+                       }
+
+                       /* delete and drop it, error somewhere */
+                       delete e;
+               }
+
+               delete MyConf;
+       }
+
+       virtual void OnRehash(userrec* user, const std::string &parameter)
+       {
+               ReadConf();
+       }
+
+       virtual int OnUserRegister(userrec* user)
+       {
+               /* only do lookups on local users */
+               if (IS_LOCAL(user))
+               {
+                       /* following code taken from bopm, reverses an IP address. */
+                       struct in_addr in;
+                       unsigned char a, b, c, d;
+                       char reversedipbuf[128];
+                       std::string reversedip;
+                       bool success = false;
+
+                       if (!inet_aton(user->GetIPString(), &in))
+                       {
+#ifdef IPV6
+                               /* We could have an ipv6 address here */
+                               std::string x = user->GetIPString();
+                               /* Is it a 4in6 address? (Compensate for this kernel kludge that people love) */
+                               if (x.find("0::ffff:") == 0)
+                               {
+                                       x.erase(x.begin(), x.begin() + 8);
+                                       if (inet_aton(x.c_str(), &in))
+                                               success = true;
+                               }
+#endif
+                       }
+                       else
+                       {
+                               success = true;
+                       }
+
+                       if (!success)
+                               return 0;
+
+                       d = (unsigned char) (in.s_addr >> 24) & 0xFF;
+                       c = (unsigned char) (in.s_addr >> 16) & 0xFF;
+                       b = (unsigned char) (in.s_addr >> 8) & 0xFF;
+                       a = (unsigned char) in.s_addr & 0xFF;
+
+                       snprintf(reversedipbuf, 128, "%d.%d.%d.%d", d, c, b, a);
+                       reversedip = std::string(reversedipbuf);
+
+                       // For each DNSBL, we will run through this lookup
+                       for (std::vector<DNSBLConfEntry *>::iterator i = DNSBLConfEntries.begin(); i != DNSBLConfEntries.end(); i++)
+                       {
+                               // Fill hostname with a dnsbl style host (d.c.b.a.domain.tld)
+                               std::string hostname = reversedip + "." + (*i)->domain;
+
+                               /* now we'd need to fire off lookups for `hostname'. */
+                               bool cached;
+                               DNSBLResolver *r = new DNSBLResolver(this, ServerInstance, hostname, user, user->GetFd(), *i, cached);
+                               ServerInstance->AddResolver(r, cached);
+                       }
+               }
+
+               /* don't do anything with this hot potato */
+               return 0;
+       }
+       
+       virtual int OnStats(char symbol, userrec* user, string_list &results)
+       {
+               if (symbol != 'd')
+                       return 0;
+               
+               unsigned long total_hits = 0, total_misses = 0;
+
+               for (std::vector<DNSBLConfEntry*>::iterator i = DNSBLConfEntries.begin(); i != DNSBLConfEntries.end(); i++)
+               {
+                       total_hits += (*i)->stats_hits;
+                       total_misses += (*i)->stats_misses;
+                       
+                       results.push_back(std::string(ServerInstance->Config->ServerName) + " 304 " + user->nick + " :DNSBLSTATS DNSbl \"" + (*i)->name + "\" had " +
+                                       ConvToStr((*i)->stats_hits) + " hits and " + ConvToStr((*i)->stats_misses) + " misses");
+               }
+               
+               results.push_back(std::string(ServerInstance->Config->ServerName) + " 304 " + user->nick + " :DNSBLSTATS Total hits: " + ConvToStr(total_hits));
+               results.push_back(std::string(ServerInstance->Config->ServerName) + " 304 " + user->nick + " :DNSBLSTATS Total misses: " + ConvToStr(total_misses));
+               
+               return 0;
+       }
+};
+
+MODULE_INIT(ModuleDNSBL)
index 9c16c8bf31ee4f346c3b3b225240d0eae31374cc..70de88e2cb8ac405d3a4614b4d6514d9e67a36e2 100644 (file)
@@ -1 +1,135 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r#include "m_filter.h"\r\r/* $ModDesc: An advanced spam filtering module */\r/* $ModDep: m_filter.h */\r\rtypedef std::map<std::string,FilterResult*> filter_t;\r\rclass ModuleFilter : public FilterBase\r{\r \r filter_t filters;\r\r public:\r    ModuleFilter(InspIRCd* Me)\r     : FilterBase(Me, "m_filter.so")\r        {\r              OnRehash(NULL,"");\r     }\r      \r       virtual ~ModuleFilter()\r        {\r      }\r\r     virtual FilterResult* FilterMatch(userrec* user, const std::string &text, int flags)\r   {\r              for (filter_t::iterator index = filters.begin(); index != filters.end(); index++)\r              {\r\r                     /* Skip ones that dont apply to us */\r                  if (!FilterBase::AppliesToMe(user, index->second, flags))\r                              continue;\r\r                     if (ServerInstance->MatchText(text,index->first))\r                      {\r                              FilterResult* fr = index->second;\r                              if (index != filters.begin())\r                          {\r                                      std::string pat = index->first;\r                                        filters.erase(index);\r                                  filters.insert(filters.begin(), std::make_pair(pat,fr));\r                               }\r                              return fr;\r                     }\r              }\r              return NULL;\r   }\r\r     virtual bool DeleteFilter(const std::string &freeform)\r {\r              if (filters.find(freeform) != filters.end())\r           {\r                      delete (filters.find(freeform))->second;\r                       filters.erase(filters.find(freeform));\r                 return true;\r           }\r              return false;\r  }\r\r     virtual std::pair<bool, std::string> AddFilter(const std::string &freeform, const std::string &type, const std::string &reason, long duration, const std::string &flags)\r       {\r              if (filters.find(freeform) != filters.end())\r           {\r                      return std::make_pair(false, "Filter already exists");\r         }\r\r             FilterResult* x = new FilterResult(freeform, reason, type, duration, flags);\r           filters[freeform] = x;\r\r                return std::make_pair(true, "");\r       }\r\r     virtual void SyncFilters(Module* proto, void* opaque)\r  {\r              for (filter_t::iterator n = filters.begin(); n != filters.end(); n++)\r          {\r                      this->SendFilter(proto, opaque, n->second);\r            }\r      }\r\r     virtual void OnRehash(userrec* user, const std::string &parameter)\r     {\r              ConfigReader* MyConf = new ConfigReader(ServerInstance);\r\r              for (int index = 0; index < MyConf->Enumerate("keyword"); index++)\r             {\r                      this->DeleteFilter(MyConf->ReadValue("keyword","pattern",index));\r\r                     std::string pattern = MyConf->ReadValue("keyword","pattern",index);\r                    std::string reason = MyConf->ReadValue("keyword","reason",index);\r                      std::string do_action = MyConf->ReadValue("keyword","action",index);\r                   std::string flags = MyConf->ReadValue("keyword","flags",index);\r                        long gline_time = ServerInstance->Duration(MyConf->ReadValue("keyword","duration",index));\r                     if (do_action.empty())\r                         do_action = "none";\r                    if (flags.empty())\r                             flags = "*";\r                   FilterResult* x = new FilterResult(pattern, reason, do_action, gline_time, flags);\r                     filters[pattern] = x;\r          }\r              DELETE(MyConf);\r        }\r\r     virtual int OnStats(char symbol, userrec* user, string_list &results)\r  {\r              if (symbol == 's')\r             {\r                      std::string sn = ServerInstance->Config->ServerName;\r                   for (filter_t::iterator n = filters.begin(); n != filters.end(); n++)\r                  {\r                              results.push_back(sn+" 223 "+user->nick+" :GLOB:"+n->second->freeform+" "+n->second->flags+" "+n->second->action+" "+ConvToStr(n->second->gline_time)+" :"+n->second->reason);\r                 }\r              }\r              return 0;\r      }\r};\r\r\rMODULE_INIT(ModuleFilter)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+#include "m_filter.h"
+
+/* $ModDesc: An advanced spam filtering module */
+/* $ModDep: m_filter.h */
+
+typedef std::map<std::string,FilterResult*> filter_t;
+
+class ModuleFilter : public FilterBase
+{
+ filter_t filters;
+
+ public:
+       ModuleFilter(InspIRCd* Me)
+       : FilterBase(Me, "m_filter.so")
+       {
+               OnRehash(NULL,"");
+       }
+       
+       virtual ~ModuleFilter()
+       {
+       }
+
+       virtual FilterResult* FilterMatch(userrec* user, const std::string &text, int flags)
+       {
+               for (filter_t::iterator index = filters.begin(); index != filters.end(); index++)
+               {
+
+                       /* Skip ones that dont apply to us */
+                       if (!FilterBase::AppliesToMe(user, index->second, flags))
+                               continue;
+
+                       if (ServerInstance->MatchText(text,index->first))
+                       {
+                               FilterResult* fr = index->second;
+                               if (index != filters.begin())
+                               {
+                                       std::string pat = index->first;
+                                       filters.erase(index);
+                                       filters.insert(filters.begin(), std::make_pair(pat,fr));
+                               }
+                               return fr;
+                       }
+               }
+               return NULL;
+       }
+
+       virtual bool DeleteFilter(const std::string &freeform)
+       {
+               if (filters.find(freeform) != filters.end())
+               {
+                       delete (filters.find(freeform))->second;
+                       filters.erase(filters.find(freeform));
+                       return true;
+               }
+               return false;
+       }
+
+       virtual std::pair<bool, std::string> AddFilter(const std::string &freeform, const std::string &type, const std::string &reason, long duration, const std::string &flags)
+       {
+               if (filters.find(freeform) != filters.end())
+               {
+                       return std::make_pair(false, "Filter already exists");
+               }
+
+               FilterResult* x = new FilterResult(freeform, reason, type, duration, flags);
+               filters[freeform] = x;
+
+               return std::make_pair(true, "");
+       }
+
+       virtual void SyncFilters(Module* proto, void* opaque)
+       {
+               for (filter_t::iterator n = filters.begin(); n != filters.end(); n++)
+               {
+                       this->SendFilter(proto, opaque, n->second);
+               }
+       }
+
+       virtual void OnRehash(userrec* user, const std::string &parameter)
+       {
+               ConfigReader* MyConf = new ConfigReader(ServerInstance);
+
+               for (int index = 0; index < MyConf->Enumerate("keyword"); index++)
+               {
+                       this->DeleteFilter(MyConf->ReadValue("keyword","pattern",index));
+
+                       std::string pattern = MyConf->ReadValue("keyword","pattern",index);
+                       std::string reason = MyConf->ReadValue("keyword","reason",index);
+                       std::string do_action = MyConf->ReadValue("keyword","action",index);
+                       std::string flags = MyConf->ReadValue("keyword","flags",index);
+                       long gline_time = ServerInstance->Duration(MyConf->ReadValue("keyword","duration",index));
+                       if (do_action.empty())
+                               do_action = "none";
+                       if (flags.empty())
+                               flags = "*";
+                       FilterResult* x = new FilterResult(pattern, reason, do_action, gline_time, flags);
+                       filters[pattern] = x;
+               }
+               DELETE(MyConf);
+       }
+
+       virtual int OnStats(char symbol, userrec* user, string_list &results)
+       {
+               if (symbol == 's')
+               {
+                       std::string sn = ServerInstance->Config->ServerName;
+                       for (filter_t::iterator n = filters.begin(); n != filters.end(); n++)
+                       {
+                               results.push_back(sn+" 223 "+user->nick+" :GLOB:"+n->second->freeform+" "+n->second->flags+" "+n->second->action+" "+ConvToStr(n->second->gline_time)+" :"+n->second->reason);
+                       }
+               }
+               return 0;
+       }
+};
+
+
+MODULE_INIT(ModuleFilter)
index ddf448e2eb98a40d32af09469cb2fcd627a8bb05..f2986804c3fe63a67df338b7d487693faba887d8 100644 (file)
@@ -1 +1,453 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "xline.h"\r\renum FilterFlags\r{\r    FLAG_NOOPERS = 1,\r      FLAG_PART = 2,\r FLAG_QUIT = 4,\r FLAG_PRIVMSG = 8,\r      FLAG_NOTICE = 16\r};\r\rclass FilterResult : public classbase\r{\r public:\r  std::string freeform;\r  std::string reason;\r    std::string action;\r    long gline_time;\r       std::string flags;\r\r    bool flag_no_opers;\r    bool flag_part_message;\r        bool flag_quit_message;\r        bool flag_privmsg;\r     bool flag_notice;\r\r     FilterResult(const std::string free, const std::string &rea, const std::string &act, long gt, const std::string &fla) : freeform(free), reason(rea),\r                                                                   action(act), gline_time(gt), flags(fla)\r        {\r              this->FillFlags(flags);\r        }\r\r     int FillFlags(const std::string &fl)\r   {\r              flags = fl;\r            flag_no_opers = flag_part_message = flag_quit_message = flag_privmsg = flag_notice = false;\r            size_t x = 0;\r\r         for (std::string::const_iterator n = flags.begin(); n != flags.end(); ++n, ++x)\r                {\r                      switch (*n)\r                    {\r                              case 'o':\r                                      flag_no_opers = true;\r                          break;\r                         case 'P':\r                                      flag_part_message = true;\r                              break;\r                         case 'q':\r                                      flag_quit_message = true;\r                              break;\r                         case 'p':\r                                      flag_privmsg = true;\r                           break;\r                         case 'n':\r                                      flag_notice = true;\r                            break;\r                         case '*':\r                                      flag_no_opers = flag_part_message = flag_quit_message =\r                                                flag_privmsg = flag_notice = true;\r                             break;\r                         default:\r                                       return x;\r                              break;\r                 }\r              }\r              return 0;\r      }\r\r     FilterResult()\r {\r      }\r\r     virtual ~FilterResult()\r        {\r      }\r};\r\rclass cmd_filter;\r\rclass FilterBase : public Module\r{\r    cmd_filter* filtcommand;\r       int flags;\r public:\r    FilterBase(InspIRCd* Me, const std::string &source);\r   virtual ~FilterBase();\r virtual void Implements(char* List);\r   virtual int OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list);\r   virtual FilterResult* FilterMatch(userrec* user, const std::string &text, int flags) = 0;\r      virtual bool DeleteFilter(const std::string &freeform) = 0;\r    virtual void SyncFilters(Module* proto, void* opaque) = 0;\r     virtual void SendFilter(Module* proto, void* opaque, FilterResult* iter);\r      virtual std::pair<bool, std::string> AddFilter(const std::string &freeform, const std::string &type, const std::string &reason, long duration, const std::string &flags) = 0;\r  virtual int OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list);\r    virtual void OnRehash(userrec* user, const std::string &parameter);\r    virtual Version GetVersion();\r  std::string EncodeFilter(FilterResult* filter);\r        FilterResult DecodeFilter(const std::string &data);\r    virtual void OnSyncOtherMetaData(Module* proto, void* opaque, bool displayable = false);\r       virtual void OnDecodeMetaData(int target_type, void* target, const std::string &extname, const std::string &extdata);\r  virtual int OnStats(char symbol, userrec* user, string_list &results) = 0;\r     virtual int OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line);\r      bool AppliesToMe(userrec* user, FilterResult* filter, int flags);\r};\r\rclass cmd_filter : public command_t\r{\r    FilterBase* Base;\r public:\r     cmd_filter(FilterBase* f, InspIRCd* Me, const std::string &source) : command_t(Me, "FILTER", 'o', 1), Base(f)\r  {\r              this->source = source;\r         this->syntax = "<filter-definition> <type> <flags> [<gline-duration>] :<reason>";\r      }\r\r     CmdResult Handle(const char** parameters, int pcnt, userrec *user)\r     {\r              if (pcnt == 1)\r         {\r                      /* Deleting a filter */\r                        if (Base->DeleteFilter(parameters[0]))\r                 {\r                              user->WriteServ("NOTICE %s :*** Deleted filter '%s'", user->nick, parameters[0]);\r                              return CMD_SUCCESS;\r                    }\r                      else\r                   {\r                              user->WriteServ("NOTICE %s :*** Filter '%s' not found on list.", user->nick, parameters[0]);\r                           return CMD_FAILURE;\r                    }\r              }\r              else\r           {\r                      /* Adding a filter */\r                  if (pcnt >= 4)\r                 {\r                              std::string freeform = parameters[0];\r                          std::string type = parameters[1];\r                              std::string flags = parameters[2];\r                             std::string reason;\r                            long duration = 0;\r\r\r                           if ((type != "gline") && (type != "none") && (type != "block") && (type != "kill") && (type != "silent"))\r                              {\r                                      user->WriteServ("NOTICE %s :*** Invalid filter type '%s'. Supported types are 'gline', 'none', 'block', 'silent' and 'kill'.", user->nick, freeform.c_str());\r                                  return CMD_FAILURE;\r                            }\r\r                             if (type == "gline")\r                           {\r                                      if (pcnt >= 5)\r                                 {\r                                              duration = ServerInstance->Duration(parameters[3]);\r                                            reason = parameters[4];\r                                        }\r                                      else\r                                   {\r                                              this->TooFewParams(user, " When setting a gline type filter, a gline duration must be specified as the third parameter.");\r                                             return CMD_FAILURE;\r                                    }\r                              }\r                              else\r                           {\r                                      reason = parameters[3];\r                                }\r                              std::pair<bool, std::string> result = Base->AddFilter(freeform, type, reason, duration, flags);\r                                if (result.first)\r                              {\r                                      user->WriteServ("NOTICE %s :*** Added filter '%s', type '%s'%s%s, flags '%s', reason: '%s'", user->nick, freeform.c_str(),\r                                                     type.c_str(), (duration ? " duration: " : ""), (duration ? parameters[3] : ""),\r                                                        flags.c_str(), reason.c_str());\r                                        return CMD_SUCCESS;\r                            }\r                              else\r                           {\r                                      user->WriteServ("NOTICE %s :*** Filter '%s' could not be added: %s", user->nick, freeform.c_str(), result.second.c_str());\r                                     return CMD_FAILURE;\r                            }\r                      }\r                      else\r                   {\r                              this->TooFewParams(user, ".");\r                         return CMD_FAILURE;\r                    }\r\r             }\r      }\r\r     void TooFewParams(userrec* user, const std::string &extra_text)\r        {\r              user->WriteServ("NOTICE %s :*** Not enough parameters%s", user->nick, extra_text.c_str());\r     }\r};\r\rbool FilterBase::AppliesToMe(userrec* user, FilterResult* filter, int flags)\r{\r   if ((flags & FLAG_NOOPERS) && (filter->flag_no_opers) && IS_OPER(user))\r                return false;\r  if ((flags & FLAG_PRIVMSG) && (!filter->flag_privmsg))\r         return false;\r  if ((flags & FLAG_NOTICE) && (!filter->flag_notice))\r           return false;\r  if ((flags & FLAG_QUIT)   && (!filter->flag_quit_message))\r             return false;\r  if ((flags & FLAG_PART)   && (!filter->flag_part_message))\r             return false;\r  return true;\r}\r\rFilterBase::FilterBase(InspIRCd* Me, const std::string &source) : Module(Me)\r{\r filtcommand = new cmd_filter(this, Me, source);\r        ServerInstance->AddCommand(filtcommand);\r}\r\rFilterBase::~FilterBase()\r{\r}\r\rvoid FilterBase::Implements(char* List)\r{\r   List[I_OnPreCommand] = List[I_OnStats] = List[I_OnSyncOtherMetaData] = List[I_OnDecodeMetaData] = List[I_OnUserPreMessage] = List[I_OnUserPreNotice] = List[I_OnRehash] = 1;\r}\r\rint FilterBase::OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)\r{\r      flags = FLAG_PRIVMSG;\r  return OnUserPreNotice(user,dest,target_type,text,status,exempt_list);\r}\r\rint FilterBase::OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)\r{\r     if (!flags)\r            flags = FLAG_NOTICE;\r\r  /* Leave ulines alone */\r       if ((ServerInstance->ULine(user->server)) || (!IS_LOCAL(user)))\r                return 0;\r\r     FilterResult* f = this->FilterMatch(user, text, flags);\r        if (f)\r {\r              std::string target = "";\r               if (target_type == TYPE_USER)\r          {\r                      userrec* t = (userrec*)dest;\r                   target = std::string(t->nick);\r         }\r              else if (target_type == TYPE_CHANNEL)\r          {\r                      chanrec* t = (chanrec*)dest;\r                   target = std::string(t->name);\r         }\r              if (f->action == "block")\r              {       \r                       ServerInstance->WriteOpers(std::string("FILTER: ")+user->nick+" had their message filtered, target was "+target+": "+f->reason);\r                       user->WriteServ("NOTICE "+std::string(user->nick)+" :Your message has been filtered and opers notified: "+f->reason);\r          }\r              if (f->action == "silent")\r             {\r                      user->WriteServ("NOTICE "+std::string(user->nick)+" :Your message has been filtered: "+f->reason);\r             }\r              if (f->action == "kill")\r               {\r                      userrec::QuitUser(ServerInstance,user,"Filtered: "+f->reason);\r         }\r              if (f->action == "gline")\r              {\r                      if (ServerInstance->XLines->add_gline(f->gline_time, ServerInstance->Config->ServerName, f->reason.c_str(), user->MakeHostIP()))\r                       {\r                              ServerInstance->XLines->apply_lines(APPLY_GLINES);\r                             FOREACH_MOD(I_OnAddGLine,OnAddGLine(f->gline_time, NULL, f->reason, user->MakeHostIP()));\r                      }\r              }\r\r             ServerInstance->Log(DEFAULT,"FILTER: "+std::string(user->nick)+std::string(" had their message filtered, target was ")+target+": "+f->reason+" Action: "+f->action);\r           return 1;\r      }\r      return 0;\r}\r\rint FilterBase::OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line)\r{\r    flags = 0;\r     if ((validated == 1) && (IS_LOCAL(user)))\r      {\r              std::string checkline;\r         int replacepoint = 0;\r          bool parting = false;\r  \r               if (command == "QUIT")\r         {\r                      /* QUIT with no reason: nothing to do */\r                       if (pcnt < 1)\r                          return 0;\r\r                     checkline = parameters[0];\r                     replacepoint = 0;\r                      parting = false;\r                       flags = FLAG_QUIT;\r             }\r              else if (command == "PART")\r            {\r                      /* PART with no reason: nothing to do */\r                       if (pcnt < 2)\r                          return 0;\r\r                     checkline = parameters[1];\r                     replacepoint = 1;\r                      parting = true;\r                        flags = FLAG_PART;\r             }\r              else\r                   /* We're only messing with PART and QUIT */\r                    return 0;\r\r             FilterResult* f = NULL;\r                \r               if (flags)\r                     f = this->FilterMatch(user, checkline, flags);\r\r                if (!f)\r                        /* PART or QUIT reason doesnt match a filter */\r                        return 0;\r\r             /* We cant block a part or quit, so instead we change the reason to 'Reason filtered' */\r               command_t* c = ServerInstance->Parser->GetHandler(command);\r            if (c)\r         {\r                      const char* params[127];\r                       for (int item = 0; item < pcnt; item++)\r                                params[item] = parameters[item];\r                       params[replacepoint] = "Reason filtered";\r\r                     /* We're blocking, OR theyre quitting and its a KILL action\r                     * (we cant kill someone whos already quitting, so filter them anyway)\r                  */\r                    if ((f->action == "block") || (((!parting) && (f->action == "kill"))) || (f->action == "silent"))\r                      {\r                              c->Handle(params, pcnt, user);\r                         return 1;\r                      }\r                      else\r                   {\r                              /* Are they parting, if so, kill is applicable */\r                              if ((parting) && (f->action == "kill"))\r                                {\r                                      user->SetWriteError("Filtered: "+f->reason);\r                                   /* This WriteServ causes the write error to be applied.\r                                         * Its not safe to kill here with QuitUser in a PreCommand handler,\r                                     * so we do it this way, which is safe just about anywhere.\r                                     */\r                                    user->WriteServ("NOTICE %s :*** Your PART message was filtered: %s", user->nick, f->reason.c_str());\r                           }\r                              if (f->action == "gline")\r                              {\r                                      /* Note: We gline *@IP so that if their host doesnt resolve the gline still applies. */\r                                        std::string wild = "*@";\r                                       wild.append(user->GetIPString());\r\r                                     if (ServerInstance->XLines->add_gline(f->gline_time, ServerInstance->Config->ServerName, f->reason.c_str(), wild.c_str()))\r                                     {\r                                              ServerInstance->XLines->apply_lines(APPLY_GLINES);\r                                             FOREACH_MOD(I_OnAddGLine,OnAddGLine(f->gline_time, NULL, f->reason, user->MakeHostIP()));\r                                      }\r                              }\r                              return 1;\r                      }\r              }\r              return 0;\r      }\r      return 0;\r}\r\rvoid FilterBase::OnRehash(userrec* user, const std::string &parameter)\r{\r}\r        \rVersion FilterBase::GetVersion()\r{\r    return Version(1,1,0,2,VF_VENDOR|VF_COMMON,API_VERSION);\r}\r\r\rstd::string FilterBase::EncodeFilter(FilterResult* filter)\r{\r      std::ostringstream stream;\r     std::string x = filter->freeform;\r\r     /* Hax to allow spaces in the freeform without changing the design of the irc protocol */\r      for (std::string::iterator n = x.begin(); n != x.end(); n++)\r           if (*n == ' ')\r                 *n = '\7';\r\r    stream << x << " " << filter->action << " " << (filter->flags.empty() ? "-" : filter->flags) << " " << filter->gline_time << " :" << filter->reason;\r   return stream.str();\r}\r\rFilterResult FilterBase::DecodeFilter(const std::string &data)\r{\r       FilterResult res;\r      irc::tokenstream tokens(data);\r tokens.GetToken(res.freeform);\r tokens.GetToken(res.action);\r   tokens.GetToken(res.flags);\r    if (res.flags == "-")\r          res.flags = "";\r        res.FillFlags(res.flags);\r      tokens.GetToken(res.gline_time);\r       tokens.GetToken(res.reason);\r\r  /* Hax to allow spaces in the freeform without changing the design of the irc protocol */\r      for (std::string::iterator n = res.freeform.begin(); n != res.freeform.end(); n++)\r             if (*n == '\7')\r                        *n = ' ';\r\r     return res;\r}\r\rvoid FilterBase::OnSyncOtherMetaData(Module* proto, void* opaque, bool displayable)\r{\r   this->SyncFilters(proto, opaque);\r}\r\rvoid FilterBase::SendFilter(Module* proto, void* opaque, FilterResult* iter)\r{\r    proto->ProtoSendMetaData(opaque, TYPE_OTHER, NULL, "filter", EncodeFilter(iter));\r}\r\rvoid FilterBase::OnDecodeMetaData(int target_type, void* target, const std::string &extname, const std::string &extdata)\r{\r        if ((target_type == TYPE_OTHER) && (extname == "filter"))\r      {\r              FilterResult data = DecodeFilter(extdata);\r             this->AddFilter(data.freeform, data.action, data.reason, data.gline_time, data.flags);\r }\r}\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "xline.h"
+
+enum FilterFlags
+{
+       FLAG_NOOPERS = 1,
+       FLAG_PART = 2,
+       FLAG_QUIT = 4,
+       FLAG_PRIVMSG = 8,
+       FLAG_NOTICE = 16
+};
+
+class FilterResult : public classbase
+{
+ public:
+       std::string freeform;
+       std::string reason;
+       std::string action;
+       long gline_time;
+       std::string flags;
+
+       bool flag_no_opers;
+       bool flag_part_message;
+       bool flag_quit_message;
+       bool flag_privmsg;
+       bool flag_notice;
+
+       FilterResult(const std::string free, const std::string &rea, const std::string &act, long gt, const std::string &fla) : freeform(free), reason(rea),
+                                                                       action(act), gline_time(gt), flags(fla)
+       {
+               this->FillFlags(flags);
+       }
+
+       int FillFlags(const std::string &fl)
+       {
+               flags = fl;
+               flag_no_opers = flag_part_message = flag_quit_message = flag_privmsg = flag_notice = false;
+               size_t x = 0;
+
+               for (std::string::const_iterator n = flags.begin(); n != flags.end(); ++n, ++x)
+               {
+                       switch (*n)
+                       {
+                               case 'o':
+                                       flag_no_opers = true;
+                               break;
+                               case 'P':
+                                       flag_part_message = true;
+                               break;
+                               case 'q':
+                                       flag_quit_message = true;
+                               break;
+                               case 'p':
+                                       flag_privmsg = true;
+                               break;
+                               case 'n':
+                                       flag_notice = true;
+                               break;
+                               case '*':
+                                       flag_no_opers = flag_part_message = flag_quit_message =
+                                               flag_privmsg = flag_notice = true;
+                               break;
+                               default:
+                                       return x;
+                               break;
+                       }
+               }
+               return 0;
+       }
+
+       FilterResult()
+       {
+       }
+
+       virtual ~FilterResult()
+       {
+       }
+};
+
+class cmd_filter;
+
+class FilterBase : public Module
+{
+       cmd_filter* filtcommand;
+       int flags;
+ public:
+       FilterBase(InspIRCd* Me, const std::string &source);
+       virtual ~FilterBase();
+       virtual void Implements(char* List);
+       virtual int OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list);
+       virtual FilterResult* FilterMatch(userrec* user, const std::string &text, int flags) = 0;
+       virtual bool DeleteFilter(const std::string &freeform) = 0;
+       virtual void SyncFilters(Module* proto, void* opaque) = 0;
+       virtual void SendFilter(Module* proto, void* opaque, FilterResult* iter);
+       virtual std::pair<bool, std::string> AddFilter(const std::string &freeform, const std::string &type, const std::string &reason, long duration, const std::string &flags) = 0;
+       virtual int OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list);
+       virtual void OnRehash(userrec* user, const std::string &parameter);
+       virtual Version GetVersion();
+       std::string EncodeFilter(FilterResult* filter);
+       FilterResult DecodeFilter(const std::string &data);
+       virtual void OnSyncOtherMetaData(Module* proto, void* opaque, bool displayable = false);
+       virtual void OnDecodeMetaData(int target_type, void* target, const std::string &extname, const std::string &extdata);
+       virtual int OnStats(char symbol, userrec* user, string_list &results) = 0;
+       virtual int OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line);
+       bool AppliesToMe(userrec* user, FilterResult* filter, int flags);
+};
+
+class cmd_filter : public command_t
+{
+       FilterBase* Base;
+ public:
+       cmd_filter(FilterBase* f, InspIRCd* Me, const std::string &source) : command_t(Me, "FILTER", 'o', 1), Base(f)
+       {
+               this->source = source;
+               this->syntax = "<filter-definition> <type> <flags> [<gline-duration>] :<reason>";
+       }
+
+       CmdResult Handle(const char** parameters, int pcnt, userrec *user)
+       {
+               if (pcnt == 1)
+               {
+                       /* Deleting a filter */
+                       if (Base->DeleteFilter(parameters[0]))
+                       {
+                               user->WriteServ("NOTICE %s :*** Deleted filter '%s'", user->nick, parameters[0]);
+                               return CMD_SUCCESS;
+                       }
+                       else
+                       {
+                               user->WriteServ("NOTICE %s :*** Filter '%s' not found on list.", user->nick, parameters[0]);
+                               return CMD_FAILURE;
+                       }
+               }
+               else
+               {
+                       /* Adding a filter */
+                       if (pcnt >= 4)
+                       {
+                               std::string freeform = parameters[0];
+                               std::string type = parameters[1];
+                               std::string flags = parameters[2];
+                               std::string reason;
+                               long duration = 0;
+
+
+                               if ((type != "gline") && (type != "none") && (type != "block") && (type != "kill") && (type != "silent"))
+                               {
+                                       user->WriteServ("NOTICE %s :*** Invalid filter type '%s'. Supported types are 'gline', 'none', 'block', 'silent' and 'kill'.", user->nick, freeform.c_str());
+                                       return CMD_FAILURE;
+                               }
+
+                               if (type == "gline")
+                               {
+                                       if (pcnt >= 5)
+                                       {
+                                               duration = ServerInstance->Duration(parameters[3]);
+                                               reason = parameters[4];
+                                       }
+                                       else
+                                       {
+                                               this->TooFewParams(user, " When setting a gline type filter, a gline duration must be specified as the third parameter.");
+                                               return CMD_FAILURE;
+                                       }
+                               }
+                               else
+                               {
+                                       reason = parameters[3];
+                               }
+                               std::pair<bool, std::string> result = Base->AddFilter(freeform, type, reason, duration, flags);
+                               if (result.first)
+                               {
+                                       user->WriteServ("NOTICE %s :*** Added filter '%s', type '%s'%s%s, flags '%s', reason: '%s'", user->nick, freeform.c_str(),
+                                                       type.c_str(), (duration ? " duration: " : ""), (duration ? parameters[3] : ""),
+                                                       flags.c_str(), reason.c_str());
+                                       return CMD_SUCCESS;
+                               }
+                               else
+                               {
+                                       user->WriteServ("NOTICE %s :*** Filter '%s' could not be added: %s", user->nick, freeform.c_str(), result.second.c_str());
+                                       return CMD_FAILURE;
+                               }
+                       }
+                       else
+                       {
+                               this->TooFewParams(user, ".");
+                               return CMD_FAILURE;
+                       }
+
+               }
+       }
+
+       void TooFewParams(userrec* user, const std::string &extra_text)
+       {
+               user->WriteServ("NOTICE %s :*** Not enough parameters%s", user->nick, extra_text.c_str());
+       }
+};
+
+bool FilterBase::AppliesToMe(userrec* user, FilterResult* filter, int flags)
+{
+       if ((flags & FLAG_NOOPERS) && (filter->flag_no_opers) && IS_OPER(user))
+               return false;
+       if ((flags & FLAG_PRIVMSG) && (!filter->flag_privmsg))
+               return false;
+       if ((flags & FLAG_NOTICE) && (!filter->flag_notice))
+               return false;
+       if ((flags & FLAG_QUIT)   && (!filter->flag_quit_message))
+               return false;
+       if ((flags & FLAG_PART)   && (!filter->flag_part_message))
+               return false;
+       return true;
+}
+
+FilterBase::FilterBase(InspIRCd* Me, const std::string &source) : Module(Me)
+{
+       filtcommand = new cmd_filter(this, Me, source);
+       ServerInstance->AddCommand(filtcommand);
+}
+
+FilterBase::~FilterBase()
+{
+}
+
+void FilterBase::Implements(char* List)
+{
+       List[I_OnPreCommand] = List[I_OnStats] = List[I_OnSyncOtherMetaData] = List[I_OnDecodeMetaData] = List[I_OnUserPreMessage] = List[I_OnUserPreNotice] = List[I_OnRehash] = 1;
+}
+
+int FilterBase::OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
+{
+       flags = FLAG_PRIVMSG;
+       return OnUserPreNotice(user,dest,target_type,text,status,exempt_list);
+}
+
+int FilterBase::OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
+{
+       if (!flags)
+               flags = FLAG_NOTICE;
+
+       /* Leave ulines alone */
+       if ((ServerInstance->ULine(user->server)) || (!IS_LOCAL(user)))
+               return 0;
+
+       FilterResult* f = this->FilterMatch(user, text, flags);
+       if (f)
+       {
+               std::string target = "";
+               if (target_type == TYPE_USER)
+               {
+                       userrec* t = (userrec*)dest;
+                       target = std::string(t->nick);
+               }
+               else if (target_type == TYPE_CHANNEL)
+               {
+                       chanrec* t = (chanrec*)dest;
+                       target = std::string(t->name);
+               }
+               if (f->action == "block")
+               {       
+                       ServerInstance->WriteOpers(std::string("FILTER: ")+user->nick+" had their message filtered, target was "+target+": "+f->reason);
+                       user->WriteServ("NOTICE "+std::string(user->nick)+" :Your message has been filtered and opers notified: "+f->reason);
+               }
+               if (f->action == "silent")
+               {
+                       user->WriteServ("NOTICE "+std::string(user->nick)+" :Your message has been filtered: "+f->reason);
+               }
+               if (f->action == "kill")
+               {
+                       userrec::QuitUser(ServerInstance,user,"Filtered: "+f->reason);
+               }
+               if (f->action == "gline")
+               {
+                       if (ServerInstance->XLines->add_gline(f->gline_time, ServerInstance->Config->ServerName, f->reason.c_str(), user->MakeHostIP()))
+                       {
+                               ServerInstance->XLines->apply_lines(APPLY_GLINES);
+                               FOREACH_MOD(I_OnAddGLine,OnAddGLine(f->gline_time, NULL, f->reason, user->MakeHostIP()));
+                       }
+               }
+
+               ServerInstance->Log(DEFAULT,"FILTER: "+std::string(user->nick)+std::string(" had their message filtered, target was ")+target+": "+f->reason+" Action: "+f->action);
+               return 1;
+       }
+       return 0;
+}
+
+int FilterBase::OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line)
+{
+       flags = 0;
+       if ((validated == 1) && (IS_LOCAL(user)))
+       {
+               std::string checkline;
+               int replacepoint = 0;
+               bool parting = false;
+       
+               if (command == "QUIT")
+               {
+                       /* QUIT with no reason: nothing to do */
+                       if (pcnt < 1)
+                               return 0;
+
+                       checkline = parameters[0];
+                       replacepoint = 0;
+                       parting = false;
+                       flags = FLAG_QUIT;
+               }
+               else if (command == "PART")
+               {
+                       /* PART with no reason: nothing to do */
+                       if (pcnt < 2)
+                               return 0;
+
+                       checkline = parameters[1];
+                       replacepoint = 1;
+                       parting = true;
+                       flags = FLAG_PART;
+               }
+               else
+                       /* We're only messing with PART and QUIT */
+                       return 0;
+
+               FilterResult* f = NULL;
+               
+               if (flags)
+                       f = this->FilterMatch(user, checkline, flags);
+
+               if (!f)
+                       /* PART or QUIT reason doesnt match a filter */
+                       return 0;
+
+               /* We cant block a part or quit, so instead we change the reason to 'Reason filtered' */
+               command_t* c = ServerInstance->Parser->GetHandler(command);
+               if (c)
+               {
+                       const char* params[127];
+                       for (int item = 0; item < pcnt; item++)
+                               params[item] = parameters[item];
+                       params[replacepoint] = "Reason filtered";
+
+                       /* We're blocking, OR theyre quitting and its a KILL action
+                        * (we cant kill someone whos already quitting, so filter them anyway)
+                        */
+                       if ((f->action == "block") || (((!parting) && (f->action == "kill"))) || (f->action == "silent"))
+                       {
+                               c->Handle(params, pcnt, user);
+                               return 1;
+                       }
+                       else
+                       {
+                               /* Are they parting, if so, kill is applicable */
+                               if ((parting) && (f->action == "kill"))
+                               {
+                                       user->SetWriteError("Filtered: "+f->reason);
+                                       /* This WriteServ causes the write error to be applied.
+                                        * Its not safe to kill here with QuitUser in a PreCommand handler,
+                                        * so we do it this way, which is safe just about anywhere.
+                                        */
+                                       user->WriteServ("NOTICE %s :*** Your PART message was filtered: %s", user->nick, f->reason.c_str());
+                               }
+                               if (f->action == "gline")
+                               {
+                                       /* Note: We gline *@IP so that if their host doesnt resolve the gline still applies. */
+                                       std::string wild = "*@";
+                                       wild.append(user->GetIPString());
+
+                                       if (ServerInstance->XLines->add_gline(f->gline_time, ServerInstance->Config->ServerName, f->reason.c_str(), wild.c_str()))
+                                       {
+                                               ServerInstance->XLines->apply_lines(APPLY_GLINES);
+                                               FOREACH_MOD(I_OnAddGLine,OnAddGLine(f->gline_time, NULL, f->reason, user->MakeHostIP()));
+                                       }
+                               }
+                               return 1;
+                       }
+               }
+               return 0;
+       }
+       return 0;
+}
+
+void FilterBase::OnRehash(userrec* user, const std::string &parameter)
+{
+}
+       
+Version FilterBase::GetVersion()
+{
+       return Version(1,1,0,2,VF_VENDOR|VF_COMMON,API_VERSION);
+}
+
+
+std::string FilterBase::EncodeFilter(FilterResult* filter)
+{
+       std::ostringstream stream;
+       std::string x = filter->freeform;
+
+       /* Hax to allow spaces in the freeform without changing the design of the irc protocol */
+       for (std::string::iterator n = x.begin(); n != x.end(); n++)
+               if (*n == ' ')
+                       *n = '\7';
+
+       stream << x << " " << filter->action << " " << (filter->flags.empty() ? "-" : filter->flags) << " " << filter->gline_time << " :" << filter->reason;
+       return stream.str();
+}
+
+FilterResult FilterBase::DecodeFilter(const std::string &data)
+{
+       FilterResult res;
+       irc::tokenstream tokens(data);
+       tokens.GetToken(res.freeform);
+       tokens.GetToken(res.action);
+       tokens.GetToken(res.flags);
+       if (res.flags == "-")
+               res.flags = "";
+       res.FillFlags(res.flags);
+       tokens.GetToken(res.gline_time);
+       tokens.GetToken(res.reason);
+
+       /* Hax to allow spaces in the freeform without changing the design of the irc protocol */
+       for (std::string::iterator n = res.freeform.begin(); n != res.freeform.end(); n++)
+               if (*n == '\7')
+                       *n = ' ';
+
+       return res;
+}
+
+void FilterBase::OnSyncOtherMetaData(Module* proto, void* opaque, bool displayable)
+{
+       this->SyncFilters(proto, opaque);
+}
+
+void FilterBase::SendFilter(Module* proto, void* opaque, FilterResult* iter)
+{
+       proto->ProtoSendMetaData(opaque, TYPE_OTHER, NULL, "filter", EncodeFilter(iter));
+}
+
+void FilterBase::OnDecodeMetaData(int target_type, void* target, const std::string &extname, const std::string &extdata)
+{
+       if ((target_type == TYPE_OTHER) && (extname == "filter"))
+       {
+               FilterResult data = DecodeFilter(extdata);
+               this->AddFilter(data.freeform, data.action, data.reason, data.gline_time, data.flags);
+       }
+}
+
index 857f4d16d5a834ea94037d4332670da0bf9eccf4..7de305923b0ec9883457c9e43302f63dc11dca51 100644 (file)
@@ -1 +1,98 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r\r/* $ModDesc: A dummy module for testing */\r\r// Class ModuleFoobar inherits from Module\r// It just outputs simple debug strings to show its methods are working.\r\rclass ModuleFoobar : public Module\r{\r private:\r       \r       // It is recommended that your class makes use of one or more Server\r   // objects. A server object is a class which contains methods which\r    // encapsulate the exports from the core of the ircd.\r  // such methods include Debug, SendChannel, etc.\r \r     \r public:\r     ModuleFoobar(InspIRCd* Me)\r             : Module(Me)\r   {\r              // The constructor just makes a copy of the server class\r       \r               \r       }\r      \r       virtual ~ModuleFoobar()\r        {\r      }\r      \r       virtual Version GetVersion()\r   {\r              // this method instantiates a class of type Version, and returns\r               // the modules version information using it.\r   \r               return Version(1,1,0,1,VF_VENDOR,API_VERSION);\r }\r\r     void Implements(char* List)\r    {\r              List[I_OnUserConnect] = List[I_OnUserQuit] = List[I_OnUserJoin] = List[I_OnUserPart] = 1;\r      }\r      \r       virtual void OnUserConnect(userrec* user)\r      {\r              // method called when a user connects\r  \r               std::string b = user->nick;\r            ServerInstance->Log(DEBUG,"Foobar: User connecting: "+b);\r      }\r\r     virtual void OnUserQuit(userrec* user, const std::string &reason, const std::string &oper_message)\r     {\r              // method called when a user disconnects\r       \r               std::string b = user->nick;\r            ServerInstance->Log(DEBUG,"Foobar: User quitting: "+b);\r        }\r      \r       virtual void OnUserJoin(userrec* user, chanrec* channel, bool &silent)\r {\r              // method called when a user joins a channel\r   \r               std::string c = channel->name;\r         std::string b = user->nick;\r            ServerInstance->Log(DEBUG,"Foobar: User "+b+" joined "+c);\r     }\r\r     virtual void OnUserPart(userrec* user, chanrec* channel, const std::string &partreason, bool &silent)\r  {\r              // method called when a user parts a channel\r   \r               std::string c = channel->name;\r         std::string b = user->nick;\r            ServerInstance->Log(DEBUG,"Foobar: User "+b+" parted "+c);\r     }\r\r};\r\r\rMODULE_INIT(ModuleFoobar)\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+
+/* $ModDesc: A dummy module for testing */
+
+// Class ModuleFoobar inherits from Module
+// It just outputs simple debug strings to show its methods are working.
+
+class ModuleFoobar : public Module
+{
+ private:
+        
+        // It is recommended that your class makes use of one or more Server
+        // objects. A server object is a class which contains methods which
+        // encapsulate the exports from the core of the ircd.
+        // such methods include Debug, SendChannel, etc.
+        
+ public:
+       ModuleFoobar(InspIRCd* Me)
+               : Module(Me)
+       {
+               // The constructor just makes a copy of the server class
+       
+               
+       }
+       
+       virtual ~ModuleFoobar()
+       {
+       }
+       
+       virtual Version GetVersion()
+       {
+               // this method instantiates a class of type Version, and returns
+               // the modules version information using it.
+       
+               return Version(1,1,0,1,VF_VENDOR,API_VERSION);
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnUserConnect] = List[I_OnUserQuit] = List[I_OnUserJoin] = List[I_OnUserPart] = 1;
+       }
+       
+       virtual void OnUserConnect(userrec* user)
+       {
+               // method called when a user connects
+       
+               std::string b = user->nick;
+               ServerInstance->Log(DEBUG,"Foobar: User connecting: "+b);
+       }
+
+       virtual void OnUserQuit(userrec* user, const std::string &reason, const std::string &oper_message)
+       {
+               // method called when a user disconnects
+       
+               std::string b = user->nick;
+               ServerInstance->Log(DEBUG,"Foobar: User quitting: "+b);
+       }
+       
+       virtual void OnUserJoin(userrec* user, chanrec* channel, bool &silent)
+       {
+               // method called when a user joins a channel
+       
+               std::string c = channel->name;
+               std::string b = user->nick;
+               ServerInstance->Log(DEBUG,"Foobar: User "+b+" joined "+c);
+       }
+
+       virtual void OnUserPart(userrec* user, chanrec* channel, const std::string &partreason, bool &silent)
+       {
+               // method called when a user parts a channel
+       
+               std::string c = channel->name;
+               std::string b = user->nick;
+               ServerInstance->Log(DEBUG,"Foobar: User "+b+" parted "+c);
+       }
+
+};
+
+
+MODULE_INIT(ModuleFoobar)
+
index 4f3438e0594d57f01eb631404b71f685d55bd873..ae87451ba0a95cd88e87f453654ed44b6ede9156 100644 (file)
@@ -1 +1,141 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r/* $ModDesc: Allows global loading of a module. */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r\r/** Handle /GLOADMODULE\r */\rclass cmd_gloadmodule : public command_t\r{\r public:\r  cmd_gloadmodule (InspIRCd* Instance) : command_t(Instance,"GLOADMODULE", 'o', 1)\r       {\r              this->source = "m_globalload.so";\r              syntax = "<modulename>";\r       }\r\r     CmdResult Handle (const char** parameters, int pcnt, userrec *user)\r    {\r              if (ServerInstance->LoadModule(parameters[0]))\r         {\r                      ServerInstance->WriteOpers("*** NEW MODULE '%s' GLOBALLY LOADED BY '%s'",parameters[0],user->nick);\r                    user->WriteServ("975 %s %s :Module successfully loaded.",user->nick, parameters[0]);\r\r                  /* route it! */\r                        return CMD_SUCCESS;\r            }\r              else\r           {\r                      user->WriteServ("974 %s %s :Failed to load module: %s",user->nick, parameters[0],ServerInstance->ModuleError());\r                       /* XXX - returning CMD_FAILURE here could potentially mean half the net loads it, half doesn't. pass it on anyway? -- w00t\r                      *\r                      * Returning CMD_SUCCESS would have the same effect, just with less servers. Someone should update this module to properly\r                      * pass the success/failure for each server to the caller (or to all opers) -Special */\r                        return CMD_FAILURE;\r            }\r      }\r};\r\r/** Handle /GUNLOADMODULE\r */\rclass cmd_gunloadmodule : public command_t\r{\r public:\r      cmd_gunloadmodule (InspIRCd* Instance) : command_t(Instance,"GUNLOADMODULE", 'o', 1)\r   {\r              this->source = "m_globalload.so";\r              syntax = "<modulename>";\r       }\r\r     CmdResult Handle (const char** parameters, int pcnt, userrec *user)\r    {\r              if (ServerInstance->UnloadModule(parameters[0]))\r               {\r                      ServerInstance->WriteOpers("*** MODULE '%s' GLOBALLY UNLOADED BY '%s'",parameters[0],user->nick);\r                      user->WriteServ("973 %s %s :Module successfully unloaded.",user->nick, parameters[0]);\r         }\r              else\r           {\r                      /* Return CMD_SUCCESS so the module will be unloaded on any servers it is loaded on - this is a seperate case entirely from loading -Special */\r                        user->WriteServ("972 %s %s :Failed to unload module: %s",user->nick, parameters[0],ServerInstance->ModuleError());\r             }\r              return CMD_SUCCESS;\r    }\r};\r\r/** Handle /GRELOADMODULE\r */\rclass cmd_greloadmodule : public command_t\r{\r public:\r      cmd_greloadmodule (InspIRCd* Instance) : command_t(Instance, "GRELOADMODULE", 'o', 1)\r  {\r              this->source = "m_globalload.so";\r              syntax = "<modulename>";\r       }\r\r     CmdResult Handle(const char** parameters, int pcnt, userrec *user)\r     {\r              if (!ServerInstance->UnloadModule(parameters[0]))\r              {\r                      user->WriteServ("972 %s %s :Failed to unload module: %s",user->nick, parameters[0],ServerInstance->ModuleError());\r                     return CMD_FAILURE;\r            }\r\r             if (!ServerInstance->LoadModule(parameters[0]))\r                {\r                      user->WriteServ("974 %s %s :Failed to load module: %s",user->nick, parameters[0],ServerInstance->ModuleError());\r                       return CMD_FAILURE;\r            }\r\r             ServerInstance->WriteOpers("*** MODULE '%s' GLOBALLY RELOADED BY '%s'",parameters[0],user->nick);\r              user->WriteServ("975 %s %s :Module successfully loaded.",user->nick, parameters[0]);\r           \r               return CMD_SUCCESS;\r    }\r};\r\rclass ModuleGlobalLoad : public Module\r{\r cmd_gloadmodule *mycommand;\r    cmd_gunloadmodule *mycommand2;\r cmd_greloadmodule *mycommand3;\r \r public:\r      ModuleGlobalLoad(InspIRCd* Me) : Module(Me)\r    {\r              \r               mycommand = new cmd_gloadmodule(ServerInstance);\r               mycommand2 = new cmd_gunloadmodule(ServerInstance);\r            mycommand3 = new cmd_greloadmodule(ServerInstance);\r            ServerInstance->AddCommand(mycommand);\r         ServerInstance->AddCommand(mycommand2);\r                ServerInstance->AddCommand(mycommand3);\r        }\r      \r       virtual ~ModuleGlobalLoad()\r    {\r      }\r      \r       virtual Version GetVersion()\r   {\r              return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION);\r    }\r};\r\rMODULE_INIT(ModuleGlobalLoad)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+/* $ModDesc: Allows global loading of a module. */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+
+/** Handle /GLOADMODULE
+ */
+class cmd_gloadmodule : public command_t
+{
+ public:
+       cmd_gloadmodule (InspIRCd* Instance) : command_t(Instance,"GLOADMODULE", 'o', 1)
+       {
+               this->source = "m_globalload.so";
+               syntax = "<modulename>";
+       }
+
+       CmdResult Handle (const char** parameters, int pcnt, userrec *user)
+       {
+               if (ServerInstance->LoadModule(parameters[0]))
+               {
+                       ServerInstance->WriteOpers("*** NEW MODULE '%s' GLOBALLY LOADED BY '%s'",parameters[0],user->nick);
+                       user->WriteServ("975 %s %s :Module successfully loaded.",user->nick, parameters[0]);
+
+                       /* route it! */
+                       return CMD_SUCCESS;
+               }
+               else
+               {
+                       user->WriteServ("974 %s %s :Failed to load module: %s",user->nick, parameters[0],ServerInstance->ModuleError());
+                       /* XXX - returning CMD_FAILURE here could potentially mean half the net loads it, half doesn't. pass it on anyway? -- w00t
+                        *
+                        * Returning CMD_SUCCESS would have the same effect, just with less servers. Someone should update this module to properly
+                        * pass the success/failure for each server to the caller (or to all opers) -Special */
+                       return CMD_FAILURE;
+               }
+       }
+};
+
+/** Handle /GUNLOADMODULE
+ */
+class cmd_gunloadmodule : public command_t
+{
+ public:
+       cmd_gunloadmodule (InspIRCd* Instance) : command_t(Instance,"GUNLOADMODULE", 'o', 1)
+       {
+               this->source = "m_globalload.so";
+               syntax = "<modulename>";
+       }
+
+       CmdResult Handle (const char** parameters, int pcnt, userrec *user)
+       {
+               if (ServerInstance->UnloadModule(parameters[0]))
+               {
+                       ServerInstance->WriteOpers("*** MODULE '%s' GLOBALLY UNLOADED BY '%s'",parameters[0],user->nick);
+                       user->WriteServ("973 %s %s :Module successfully unloaded.",user->nick, parameters[0]);
+               }
+               else
+               {
+                       /* Return CMD_SUCCESS so the module will be unloaded on any servers it is loaded on - this is a seperate case entirely from loading -Special */
+                       user->WriteServ("972 %s %s :Failed to unload module: %s",user->nick, parameters[0],ServerInstance->ModuleError());
+               }
+               return CMD_SUCCESS;
+       }
+};
+
+/** Handle /GRELOADMODULE
+ */
+class cmd_greloadmodule : public command_t
+{
+ public:
+       cmd_greloadmodule (InspIRCd* Instance) : command_t(Instance, "GRELOADMODULE", 'o', 1)
+       {
+               this->source = "m_globalload.so";
+               syntax = "<modulename>";
+       }
+
+       CmdResult Handle(const char** parameters, int pcnt, userrec *user)
+       {
+               if (!ServerInstance->UnloadModule(parameters[0]))
+               {
+                       user->WriteServ("972 %s %s :Failed to unload module: %s",user->nick, parameters[0],ServerInstance->ModuleError());
+                       return CMD_FAILURE;
+               }
+
+               if (!ServerInstance->LoadModule(parameters[0]))
+               {
+                       user->WriteServ("974 %s %s :Failed to load module: %s",user->nick, parameters[0],ServerInstance->ModuleError());
+                       return CMD_FAILURE;
+               }
+
+               ServerInstance->WriteOpers("*** MODULE '%s' GLOBALLY RELOADED BY '%s'",parameters[0],user->nick);
+               user->WriteServ("975 %s %s :Module successfully loaded.",user->nick, parameters[0]);
+               
+               return CMD_SUCCESS;
+       }
+};
+
+class ModuleGlobalLoad : public Module
+{
+       cmd_gloadmodule *mycommand;
+       cmd_gunloadmodule *mycommand2;
+       cmd_greloadmodule *mycommand3;
+       
+ public:
+       ModuleGlobalLoad(InspIRCd* Me) : Module(Me)
+       {
+               
+               mycommand = new cmd_gloadmodule(ServerInstance);
+               mycommand2 = new cmd_gunloadmodule(ServerInstance);
+               mycommand3 = new cmd_greloadmodule(ServerInstance);
+               ServerInstance->AddCommand(mycommand);
+               ServerInstance->AddCommand(mycommand2);
+               ServerInstance->AddCommand(mycommand3);
+       }
+       
+       virtual ~ModuleGlobalLoad()
+       {
+       }
+       
+       virtual Version GetVersion()
+       {
+               return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION);
+       }
+};
+
+MODULE_INIT(ModuleGlobalLoad)
index 5745cc9c6d38bc68ec487a6601c7509886ca2619..1a49858e2e009276f64101b5ac3c8268adb3db4d 100644 (file)
@@ -1 +1,76 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r// Globops and +g support module by C.J.Edwards\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r\r/* $ModDesc: Provides support for GLOBOPS and user mode +g */\r\r/** Handle /GLOBOPS\r */\rclass cmd_globops : public command_t\r{\r public:\r      cmd_globops (InspIRCd* Instance) : command_t(Instance,"GLOBOPS",'o',1)\r {\r              this->source = "m_globops.so";\r         syntax = "<any-text>";\r }\r\r     CmdResult Handle (const char** parameters, int pcnt, userrec *user)\r    {\r              std::string line = "From " + std::string(user->nick) + ": ";\r           for (int i = 0; i < pcnt; i++)\r         {\r                      line = line + std::string(parameters[i]) + " ";\r                }\r              ServerInstance->SNO->WriteToSnoMask('g',line);\r\r                /* route it (ofc :p) */\r                return CMD_SUCCESS;\r    }\r};\r\rclass ModuleGlobops : public Module\r{\r    cmd_globops* mycommand;\r public:\r       ModuleGlobops(InspIRCd* Me)\r            : Module(Me)\r   {\r              mycommand = new cmd_globops(ServerInstance);\r           ServerInstance->AddCommand(mycommand);\r         ServerInstance->SNO->EnableSnomask('g',"GLOBOPS");\r     }\r      \r       virtual ~ModuleGlobops()\r       {\r              ServerInstance->SNO->DisableSnomask('g');\r              DELETE(mycommand);\r     }\r      \r       virtual Version GetVersion()\r   {\r              return Version(1, 1, 0, 1, VF_COMMON | VF_VENDOR, API_VERSION);\r        }\r\r     void Implements(char* List)\r    {\r      }\r};\r\rMODULE_INIT(ModuleGlobops)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+// Globops and +g support module by C.J.Edwards
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+
+/* $ModDesc: Provides support for GLOBOPS and user mode +g */
+
+/** Handle /GLOBOPS
+ */
+class cmd_globops : public command_t
+{
+ public:
+       cmd_globops (InspIRCd* Instance) : command_t(Instance,"GLOBOPS",'o',1)
+       {
+               this->source = "m_globops.so";
+               syntax = "<any-text>";
+       }
+
+       CmdResult Handle (const char** parameters, int pcnt, userrec *user)
+       {
+               std::string line = "From " + std::string(user->nick) + ": ";
+               for (int i = 0; i < pcnt; i++)
+               {
+                       line = line + std::string(parameters[i]) + " ";
+               }
+               ServerInstance->SNO->WriteToSnoMask('g',line);
+
+               /* route it (ofc :p) */
+               return CMD_SUCCESS;
+       }
+};
+
+class ModuleGlobops : public Module
+{
+       cmd_globops* mycommand;
+ public:
+       ModuleGlobops(InspIRCd* Me)
+               : Module(Me)
+       {
+               mycommand = new cmd_globops(ServerInstance);
+               ServerInstance->AddCommand(mycommand);
+               ServerInstance->SNO->EnableSnomask('g',"GLOBOPS");
+       }
+       
+       virtual ~ModuleGlobops()
+       {
+               ServerInstance->SNO->DisableSnomask('g');
+               DELETE(mycommand);
+       }
+       
+       virtual Version GetVersion()
+       {
+               return Version(1, 1, 0, 1, VF_COMMON | VF_VENDOR, API_VERSION);
+       }
+
+       void Implements(char* List)
+       {
+       }
+};
+
+MODULE_INIT(ModuleGlobops)
index d82104cdb97b8b1527f16e76cd2ab3228ec6643a..ee9ead21cc92fe91e063f953fa9f9b862b8fe79c 100644 (file)
@@ -1 +1,196 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __HASH_H__\r#define __HASH_H__\r\r#include "modules.h"\r\r#define SHA256_DIGEST_SIZE (256 / 8)\r#define SHA256_BLOCK_SIZE  (512 / 8)\r\r/** HashRequest is the base class used to send Hash requests to hashing.so.\r * You should not instantiate classes of type HashRequest directly, instead\r * you should instantiate classes of type HashResetRequest, HashSumRequest,\r * HashKeyRequest and HashHexRequest, shown below.\r */\rclass HashRequest : public Request\r{\r   /** The keys (IV) to use */\r    unsigned int* keys;\r    /** The output characters (hex sequence) to use */\r     const char* outputs;\r   /** The string to hash */\r      std::string tohash;\r public:\r   /** Initialize HashRequest as an Hash_RESET message */\r HashRequest(const char* req, Module* Me, Module* Target) : Request(Me, Target, req)\r    {\r      }\r\r     /** Initialize HashRequest as an Hash_SUM message */\r   HashRequest(Module* Me, Module* Target, const std::string &hashable) : Request(Me, Target, "SUM"), keys(NULL), outputs(NULL), tohash(hashable)\r {\r      }\r\r     /** Initialize HashRequest as an Hash_KEY message */\r   HashRequest(Module* Me, Module* Target, unsigned int* k) : Request(Me, Target, "KEY"), keys(k), outputs(NULL), tohash("")\r      {\r      }\r\r     /** Initialize HashRequest as an Hash_HEX message */\r   HashRequest(Module* Me, Module* Target, const char* out) : Request(Me, Target, "HEX"), keys(NULL), outputs(out), tohash("")\r    {\r      }\r\r     /** Get data to be hashed */\r   const char* GetHashData()\r      {\r              return tohash.c_str();\r }\r\r     /** Get keys (IVs) to be used */\r       unsigned int* GetKeyData()\r     {\r              return keys;\r   }\r\r     /** Get output characters (hex sequence) to be used */\r const char* GetOutputs()\r       {\r              return outputs;\r        }\r};\r\r/** Send this class to the hashing module to query for its name.\r *\r * Example:\r * \code\r * cout << "Using hash algorithm: " << HashNameRequest(this, HashModule).Send();\r * \endcode\r */\rclass HashNameRequest : public HashRequest\r{\r public:\r  /** Initialize HashNameRequest for sending.\r     * @param Me A pointer to the sending module\r    * @param Target A pointer to the hashing module\r        */\r    HashNameRequest(Module* Me, Module* Target) : HashRequest("NAME", Me, Target)\r  {\r      }\r};\r\r/** Send this class to the hashing module to reset the Hash module to a known state.\r * This will reset the IV to the defaults specified by the Hash spec,\r * and reset the hex sequence to "0123456789abcdef". It should be sent before\r * ANY other Request types.\r *\r * Example:\r * \code\r * // Reset the Hash module.\r * HashResetRequest(this, HashModule).Send();\r * \endcode\r */\rclass HashResetRequest : public HashRequest\r{\r public:\r   /** Initialize HashResetRequest for sending.\r    * @param Me A pointer to the sending module\r    * @param Target A pointer to the hashing module\r        */\r    HashResetRequest(Module* Me, Module* Target) : HashRequest("RESET", Me, Target)\r        {\r      }\r};\r\r/** Send this class to the hashing module to HashSUM a std::string.\r * You should make sure you know the state of the module before you send this\r * class, e.g. by first sending an HashResetRequest class. The hash will be\r * returned when you call Send().\r *\r * Example:\r * \code\r * // ALWAYS ALWAYS reset first, or set your own IV and hex chars.\r * HashResetRequest(this, HashModule).Send();\r * // Get the Hash sum of the string 'doodads'.\r * std::string result = HashSumRequest(this, HashModule, "doodads").Send();\r * \endcode\r */\rclass HashSumRequest : public HashRequest\r{\r public:\r        /** Initialize HashSumRequest for sending.\r      * @param Me A pointer to the sending module\r    * @param Target A pointer to the hashing module\r        * @param data The data to be hashed\r    */\r    HashSumRequest(Module* Me, Module* Target, const std::string &data) : HashRequest(Me, Target, data)\r    {\r      }\r};\r\r/** Send this class to hashing module to change the IVs (keys) to use for hashing.\r * You should make sure you know the state of the module before you send this\r * class, e.g. by first sending an HashResetRequest class. The default values for\r * the IV's are those specified in the Hash specification. Only in very special\r * circumstances should you need to change the IV's (see for example m_cloaking.cpp)\r *\r * Example:\r * \code\r * unsigned int iv[] = { 0xFFFFFFFF, 0x00000000, 0xAAAAAAAA, 0xCCCCCCCC };\r * HashKeyRequest(this, HashModule, iv);\r * \endcode\r */\rclass HashKeyRequest : public HashRequest\r{\r public:\r /** Initialize HashKeyRequest for sending.\r      * @param Me A pointer to the sending module\r    * @param Target A pointer to the hashing module\r        * @param data The new IV's. This should be an array of exactly four 32 bit values.\r     * On 64-bit architectures, the upper 32 bits of the values will be discarded.\r  */\r    HashKeyRequest(Module* Me, Module* Target, unsigned int* data) : HashRequest(Me, Target, data)\r {\r      }\r};\r\r/** Send this class to the hashing module to change the hex sequence to use for generating the returned value.\r * You should make sure you know the state of the module before you send this\r * class, e.g. by first sending an HashResetRequest class. The default value for\r * the hex sequence is "0123456789abcdef". Only in very special circumstances should\r * you need to change the hex sequence (see for example m_cloaking.cpp).\r *\r * Example:\r * \code\r * static const char tab[] = "fedcba9876543210";\r * HashHexRequest(this, HashModule, tab);\r * \endcode\r */\rclass HashHexRequest : public HashRequest\r{\r public:\r      /** Initialize HashHexRequest for sending.\r      * @param Me A pointer to the sending module\r    * @param Target A pointer to the hashing module\r        * @param data The hex sequence to use. This should contain exactly 16 ASCII characters,\r        * terminated by a NULL char.\r   */\r    HashHexRequest(Module* Me, Module* Target, const char* data) : HashRequest(Me, Target, data)\r   {\r      }\r};\r\r#endif\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __HASH_H__
+#define __HASH_H__
+
+#include "modules.h"
+
+#define SHA256_DIGEST_SIZE (256 / 8)
+#define SHA256_BLOCK_SIZE  (512 / 8)
+
+/** HashRequest is the base class used to send Hash requests to hashing.so.
+ * You should not instantiate classes of type HashRequest directly, instead
+ * you should instantiate classes of type HashResetRequest, HashSumRequest,
+ * HashKeyRequest and HashHexRequest, shown below.
+ */
+class HashRequest : public Request
+{
+       /** The keys (IV) to use */
+       unsigned int* keys;
+       /** The output characters (hex sequence) to use */
+       const char* outputs;
+       /** The string to hash */
+       std::string tohash;
+ public:
+       /** Initialize HashRequest as an Hash_RESET message */
+       HashRequest(const char* req, Module* Me, Module* Target) : Request(Me, Target, req)
+       {
+       }
+
+       /** Initialize HashRequest as an Hash_SUM message */
+       HashRequest(Module* Me, Module* Target, const std::string &hashable) : Request(Me, Target, "SUM"), keys(NULL), outputs(NULL), tohash(hashable)
+       {
+       }
+
+       /** Initialize HashRequest as an Hash_KEY message */
+       HashRequest(Module* Me, Module* Target, unsigned int* k) : Request(Me, Target, "KEY"), keys(k), outputs(NULL), tohash("")
+       {
+       }
+
+       /** Initialize HashRequest as an Hash_HEX message */
+       HashRequest(Module* Me, Module* Target, const char* out) : Request(Me, Target, "HEX"), keys(NULL), outputs(out), tohash("")
+       {
+       }
+
+       /** Get data to be hashed */
+       const char* GetHashData()
+       {
+               return tohash.c_str();
+       }
+
+       /** Get keys (IVs) to be used */
+       unsigned int* GetKeyData()
+       {
+               return keys;
+       }
+
+       /** Get output characters (hex sequence) to be used */
+       const char* GetOutputs()
+       {
+               return outputs;
+       }
+};
+
+/** Send this class to the hashing module to query for its name.
+ *
+ * Example:
+ * \code
+ * cout << "Using hash algorithm: " << HashNameRequest(this, HashModule).Send();
+ * \endcode
+ */
+class HashNameRequest : public HashRequest
+{
+ public:
+       /** Initialize HashNameRequest for sending.
+        * @param Me A pointer to the sending module
+        * @param Target A pointer to the hashing module
+        */
+       HashNameRequest(Module* Me, Module* Target) : HashRequest("NAME", Me, Target)
+       {
+       }
+};
+
+/** Send this class to the hashing module to reset the Hash module to a known state.
+ * This will reset the IV to the defaults specified by the Hash spec,
+ * and reset the hex sequence to "0123456789abcdef". It should be sent before
+ * ANY other Request types.
+ *
+ * Example:
+ * \code
+ * // Reset the Hash module.
+ * HashResetRequest(this, HashModule).Send();
+ * \endcode
+ */
+class HashResetRequest : public HashRequest
+{
+ public:
+       /** Initialize HashResetRequest for sending.
+        * @param Me A pointer to the sending module
+        * @param Target A pointer to the hashing module
+        */
+       HashResetRequest(Module* Me, Module* Target) : HashRequest("RESET", Me, Target)
+       {
+       }
+};
+
+/** Send this class to the hashing module to HashSUM a std::string.
+ * You should make sure you know the state of the module before you send this
+ * class, e.g. by first sending an HashResetRequest class. The hash will be
+ * returned when you call Send().
+ *
+ * Example:
+ * \code
+ * // ALWAYS ALWAYS reset first, or set your own IV and hex chars.
+ * HashResetRequest(this, HashModule).Send();
+ * // Get the Hash sum of the string 'doodads'.
+ * std::string result = HashSumRequest(this, HashModule, "doodads").Send();
+ * \endcode
+ */
+class HashSumRequest : public HashRequest
+{
+ public:
+       /** Initialize HashSumRequest for sending.
+        * @param Me A pointer to the sending module
+        * @param Target A pointer to the hashing module
+        * @param data The data to be hashed
+        */
+       HashSumRequest(Module* Me, Module* Target, const std::string &data) : HashRequest(Me, Target, data)
+       {
+       }
+};
+
+/** Send this class to hashing module to change the IVs (keys) to use for hashing.
+ * You should make sure you know the state of the module before you send this
+ * class, e.g. by first sending an HashResetRequest class. The default values for
+ * the IV's are those specified in the Hash specification. Only in very special
+ * circumstances should you need to change the IV's (see for example m_cloaking.cpp)
+ *
+ * Example:
+ * \code
+ * unsigned int iv[] = { 0xFFFFFFFF, 0x00000000, 0xAAAAAAAA, 0xCCCCCCCC };
+ * HashKeyRequest(this, HashModule, iv);
+ * \endcode
+ */
+class HashKeyRequest : public HashRequest
+{
+ public:
+       /** Initialize HashKeyRequest for sending.
+        * @param Me A pointer to the sending module
+        * @param Target A pointer to the hashing module
+        * @param data The new IV's. This should be an array of exactly four 32 bit values.
+        * On 64-bit architectures, the upper 32 bits of the values will be discarded.
+        */
+       HashKeyRequest(Module* Me, Module* Target, unsigned int* data) : HashRequest(Me, Target, data)
+       {
+       }
+};
+
+/** Send this class to the hashing module to change the hex sequence to use for generating the returned value.
+ * You should make sure you know the state of the module before you send this
+ * class, e.g. by first sending an HashResetRequest class. The default value for
+ * the hex sequence is "0123456789abcdef". Only in very special circumstances should
+ * you need to change the hex sequence (see for example m_cloaking.cpp).
+ *
+ * Example:
+ * \code
+ * static const char tab[] = "fedcba9876543210";
+ * HashHexRequest(this, HashModule, tab);
+ * \endcode
+ */
+class HashHexRequest : public HashRequest
+{
+ public:
+       /** Initialize HashHexRequest for sending.
+        * @param Me A pointer to the sending module
+        * @param Target A pointer to the hashing module
+        * @param data The hex sequence to use. This should contain exactly 16 ASCII characters,
+        * terminated by a NULL char.
+        */
+       HashHexRequest(Module* Me, Module* Target, const char* data) : HashRequest(Me, Target, data)
+       {
+       }
+};
+
+#endif
+
index 965194a0892e0a16336b0fac2c0cac987a57e92f..341f2b8613a5034c5b042389dd0d849d792ce889 100644 (file)
@@ -1 +1,191 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r\r/* $ModDesc: /helpop Command, Works like Unreal helpop */\rstatic std::map<irc::string, std::string> helpop_map;\r\r\r/** Handles user mode +h\r */\rclass Helpop : public ModeHandler\r{\r public:\r  Helpop(InspIRCd* Instance) : ModeHandler(Instance, 'h', 0, 0, false, MODETYPE_USER, true) { }\r\r ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)\r {\r              if (adding)\r            {\r                      if (!dest->IsModeSet('h'))\r                     {\r                              dest->SetMode('h',true);\r                               return MODEACTION_ALLOW;\r                       }\r              }\r              else\r           {\r                      if (dest->IsModeSet('h'))\r                      {\r                              dest->SetMode('h',false);\r                              return MODEACTION_ALLOW;\r                       }\r              }\r\r             return MODEACTION_DENY;\r        }\r};\r\r/** Handles /HELPOP\r */\rclass cmd_helpop : public command_t\r{\r public:\r   cmd_helpop (InspIRCd* Instance) : command_t(Instance, "HELPOP", 0, 0)\r  {\r              this->source = "m_helpop.so";\r          syntax = "<any-text>";\r }\r\r     CmdResult Handle (const char** parameters, int pcnt, userrec *user)\r    {\r              irc::string parameter;\r         if (pcnt > 0)\r                  parameter = parameters[0];\r\r            if (pcnt == 0 || parameter == "index")\r         {\r                      /* iterate over all helpop items */\r                    user->WriteServ("NOTICE %s :HELPOP topic index", user->nick);\r                  for (std::map<irc::string, std::string>::iterator iter = helpop_map.begin(); iter != helpop_map.end(); iter++)\r                 {\r                              user->WriteServ("NOTICE %s :    %s", user->nick, iter->first.c_str());                          \r                       }\r                      user->WriteServ("NOTICE %s :*** End of HELPOP topic index", user->nick);\r               }\r              else\r           {\r                      user->WriteServ("NOTICE %s :*** HELPOP for %s", user->nick, parameters[0]);\r\r                   std::map<irc::string, std::string>::iterator iter = helpop_map.find(parameter);\r\r                       if (iter == helpop_map.end())\r                  {\r                              iter = helpop_map.find("nohelp");\r                      }\r\r                     std::string value = iter->second;\r                      irc::sepstream stream(value, '\n');\r                    std::string token = "*";\r\r                      while ((token = stream.GetToken()) != "")\r                      {\r                              user->WriteServ("NOTICE %s :%s", user->nick, token.c_str());\r                   }\r\r                     user->WriteServ("NOTICE %s :*** End of HELPOP", user->nick);\r           }\r\r             /* We dont want these going out over the network, return CMD_FAILURE\r            * to make sure the protocol module thinks theyre not worth sending.\r            */\r            return CMD_FAILURE;\r    }\r};\r\rclass ModuleHelpop : public Module\r{\r     private:\r               std::string  h_file;\r           cmd_helpop* mycommand;\r         Helpop* ho;\r\r   public:\r                ModuleHelpop(InspIRCd* Me)\r                     : Module(Me)\r           {\r                      ReadConfig();\r                  ho = new Helpop(ServerInstance);\r                       if (!ServerInstance->AddMode(ho, 'h'))\r                         throw ModuleException("Could not add new modes!");\r                     mycommand = new cmd_helpop(ServerInstance);\r                    ServerInstance->AddCommand(mycommand);\r         }\r\r             virtual void ReadConfig()\r              {\r                      ConfigReader *MyConf = new ConfigReader(ServerInstance);\r\r                      helpop_map.clear();\r\r                   for (int i = 0; i < MyConf->Enumerate("helpop"); i++)\r                  {\r                              irc::string key = assign(MyConf->ReadValue("helpop", "key", i));\r                               std::string value = MyConf->ReadValue("helpop", "value", i, true); /* Linefeeds allowed! */\r\r                           if (key == "index")\r                            {\r                                      throw ModuleException("m_helpop: The key 'index' is reserved for internal purposes. Please remove it.");\r                               }\r\r                             helpop_map[key] = value;\r                       }\r\r                     if (helpop_map.find("start") == helpop_map.end())\r                      {\r                              // error!\r                              throw ModuleException("m_helpop: Helpop file is missing important entries. Please check the example conf.");\r                   }\r                      else if (helpop_map.find("nohelp") == helpop_map.end())\r                        {\r                              // error!\r                              throw ModuleException("m_helpop: Helpop file is missing important entries. Please check the example conf.");\r                   }\r\r             }\r\r             void Implements(char* List)\r            {\r                      List[I_OnRehash] = List[I_OnWhois] = 1;\r                }\r\r             virtual void OnRehash(userrec* user, const std::string &parameter)\r             {\r                      ReadConfig();\r          }\r\r             virtual void OnWhois(userrec* src, userrec* dst)\r               {\r                      if (dst->IsModeSet('h'))\r                       {\r                              ServerInstance->SendWhoisLine(src, dst, 310, std::string(src->nick)+" "+std::string(dst->nick)+" :is available for help.");\r                    }\r              }\r\r             virtual ~ModuleHelpop()\r                {\r                      ServerInstance->Modes->DelMode(ho);\r                    DELETE(ho);\r            }\r      \r               virtual Version GetVersion()\r           {\r                      return Version(1,1,0,1,VF_COMMON|VF_VENDOR,API_VERSION);\r               }\r};\r\rMODULE_INIT(ModuleHelpop)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+
+/* $ModDesc: /helpop Command, Works like Unreal helpop */
+static std::map<irc::string, std::string> helpop_map;
+
+
+/** Handles user mode +h
+ */
+class Helpop : public ModeHandler
+{
+ public:
+       Helpop(InspIRCd* Instance) : ModeHandler(Instance, 'h', 0, 0, false, MODETYPE_USER, true) { }
+
+       ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)
+       {
+               if (adding)
+               {
+                       if (!dest->IsModeSet('h'))
+                       {
+                               dest->SetMode('h',true);
+                               return MODEACTION_ALLOW;
+                       }
+               }
+               else
+               {
+                       if (dest->IsModeSet('h'))
+                       {
+                               dest->SetMode('h',false);
+                               return MODEACTION_ALLOW;
+                       }
+               }
+
+               return MODEACTION_DENY;
+       }
+};
+
+/** Handles /HELPOP
+ */
+class cmd_helpop : public command_t
+{
+ public:
+       cmd_helpop (InspIRCd* Instance) : command_t(Instance, "HELPOP", 0, 0)
+       {
+               this->source = "m_helpop.so";
+               syntax = "<any-text>";
+       }
+
+       CmdResult Handle (const char** parameters, int pcnt, userrec *user)
+       {
+               irc::string parameter;
+               if (pcnt > 0)
+                       parameter = parameters[0];
+
+               if (pcnt == 0 || parameter == "index")
+               {
+                       /* iterate over all helpop items */
+                       user->WriteServ("NOTICE %s :HELPOP topic index", user->nick);
+                       for (std::map<irc::string, std::string>::iterator iter = helpop_map.begin(); iter != helpop_map.end(); iter++)
+                       {
+                               user->WriteServ("NOTICE %s :    %s", user->nick, iter->first.c_str());                          
+                       }
+                       user->WriteServ("NOTICE %s :*** End of HELPOP topic index", user->nick);
+               }
+               else
+               {
+                       user->WriteServ("NOTICE %s :*** HELPOP for %s", user->nick, parameters[0]);
+
+                       std::map<irc::string, std::string>::iterator iter = helpop_map.find(parameter);
+
+                       if (iter == helpop_map.end())
+                       {
+                               iter = helpop_map.find("nohelp");
+                       }
+
+                       std::string value = iter->second;
+                       irc::sepstream stream(value, '\n');
+                       std::string token = "*";
+
+                       while ((token = stream.GetToken()) != "")
+                       {
+                               user->WriteServ("NOTICE %s :%s", user->nick, token.c_str());
+                       }
+
+                       user->WriteServ("NOTICE %s :*** End of HELPOP", user->nick);
+               }
+
+               /* We dont want these going out over the network, return CMD_FAILURE
+                * to make sure the protocol module thinks theyre not worth sending.
+                */
+               return CMD_FAILURE;
+       }
+};
+
+class ModuleHelpop : public Module
+{
+       private:
+               std::string  h_file;
+               cmd_helpop* mycommand;
+               Helpop* ho;
+
+       public:
+               ModuleHelpop(InspIRCd* Me)
+                       : Module(Me)
+               {
+                       ReadConfig();
+                       ho = new Helpop(ServerInstance);
+                       if (!ServerInstance->AddMode(ho, 'h'))
+                               throw ModuleException("Could not add new modes!");
+                       mycommand = new cmd_helpop(ServerInstance);
+                       ServerInstance->AddCommand(mycommand);
+               }
+
+               virtual void ReadConfig()
+               {
+                       ConfigReader *MyConf = new ConfigReader(ServerInstance);
+
+                       helpop_map.clear();
+
+                       for (int i = 0; i < MyConf->Enumerate("helpop"); i++)
+                       {
+                               irc::string key = assign(MyConf->ReadValue("helpop", "key", i));
+                               std::string value = MyConf->ReadValue("helpop", "value", i, true); /* Linefeeds allowed! */
+
+                               if (key == "index")
+                               {
+                                       throw ModuleException("m_helpop: The key 'index' is reserved for internal purposes. Please remove it.");
+                               }
+
+                               helpop_map[key] = value;
+                       }
+
+                       if (helpop_map.find("start") == helpop_map.end())
+                       {
+                               // error!
+                               throw ModuleException("m_helpop: Helpop file is missing important entries. Please check the example conf.");
+                       }
+                       else if (helpop_map.find("nohelp") == helpop_map.end())
+                       {
+                               // error!
+                               throw ModuleException("m_helpop: Helpop file is missing important entries. Please check the example conf.");
+                       }
+
+               }
+
+               void Implements(char* List)
+               {
+                       List[I_OnRehash] = List[I_OnWhois] = 1;
+               }
+
+               virtual void OnRehash(userrec* user, const std::string &parameter)
+               {
+                       ReadConfig();
+               }
+
+               virtual void OnWhois(userrec* src, userrec* dst)
+               {
+                       if (dst->IsModeSet('h'))
+                       {
+                               ServerInstance->SendWhoisLine(src, dst, 310, std::string(src->nick)+" "+std::string(dst->nick)+" :is available for help.");
+                       }
+               }
+
+               virtual ~ModuleHelpop()
+               {
+                       ServerInstance->Modes->DelMode(ho);
+                       DELETE(ho);
+               }
+       
+               virtual Version GetVersion()
+               {
+                       return Version(1,1,0,1,VF_COMMON|VF_VENDOR,API_VERSION);
+               }
+};
+
+MODULE_INIT(ModuleHelpop)
index 3924b84b959746f82844beaf43e8797cf31d399d..2c3769f7ada7989fb61b462c70139ec75b0784b9 100644 (file)
@@ -1 +1,95 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r\r/* $ModDesc: Provides support for hiding channels with user mode +I */\r\r/** Handles user mode +I\r */\rclass HideChans : public ModeHandler\r{\r public:\r HideChans(InspIRCd* Instance) : ModeHandler(Instance, 'I', 0, 0, false, MODETYPE_USER, false) { }\r\r     ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)\r {\r              /* Only opers can change other users modes */\r          if (source != dest)\r                    return MODEACTION_DENY;\r\r               if (adding)\r            {\r                      if (!dest->IsModeSet('I'))\r                     {\r                              dest->SetMode('I',true);\r                               return MODEACTION_ALLOW;\r                       }\r              }\r              else\r           {\r                      if (dest->IsModeSet('I'))\r                      {\r                              dest->SetMode('I',false);\r                              return MODEACTION_ALLOW;\r                       }\r              }\r              \r               return MODEACTION_DENY;\r        }\r};\r\rclass ModuleHideChans : public Module\r{\r  \r       HideChans* hm;\r public:\r        ModuleHideChans(InspIRCd* Me)\r          : Module(Me)\r   {\r              \r               hm = new HideChans(ServerInstance);\r            if (!ServerInstance->AddMode(hm, 'I'))\r                 throw ModuleException("Could not add new modes!");\r     }\r\r     void Implements(char* List)\r    {\r              List[I_OnWhoisLine] = 1;\r       }\r      \r       virtual ~ModuleHideChans()\r     {\r              ServerInstance->Modes->DelMode(hm);\r            DELETE(hm);\r    }\r      \r       virtual Version GetVersion()\r   {\r              return Version(1,1,0,0,VF_COMMON|VF_VENDOR,API_VERSION);\r       }\r\r     int OnWhoisLine(userrec* user, userrec* dest, int &numeric, std::string &text)\r {\r              /* Dont display channels if they have +I set and the\r            * person doing the WHOIS is not an oper\r                */\r            return ((user != dest) && (!IS_OPER(user)) && (numeric == 319) && dest->IsModeSet('I'));\r       }\r};\r\r\rMODULE_INIT(ModuleHideChans)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+
+/* $ModDesc: Provides support for hiding channels with user mode +I */
+
+/** Handles user mode +I
+ */
+class HideChans : public ModeHandler
+{
+ public:
+       HideChans(InspIRCd* Instance) : ModeHandler(Instance, 'I', 0, 0, false, MODETYPE_USER, false) { }
+
+       ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)
+       {
+               /* Only opers can change other users modes */
+               if (source != dest)
+                       return MODEACTION_DENY;
+
+               if (adding)
+               {
+                       if (!dest->IsModeSet('I'))
+                       {
+                               dest->SetMode('I',true);
+                               return MODEACTION_ALLOW;
+                       }
+               }
+               else
+               {
+                       if (dest->IsModeSet('I'))
+                       {
+                               dest->SetMode('I',false);
+                               return MODEACTION_ALLOW;
+                       }
+               }
+               
+               return MODEACTION_DENY;
+       }
+};
+
+class ModuleHideChans : public Module
+{
+       
+       HideChans* hm;
+ public:
+       ModuleHideChans(InspIRCd* Me)
+               : Module(Me)
+       {
+               
+               hm = new HideChans(ServerInstance);
+               if (!ServerInstance->AddMode(hm, 'I'))
+                       throw ModuleException("Could not add new modes!");
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnWhoisLine] = 1;
+       }
+       
+       virtual ~ModuleHideChans()
+       {
+               ServerInstance->Modes->DelMode(hm);
+               DELETE(hm);
+       }
+       
+       virtual Version GetVersion()
+       {
+               return Version(1,1,0,0,VF_COMMON|VF_VENDOR,API_VERSION);
+       }
+
+       int OnWhoisLine(userrec* user, userrec* dest, int &numeric, std::string &text)
+       {
+               /* Dont display channels if they have +I set and the
+                * person doing the WHOIS is not an oper
+                */
+               return ((user != dest) && (!IS_OPER(user)) && (numeric == 319) && dest->IsModeSet('I'));
+       }
+};
+
+
+MODULE_INIT(ModuleHideChans)
index c2b472bad9aec05b516d28ebd3ac17ee733b2e03..9f547d77db0a6e22ca8a23dbe6f1760bbcc7c2d5 100644 (file)
@@ -1 +1,94 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r\r/* $ModDesc: Provides support for hiding oper status with user mode +H */\r\r/** Handles user mode +B\r */\rclass HideOper : public ModeHandler\r{\r public:\r       HideOper(InspIRCd* Instance) : ModeHandler(Instance, 'H', 0, 0, false, MODETYPE_USER, true) { }\r\r       ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)\r {\r              if (source != dest)\r                    return MODEACTION_DENY;\r\r               if (adding)\r            {\r                      if (!dest->IsModeSet('H'))\r                     {\r                              dest->SetMode('H',true);\r                               return MODEACTION_ALLOW;\r                       }\r              }\r              else\r           {\r                      if (dest->IsModeSet('H'))\r                      {\r                              dest->SetMode('H',false);\r                              return MODEACTION_ALLOW;\r                       }\r              }\r              \r               return MODEACTION_DENY;\r        }\r};\r\rclass ModuleHideOper : public Module\r{\r   \r       HideOper* hm;\r public:\r ModuleHideOper(InspIRCd* Me)\r           : Module(Me)\r   {\r              \r               hm = new HideOper(ServerInstance);\r             if (!ServerInstance->AddMode(hm, 'H'))\r                 throw ModuleException("Could not add new modes!");\r     }\r\r     void Implements(char* List)\r    {\r              List[I_OnWhoisLine] = 1;\r       }\r      \r       virtual ~ModuleHideOper()\r      {\r              ServerInstance->Modes->DelMode(hm);\r            DELETE(hm);\r    }\r      \r       virtual Version GetVersion()\r   {\r              return Version(1,1,0,0,VF_COMMON|VF_VENDOR,API_VERSION);\r       }\r\r     int OnWhoisLine(userrec* user, userrec* dest, int &numeric, std::string &text)\r {\r              /* Dont display numeric 313 (RPL_WHOISOPER) if they have +H set and the\r                 * person doing the WHOIS is not an oper\r                */\r            return ((!IS_OPER(user)) && (numeric == 313) && dest->IsModeSet('H'));\r }\r};\r\r\rMODULE_INIT(ModuleHideOper)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+
+/* $ModDesc: Provides support for hiding oper status with user mode +H */
+
+/** Handles user mode +B
+ */
+class HideOper : public ModeHandler
+{
+ public:
+       HideOper(InspIRCd* Instance) : ModeHandler(Instance, 'H', 0, 0, false, MODETYPE_USER, true) { }
+
+       ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)
+       {
+               if (source != dest)
+                       return MODEACTION_DENY;
+
+               if (adding)
+               {
+                       if (!dest->IsModeSet('H'))
+                       {
+                               dest->SetMode('H',true);
+                               return MODEACTION_ALLOW;
+                       }
+               }
+               else
+               {
+                       if (dest->IsModeSet('H'))
+                       {
+                               dest->SetMode('H',false);
+                               return MODEACTION_ALLOW;
+                       }
+               }
+               
+               return MODEACTION_DENY;
+       }
+};
+
+class ModuleHideOper : public Module
+{
+       
+       HideOper* hm;
+ public:
+       ModuleHideOper(InspIRCd* Me)
+               : Module(Me)
+       {
+               
+               hm = new HideOper(ServerInstance);
+               if (!ServerInstance->AddMode(hm, 'H'))
+                       throw ModuleException("Could not add new modes!");
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnWhoisLine] = 1;
+       }
+       
+       virtual ~ModuleHideOper()
+       {
+               ServerInstance->Modes->DelMode(hm);
+               DELETE(hm);
+       }
+       
+       virtual Version GetVersion()
+       {
+               return Version(1,1,0,0,VF_COMMON|VF_VENDOR,API_VERSION);
+       }
+
+       int OnWhoisLine(userrec* user, userrec* dest, int &numeric, std::string &text)
+       {
+               /* Dont display numeric 313 (RPL_WHOISOPER) if they have +H set and the
+                * person doing the WHOIS is not an oper
+                */
+               return ((!IS_OPER(user)) && (numeric == 313) && dest->IsModeSet('H'));
+       }
+};
+
+
+MODULE_INIT(ModuleHideOper)
index f7ff58fa17aba57b79e9723f2b867c3a11ebb961..dc45a43d46bde86c96fe05e1783b7da816e9e2d8 100644 (file)
@@ -1 +1,148 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r\r/* $ModDesc: Provides masking of user hostnames in a different way to m_cloaking */\r\r/** Holds information on a host set by m_hostchange\r */\rclass Host : public classbase\r{\r public:\r        std::string action;\r    std::string newhost;\r};\r\rtypedef std::map<std::string,Host*> hostchanges_t;\r\rclass ModuleHostChange : public Module\r{\r private:\r        hostchanges_t hostchanges;\r     std::string MySuffix;\r  std::string MyPrefix;\r  std::string MySeparator;\r        \r public:\r     ModuleHostChange(InspIRCd* Me)\r         : Module(Me)\r   {\r              OnRehash(NULL,"");\r     }\r      \r       virtual ~ModuleHostChange()\r    {\r              for (hostchanges_t::iterator i = hostchanges.begin(); i != hostchanges.end(); i++)\r             {\r                      DELETE(i->second);\r             }\r              hostchanges.clear();\r   }\r\r     Priority Prioritize()\r  {\r              return (Priority)ServerInstance->PriorityAfter("m_cloaking.so");\r       }\r\r     void Implements(char* List)\r    {\r              List[I_OnRehash] = List[I_OnUserConnect] = 1;\r  }\r\r     virtual void OnRehash(userrec* user, const std::string &parameter)\r     {\r              ConfigReader Conf(ServerInstance);\r             MySuffix = Conf.ReadValue("host","suffix",0);\r          MyPrefix = Conf.ReadValue("host","prefix","",0);\r               MySeparator = Conf.ReadValue("host","separator",".",0);\r                for (hostchanges_t::iterator i = hostchanges.begin(); i != hostchanges.end(); i++)\r             {\r                      DELETE(i->second);\r             }\r              hostchanges.clear();\r           for (int index = 0; index < Conf.Enumerate("hostchange"); index++)\r             {\r                      std::string mask = Conf.ReadValue("hostchange","mask",index);\r                  std::string action = Conf.ReadValue("hostchange","action",index);\r                      std::string newhost = Conf.ReadValue("hostchange","value",index);\r                      Host* x = new Host;\r                    x->action = action;\r                    x->newhost = newhost;\r                  hostchanges[mask] = x;\r         }\r      }\r      \r       virtual Version GetVersion()\r   {\r              // returns the version number of the module to be\r              // listed in /MODULES\r          return Version(1,1,0,1,VF_VENDOR,API_VERSION);\r }\r      \r       virtual void OnUserConnect(userrec* user)\r      {\r              for (hostchanges_t::iterator i = hostchanges.begin(); i != hostchanges.end(); i++)\r             {\r                      if (ServerInstance->MatchText(std::string(user->ident)+"@"+std::string(user->host),i->first))\r                  {\r                              Host* h = (Host*)i->second;\r                            // host of new user matches a hostchange tag's mask\r                            std::string newhost;\r                           if (h->action == "set")\r                                {\r                                      newhost = h->newhost;\r                          }\r                              else if (h->action == "suffix")\r                                {\r                                      newhost = MySuffix;\r                            }\r                              else if (h->action == "addnick")\r                               {\r                                      // first take their nick and strip out non-dns, leaving just [A-Z0-9\-]\r                                        std::string complete;\r                                  std::string old = user->nick;\r                                  for (unsigned int j = 0; j < old.length(); j++)\r                                        {\r                                              if  (((old[j] >= 'A') && (old[j] <= 'Z')) ||\r                                               ((old[j] >= 'a') && (old[j] <= 'z')) ||\r                                                ((old[j] >= '0') && (old[j] <= '9')) ||\r                                                (old[j] == '-'))\r                                           {\r                                                      complete = complete + old[j];\r                                          }\r                                      }\r                                      if (complete.empty())\r                                          complete = "i-have-a-lame-nick";\r                                               \r                                       if (!MyPrefix.empty())\r                                         newhost = MyPrefix + MySeparator + complete;\r                                   else\r                                           newhost = complete + MySeparator + MySuffix;\r                           }\r                              if (!newhost.empty())\r                          {\r                                      user->WriteServ("NOTICE "+std::string(user->nick)+" :Setting your virtual host: " + newhost);\r                                  if (!user->ChangeDisplayedHost(newhost.c_str()))\r                                               user->WriteServ("NOTICE "+std::string(user->nick)+" :Could not set your virtual host: " + newhost);\r                                    return;\r                                }\r                      }\r              }\r      }\r};\r\rMODULE_INIT(ModuleHostChange)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+
+/* $ModDesc: Provides masking of user hostnames in a different way to m_cloaking */
+
+/** Holds information on a host set by m_hostchange
+ */
+class Host : public classbase
+{
+ public:
+       std::string action;
+       std::string newhost;
+};
+
+typedef std::map<std::string,Host*> hostchanges_t;
+
+class ModuleHostChange : public Module
+{
+ private:
+       hostchanges_t hostchanges;
+       std::string MySuffix;
+       std::string MyPrefix;
+       std::string MySeparator;
+        
+ public:
+       ModuleHostChange(InspIRCd* Me)
+               : Module(Me)
+       {
+               OnRehash(NULL,"");
+       }
+       
+       virtual ~ModuleHostChange()
+       {
+               for (hostchanges_t::iterator i = hostchanges.begin(); i != hostchanges.end(); i++)
+               {
+                       DELETE(i->second);
+               }
+               hostchanges.clear();
+       }
+
+       Priority Prioritize()
+       {
+               return (Priority)ServerInstance->PriorityAfter("m_cloaking.so");
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnRehash] = List[I_OnUserConnect] = 1;
+       }
+
+       virtual void OnRehash(userrec* user, const std::string &parameter)
+       {
+               ConfigReader Conf(ServerInstance);
+               MySuffix = Conf.ReadValue("host","suffix",0);
+               MyPrefix = Conf.ReadValue("host","prefix","",0);
+               MySeparator = Conf.ReadValue("host","separator",".",0);
+               for (hostchanges_t::iterator i = hostchanges.begin(); i != hostchanges.end(); i++)
+               {
+                       DELETE(i->second);
+               }
+               hostchanges.clear();
+               for (int index = 0; index < Conf.Enumerate("hostchange"); index++)
+               {
+                       std::string mask = Conf.ReadValue("hostchange","mask",index);
+                       std::string action = Conf.ReadValue("hostchange","action",index);
+                       std::string newhost = Conf.ReadValue("hostchange","value",index);
+                       Host* x = new Host;
+                       x->action = action;
+                       x->newhost = newhost;
+                       hostchanges[mask] = x;
+               }
+       }
+       
+       virtual Version GetVersion()
+       {
+               // returns the version number of the module to be
+               // listed in /MODULES
+               return Version(1,1,0,1,VF_VENDOR,API_VERSION);
+       }
+       
+       virtual void OnUserConnect(userrec* user)
+       {
+               for (hostchanges_t::iterator i = hostchanges.begin(); i != hostchanges.end(); i++)
+               {
+                       if (ServerInstance->MatchText(std::string(user->ident)+"@"+std::string(user->host),i->first))
+                       {
+                               Host* h = (Host*)i->second;
+                               // host of new user matches a hostchange tag's mask
+                               std::string newhost;
+                               if (h->action == "set")
+                               {
+                                       newhost = h->newhost;
+                               }
+                               else if (h->action == "suffix")
+                               {
+                                       newhost = MySuffix;
+                               }
+                               else if (h->action == "addnick")
+                               {
+                                       // first take their nick and strip out non-dns, leaving just [A-Z0-9\-]
+                                       std::string complete;
+                                       std::string old = user->nick;
+                                       for (unsigned int j = 0; j < old.length(); j++)
+                                       {
+                                               if  (((old[j] >= 'A') && (old[j] <= 'Z')) ||
+                                                   ((old[j] >= 'a') && (old[j] <= 'z')) ||
+                                                   ((old[j] >= '0') && (old[j] <= '9')) ||
+                                                   (old[j] == '-'))
+                                               {
+                                                       complete = complete + old[j];
+                                               }
+                                       }
+                                       if (complete.empty())
+                                               complete = "i-have-a-lame-nick";
+                                               
+                                       if (!MyPrefix.empty())
+                                               newhost = MyPrefix + MySeparator + complete;
+                                       else
+                                               newhost = complete + MySeparator + MySuffix;
+                               }
+                               if (!newhost.empty())
+                               {
+                                       user->WriteServ("NOTICE "+std::string(user->nick)+" :Setting your virtual host: " + newhost);
+                                       if (!user->ChangeDisplayedHost(newhost.c_str()))
+                                               user->WriteServ("NOTICE "+std::string(user->nick)+" :Could not set your virtual host: " + newhost);
+                                       return;
+                               }
+                       }
+               }
+       }
+};
+
+MODULE_INIT(ModuleHostChange)
index 3f9875caf2d8da94193547af4a52e1bfc641ff2a..35b93b5818c480359e55e47133661ab567727b5d 100644 (file)
@@ -1 +1,346 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "httpclient.h"\r\r/* $ModDesc: HTTP client service provider */\r\rclass URL\r{\r public:\r std::string url;\r       std::string protocol, username, password, domain, request;\r     int port;\r};\r\rclass HTTPSocket : public InspSocket\r{\r private:\r InspIRCd *Server;\r      class ModuleHTTPClient *Mod;\r   HTTPClientRequest req;\r HTTPClientResponse *response;\r  URL url;\r       enum { HTTP_CLOSED, HTTP_REQSENT, HTTP_HEADERS, HTTP_DATA } status;\r    std::string data;\r      std::string buffer;\r\r public:\r  HTTPSocket(InspIRCd *Instance, class ModuleHTTPClient *Mod);\r   virtual ~HTTPSocket();\r virtual bool DoRequest(HTTPClientRequest *req);\r        virtual bool ParseURL(const std::string &url);\r virtual void Connect(const std::string &ip);\r   virtual bool OnConnected();\r    virtual bool OnDataReady();\r    virtual void OnClose();\r};\r\rclass HTTPResolver : public Resolver\r{\r private:\r   HTTPSocket *socket;\r public:\r   HTTPResolver(HTTPSocket *socket, InspIRCd *Instance, const string &hostname, bool &cached, Module* me) : Resolver(Instance, hostname, DNS_QUERY_FORWARD, cached, me), socket(socket)\r   {\r      }\r      \r       void OnLookupComplete(const string &result, unsigned int ttl, bool cached)\r     {\r              socket->Connect(result);\r       }\r      \r       void OnError(ResolverError e, const string &errmsg)\r    {\r              delete socket;\r }\r};\r\rtypedef vector<HTTPSocket*> HTTPList;\r\rclass ModuleHTTPClient : public Module\r{\r public:\r HTTPList sockets;\r\r     ModuleHTTPClient(InspIRCd *Me)\r         : Module(Me)\r   {\r      }\r      \r       virtual ~ModuleHTTPClient()\r    {\r              for (HTTPList::iterator i = sockets.begin(); i != sockets.end(); i++)\r                  delete *i;\r     }\r      \r       virtual Version GetVersion()\r   {\r              return Version(1, 0, 0, 0, VF_SERVICEPROVIDER | VF_VENDOR, API_VERSION);\r       }\r\r     void Implements(char* List)\r    {\r              List[I_OnRequest] = 1;\r }\r\r     char* OnRequest(Request *req)\r  {\r              HTTPClientRequest *httpreq = (HTTPClientRequest *)req;\r         if (!strcmp(httpreq->GetId(), HTTP_CLIENT_REQUEST))\r            {\r                      HTTPSocket *sock = new HTTPSocket(ServerInstance, this);\r                       sock->DoRequest(httpreq);\r                      // No return value\r             }\r              return NULL;\r   }\r};\r\rHTTPSocket::HTTPSocket(InspIRCd *Instance, ModuleHTTPClient *Mod)\r                : InspSocket(Instance), Server(Instance), Mod(Mod), status(HTTP_CLOSED)\r{\r      this->ClosePending = false;\r    this->port = 80;\r}\r\rHTTPSocket::~HTTPSocket()\r{\r        Close();\r       for (HTTPList::iterator i = Mod->sockets.begin(); i != Mod->sockets.end(); i++)\r        {\r              if (*i == this)\r                {\r                      Mod->sockets.erase(i);\r                 break;\r         }\r      }\r}\r\rbool HTTPSocket::DoRequest(HTTPClientRequest *req)\r{\r      /* Tweak by brain - we take a copy of this,\r     * so that the caller doesnt need to leave\r      * pointers knocking around, less chance of\r     * a memory leak.\r       */\r    this->req = *req;\r\r     if (!ParseURL(this->req.GetURL()))\r             return false;\r  \r       this->port = url.port;\r strlcpy(this->host, url.domain.c_str(), MAXBUF);\r\r      in_addr addy1;\r#ifdef IPV6\r     in6_addr addy2;\r        if ((inet_aton(this->host, &addy1) > 0) || (inet_pton(AF_INET6, this->host, &addy2) > 0))\r#else\r        if (inet_aton(this->host, &addy1) > 0)\r#endif\r  {\r              bool cached;\r           HTTPResolver* r = new HTTPResolver(this, Server, url.domain, cached, (Module*)Mod);\r            Instance->AddResolver(r, cached);\r              return true;\r   }\r      else\r   {\r              this->Connect(url.domain);\r     }\r      \r       return true;\r}\r\rbool HTTPSocket::ParseURL(const std::string &iurl)\r{\r   url.url = iurl;\r        url.port = 80;\r url.protocol = "http";\r\r        irc::sepstream tokenizer(iurl, '/');\r   \r       for (int p = 0;; p++)\r  {\r              std::string part = tokenizer.GetToken();\r               if (part.empty() && tokenizer.StreamEnd())\r                     break;\r         \r               if ((p == 0) && (part[part.length() - 1] == ':'))\r              {\r                      // Protocol ('http:')\r                  url.protocol = part.substr(0, part.length() - 1);\r              }\r              else if ((p == 1) && (part.empty()))\r           {\r                      continue;\r              }\r              else if (url.domain.empty())\r           {\r                      // Domain part: [user[:pass]@]domain[:port]\r                    std::string::size_type usrpos = part.find('@');\r                        if (usrpos != std::string::npos)\r                       {\r                              // Have a user (and possibly password) part\r                            std::string::size_type ppos = part.find(':');\r                          if ((ppos != std::string::npos) && (ppos < usrpos))\r                            {\r                                      // Have password too\r                                   url.password = part.substr(ppos + 1, usrpos - ppos - 1);\r                                       url.username = part.substr(0, ppos);\r                           }\r                              else\r                           {\r                                      url.username = part.substr(0, usrpos);\r                         }\r                              \r                               part = part.substr(usrpos + 1);\r                        }\r                      \r                       std::string::size_type popos = part.rfind(':');\r                        if (popos != std::string::npos)\r                        {\r                              url.port = atoi(part.substr(popos + 1).c_str());\r                               url.domain = part.substr(0, popos);\r                    }\r                      else\r                   {\r                              url.domain = part;\r                     }\r              }\r              else\r           {\r                      // Request (part of it)..\r                      url.request.append("/");\r                       url.request.append(part);\r              }\r      }\r      \r       if (url.request.empty())\r               url.request = "/";\r\r    if ((url.domain.empty()) || (!url.port) || (url.protocol.empty()))\r     {\r              Instance->Log(DEFAULT, "Invalid URL (%s): Missing required value", iurl.c_str());\r              return false;\r  }\r      \r       if (url.protocol != "http")\r    {\r              Instance->Log(DEFAULT, "Invalid URL (%s): Unsupported protocol '%s'", iurl.c_str(), url.protocol.c_str());\r             return false;\r  }\r      \r       return true;\r}\r\rvoid HTTPSocket::Connect(const string &ip)\r{\r   strlcpy(this->IP, ip.c_str(), MAXBUF);\r \r       if (!this->DoConnect())\r        {\r              delete this;\r   }\r}\r\rbool HTTPSocket::OnConnected()\r{\r  std::string request = "GET " + url.request + " HTTP/1.1\r\n";\r\r // Dump headers into the request\r       HeaderMap headers = req.GetHeaders();\r  \r       for (HeaderMap::iterator i = headers.begin(); i != headers.end(); i++)\r         request += i->first + ": " + i->second + "\r\n";\r\r      // The Host header is required for HTTP 1.1 and isn't known when the request is created; if they didn't overload it\r    // manually, add it here\r       if (headers.find("Host") == headers.end())\r             request += "Host: " + url.domain + "\r\n"; \r    \r       request += "\r\n";\r     \r       this->status = HTTP_REQSENT;\r   \r       return this->Write(request);\r}\r\rbool HTTPSocket::OnDataReady()\r{\r       char *data = this->Read();\r\r    if (!data)\r     {\r              this->Close();\r         return false;\r  }\r\r     if (this->status < HTTP_DATA)\r  {\r              std::string line;\r              std::string::size_type pos;\r\r           this->buffer += data;\r          while ((pos = buffer.find("\r\n")) != std::string::npos)\r               {\r                      line = buffer.substr(0, pos);\r                  buffer = buffer.substr(pos + 2);\r                       if (line.empty())\r                      {\r                              this->status = HTTP_DATA;\r                              this->data += this->buffer;\r                            this->buffer.clear();\r                          break;\r                 }\r\r                     if (this->status == HTTP_REQSENT)\r                      {\r                              // HTTP reply (HTTP/1.1 200 msg)\r                               char const* data = line.c_str();\r                               data += 9;\r                             response = new HTTPClientResponse((Module*)Mod, req.GetSource() , url.url, atoi(data), data + 4);\r                              this->status = HTTP_HEADERS;\r                           continue;\r                      }\r                      \r                       if ((pos = line.find(':')) != std::string::npos)\r                       {\r                              response->AddHeader(line.substr(0, pos), line.substr(pos + 1));\r                        }\r                      else\r                   {\r                              continue;\r                      }\r              }\r      }\r      else\r   {\r              this->data += data;\r    }\r      return true;\r}\r\rvoid HTTPSocket::OnClose()\r{\r   if (data.empty())\r              return; // notification that request failed?\r\r  response->data = data;\r response->Send();\r      delete response;\r}\r\rMODULE_INIT(ModuleHTTPClient)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "httpclient.h"
+
+/* $ModDesc: HTTP client service provider */
+
+class URL
+{
+ public:
+       std::string url;
+       std::string protocol, username, password, domain, request;
+       int port;
+};
+
+class HTTPSocket : public InspSocket
+{
+ private:
+       InspIRCd *Server;
+       class ModuleHTTPClient *Mod;
+       HTTPClientRequest req;
+       HTTPClientResponse *response;
+       URL url;
+       enum { HTTP_CLOSED, HTTP_REQSENT, HTTP_HEADERS, HTTP_DATA } status;
+       std::string data;
+       std::string buffer;
+
+ public:
+       HTTPSocket(InspIRCd *Instance, class ModuleHTTPClient *Mod);
+       virtual ~HTTPSocket();
+       virtual bool DoRequest(HTTPClientRequest *req);
+       virtual bool ParseURL(const std::string &url);
+       virtual void Connect(const std::string &ip);
+       virtual bool OnConnected();
+       virtual bool OnDataReady();
+       virtual void OnClose();
+};
+
+class HTTPResolver : public Resolver
+{
+ private:
+       HTTPSocket *socket;
+ public:
+       HTTPResolver(HTTPSocket *socket, InspIRCd *Instance, const string &hostname, bool &cached, Module* me) : Resolver(Instance, hostname, DNS_QUERY_FORWARD, cached, me), socket(socket)
+       {
+       }
+       
+       void OnLookupComplete(const string &result, unsigned int ttl, bool cached)
+       {
+               socket->Connect(result);
+       }
+       
+       void OnError(ResolverError e, const string &errmsg)
+       {
+               delete socket;
+       }
+};
+
+typedef vector<HTTPSocket*> HTTPList;
+
+class ModuleHTTPClient : public Module
+{
+ public:
+       HTTPList sockets;
+
+       ModuleHTTPClient(InspIRCd *Me)
+               : Module(Me)
+       {
+       }
+       
+       virtual ~ModuleHTTPClient()
+       {
+               for (HTTPList::iterator i = sockets.begin(); i != sockets.end(); i++)
+                       delete *i;
+       }
+       
+       virtual Version GetVersion()
+       {
+               return Version(1, 0, 0, 0, VF_SERVICEPROVIDER | VF_VENDOR, API_VERSION);
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnRequest] = 1;
+       }
+
+       char* OnRequest(Request *req)
+       {
+               HTTPClientRequest *httpreq = (HTTPClientRequest *)req;
+               if (!strcmp(httpreq->GetId(), HTTP_CLIENT_REQUEST))
+               {
+                       HTTPSocket *sock = new HTTPSocket(ServerInstance, this);
+                       sock->DoRequest(httpreq);
+                       // No return value
+               }
+               return NULL;
+       }
+};
+
+HTTPSocket::HTTPSocket(InspIRCd *Instance, ModuleHTTPClient *Mod)
+               : InspSocket(Instance), Server(Instance), Mod(Mod), status(HTTP_CLOSED)
+{
+       this->ClosePending = false;
+       this->port = 80;
+}
+
+HTTPSocket::~HTTPSocket()
+{
+       Close();
+       for (HTTPList::iterator i = Mod->sockets.begin(); i != Mod->sockets.end(); i++)
+       {
+               if (*i == this)
+               {
+                       Mod->sockets.erase(i);
+                       break;
+               }
+       }
+}
+
+bool HTTPSocket::DoRequest(HTTPClientRequest *req)
+{
+       /* Tweak by brain - we take a copy of this,
+        * so that the caller doesnt need to leave
+        * pointers knocking around, less chance of
+        * a memory leak.
+        */
+       this->req = *req;
+
+       if (!ParseURL(this->req.GetURL()))
+               return false;
+       
+       this->port = url.port;
+       strlcpy(this->host, url.domain.c_str(), MAXBUF);
+
+       in_addr addy1;
+#ifdef IPV6
+       in6_addr addy2;
+       if ((inet_aton(this->host, &addy1) > 0) || (inet_pton(AF_INET6, this->host, &addy2) > 0))
+#else
+       if (inet_aton(this->host, &addy1) > 0)
+#endif
+       {
+               bool cached;
+               HTTPResolver* r = new HTTPResolver(this, Server, url.domain, cached, (Module*)Mod);
+               Instance->AddResolver(r, cached);
+               return true;
+       }
+       else
+       {
+               this->Connect(url.domain);
+       }
+       
+       return true;
+}
+
+bool HTTPSocket::ParseURL(const std::string &iurl)
+{
+       url.url = iurl;
+       url.port = 80;
+       url.protocol = "http";
+
+       irc::sepstream tokenizer(iurl, '/');
+       
+       for (int p = 0;; p++)
+       {
+               std::string part = tokenizer.GetToken();
+               if (part.empty() && tokenizer.StreamEnd())
+                       break;
+               
+               if ((p == 0) && (part[part.length() - 1] == ':'))
+               {
+                       // Protocol ('http:')
+                       url.protocol = part.substr(0, part.length() - 1);
+               }
+               else if ((p == 1) && (part.empty()))
+               {
+                       continue;
+               }
+               else if (url.domain.empty())
+               {
+                       // Domain part: [user[:pass]@]domain[:port]
+                       std::string::size_type usrpos = part.find('@');
+                       if (usrpos != std::string::npos)
+                       {
+                               // Have a user (and possibly password) part
+                               std::string::size_type ppos = part.find(':');
+                               if ((ppos != std::string::npos) && (ppos < usrpos))
+                               {
+                                       // Have password too
+                                       url.password = part.substr(ppos + 1, usrpos - ppos - 1);
+                                       url.username = part.substr(0, ppos);
+                               }
+                               else
+                               {
+                                       url.username = part.substr(0, usrpos);
+                               }
+                               
+                               part = part.substr(usrpos + 1);
+                       }
+                       
+                       std::string::size_type popos = part.rfind(':');
+                       if (popos != std::string::npos)
+                       {
+                               url.port = atoi(part.substr(popos + 1).c_str());
+                               url.domain = part.substr(0, popos);
+                       }
+                       else
+                       {
+                               url.domain = part;
+                       }
+               }
+               else
+               {
+                       // Request (part of it)..
+                       url.request.append("/");
+                       url.request.append(part);
+               }
+       }
+       
+       if (url.request.empty())
+               url.request = "/";
+
+       if ((url.domain.empty()) || (!url.port) || (url.protocol.empty()))
+       {
+               Instance->Log(DEFAULT, "Invalid URL (%s): Missing required value", iurl.c_str());
+               return false;
+       }
+       
+       if (url.protocol != "http")
+       {
+               Instance->Log(DEFAULT, "Invalid URL (%s): Unsupported protocol '%s'", iurl.c_str(), url.protocol.c_str());
+               return false;
+       }
+       
+       return true;
+}
+
+void HTTPSocket::Connect(const string &ip)
+{
+       strlcpy(this->IP, ip.c_str(), MAXBUF);
+       
+       if (!this->DoConnect())
+       {
+               delete this;
+       }
+}
+
+bool HTTPSocket::OnConnected()
+{
+       std::string request = "GET " + url.request + " HTTP/1.1\r\n";
+
+       // Dump headers into the request
+       HeaderMap headers = req.GetHeaders();
+       
+       for (HeaderMap::iterator i = headers.begin(); i != headers.end(); i++)
+               request += i->first + ": " + i->second + "\r\n";
+
+       // The Host header is required for HTTP 1.1 and isn't known when the request is created; if they didn't overload it
+       // manually, add it here
+       if (headers.find("Host") == headers.end())
+               request += "Host: " + url.domain + "\r\n"; 
+       
+       request += "\r\n";
+       
+       this->status = HTTP_REQSENT;
+       
+       return this->Write(request);
+}
+
+bool HTTPSocket::OnDataReady()
+{
+       char *data = this->Read();
+
+       if (!data)
+       {
+               this->Close();
+               return false;
+       }
+
+       if (this->status < HTTP_DATA)
+       {
+               std::string line;
+               std::string::size_type pos;
+
+               this->buffer += data;
+               while ((pos = buffer.find("\r\n")) != std::string::npos)
+               {
+                       line = buffer.substr(0, pos);
+                       buffer = buffer.substr(pos + 2);
+                       if (line.empty())
+                       {
+                               this->status = HTTP_DATA;
+                               this->data += this->buffer;
+                               this->buffer.clear();
+                               break;
+                       }
+
+                       if (this->status == HTTP_REQSENT)
+                       {
+                               // HTTP reply (HTTP/1.1 200 msg)
+                               char const* data = line.c_str();
+                               data += 9;
+                               response = new HTTPClientResponse((Module*)Mod, req.GetSource() , url.url, atoi(data), data + 4);
+                               this->status = HTTP_HEADERS;
+                               continue;
+                       }
+                       
+                       if ((pos = line.find(':')) != std::string::npos)
+                       {
+                               response->AddHeader(line.substr(0, pos), line.substr(pos + 1));
+                       }
+                       else
+                       {
+                               continue;
+                       }
+               }
+       }
+       else
+       {
+               this->data += data;
+       }
+       return true;
+}
+
+void HTTPSocket::OnClose()
+{
+       if (data.empty())
+               return; // notification that request failed?
+
+       response->data = data;
+       response->Send();
+       delete response;
+}
+
+MODULE_INIT(ModuleHTTPClient)
index 6ff80ad807ca15322fe3fe7fd8addbb3dcb9ebd0..8494863a3f4b4597471d6e6181936536b009e271 100644 (file)
@@ -1 +1,419 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include <algorithm>\r#include "modules.h"\r#include "httpd.h"\r\r/* $ModDesc: Provides HTTP serving facilities to modules */\r\rclass ModuleHttpServer;\r\rstatic ModuleHttpServer* HttpModule;\rstatic bool claimed;\r\r/** HTTP socket states\r */\renum HttpState\r{\r  HTTP_LISTEN = 0,\r       HTTP_SERVE_WAIT_REQUEST = 1,\r   HTTP_SERVE_RECV_POSTDATA = 2,\r  HTTP_SERVE_SEND_DATA = 3\r};\r\rclass HttpServerSocket;\r\r/** This class is used to handle HTTP socket timeouts\r */\rclass HttpServerTimeout : public InspTimer\r{\r private:\r /** HttpServerSocket we are attached to\r         */\r    HttpServerSocket* s;\r   /** Socketengine the file descriptor is in\r      */\r    SocketEngine* SE;\r public:\r     /** Attach timeout to HttpServerSocket\r  */\r    HttpServerTimeout(HttpServerSocket* sock, SocketEngine* engine);\r       /** Handle timer tick\r   */\r    void Tick(time_t TIME);\r};\r\r/** A socket used for HTTP transport\r */\rclass HttpServerSocket : public InspSocket\r{\r      FileReader* index;\r     HttpState InternalState;\r       std::stringstream headers;\r     std::string postdata;\r  std::string request_type;\r      std::string uri;\r       std::string http_version;\r      unsigned int postsize;\r HttpServerTimeout* Timeout;\r\r public:\r\r HttpServerSocket(InspIRCd* SI, std::string host, int port, bool listening, unsigned long maxtime, FileReader* index_page) : InspSocket(SI, host, port, listening, maxtime), index(index_page), postsize(0)\r     {\r              InternalState = HTTP_LISTEN;\r           Timeout = NULL;\r        }\r\r     HttpServerSocket(InspIRCd* SI, int newfd, char* ip, FileReader* ind) : InspSocket(SI, newfd, ip), index(ind), postsize(0)\r      {\r              InternalState = HTTP_SERVE_WAIT_REQUEST;\r               Timeout = new HttpServerTimeout(this, Instance->SE);\r           Instance->Timers->AddTimer(Timeout);\r   }\r\r     FileReader* GetIndex()\r {\r              return index;\r  }\r\r     ~HttpServerSocket()\r    {\r              if (Timeout)\r           {\r                      if (Instance->Time() < Timeout->GetTimer())\r                            Instance->Timers->DelTimer(Timeout);\r                   Timeout = NULL;\r                }\r      }\r\r     virtual int OnIncomingConnection(int newsock, char* ip)\r        {\r              if (InternalState == HTTP_LISTEN)\r              {\r                      HttpServerSocket* s = new HttpServerSocket(this->Instance, newsock, ip, index);\r                        s = s; /* Stop GCC whining */\r          }\r              return true;\r   }\r\r     virtual void OnClose()\r {\r      }\r\r     std::string Response(int response)\r     {\r              switch (response)\r              {\r                      case 100:\r                              return "CONTINUE";\r                     case 101:\r                              return "SWITCHING PROTOCOLS";\r                  case 200:\r                              return "OK";\r                   case 201:\r                              return "CREATED";\r                      case 202:\r                              return "ACCEPTED";\r                     case 203:\r                              return "NON-AUTHORITATIVE INFORMATION";\r                        case 204:\r                              return "NO CONTENT";\r                   case 205:\r                              return "RESET CONTENT";\r                        case 206:\r                              return "PARTIAL CONTENT";\r                      case 300:\r                              return "MULTIPLE CHOICES";\r                     case 301:\r                              return "MOVED PERMENANTLY";\r                    case 302:\r                              return "FOUND";\r                        case 303:\r                              return "SEE OTHER";\r                    case 304:\r                              return "NOT MODIFIED";\r                 case 305:\r                              return "USE PROXY";\r                    case 307:\r                              return "TEMPORARY REDIRECT";\r                   case 400:\r                              return "BAD REQUEST";\r                  case 401:\r                              return "UNAUTHORIZED";\r                 case 402:\r                              return "PAYMENT REQUIRED";\r                     case 403:\r                              return "FORBIDDEN";\r                    case 404:\r                              return "NOT FOUND";\r                    case 405:\r                              return "METHOD NOT ALLOWED";\r                   case 406:\r                              return "NOT ACCEPTABLE";\r                       case 407:\r                              return "PROXY AUTHENTICATION REQUIRED";\r                        case 408:\r                              return "REQUEST TIMEOUT";\r                      case 409:\r                              return "CONFLICT";\r                     case 410:\r                              return "GONE";\r                 case 411:\r                              return "LENGTH REQUIRED";\r                      case 412:\r                              return "PRECONDITION FAILED";\r                  case 413:\r                              return "REQUEST ENTITY TOO LARGE";\r                     case 414:\r                              return "REQUEST-URI TOO LONG";\r                 case 415:\r                              return "UNSUPPORTED MEDIA TYPE";\r                       case 416:\r                              return "REQUESTED RANGE NOT SATISFIABLE";\r                      case 417:\r                              return "EXPECTATION FAILED";\r                   case 500:\r                              return "INTERNAL SERVER ERROR";\r                        case 501:\r                              return "NOT IMPLEMENTED";\r                      case 502:\r                              return "BAD GATEWAY";\r                  case 503:\r                              return "SERVICE UNAVAILABLE";\r                  case 504:\r                              return "GATEWAY TIMEOUT";\r                      case 505:\r                              return "HTTP VERSION NOT SUPPORTED";\r                   default:\r                               return "WTF";\r                  break;\r                         \r               }\r      }\r\r     void SendHeaders(unsigned long size, int response, const std::string &extraheaders)\r    {\r              time_t local = this->Instance->Time();\r         struct tm *timeinfo = gmtime(&local);\r          this->Write("HTTP/1.1 "+ConvToStr(response)+" "+Response(response)+"\r\nDate: ");\r              this->Write(asctime(timeinfo));\r                if (extraheaders.empty())\r              {\r                      this->Write("Content-Type: text/html\r\n");\r            }\r              else\r           {\r                      this->Write(extraheaders);\r             }\r              this->Write("Server: InspIRCd/m_httpd.so/1.1\r\nContent-Length: "+ConvToStr(size)+\r                             "\r\nConnection: close\r\n\r\n");\r      }\r\r     virtual bool OnDataReady()\r     {\r              char* data = this->Read();\r\r            /* Check that the data read is a valid pointer and it has some content */\r              if (data && *data)\r             {\r                      headers << data;\r\r                      if (headers.str().find("\r\n\r\n") != std::string::npos)\r                       {\r                              if (request_type.empty())\r                              {\r                                      headers >> request_type;\r                                       headers >> uri;\r                                        headers >> http_version;\r\r                                      std::transform(request_type.begin(), request_type.end(), request_type.begin(), ::toupper);\r                                     std::transform(http_version.begin(), http_version.end(), http_version.begin(), ::toupper);\r                             }\r\r                             if ((InternalState == HTTP_SERVE_WAIT_REQUEST) && (request_type == "POST"))\r                            {\r                                      /* Do we need to fetch postdata? */\r                                    postdata.clear();\r                                      InternalState = HTTP_SERVE_RECV_POSTDATA;\r                                      std::string header_item;\r                                       while (headers >> header_item)\r                                 {\r                                              if (header_item == "Content-Length:")\r                                          {\r                                                      headers >> header_item;\r                                                        postsize = atoi(header_item.c_str());\r                                          }\r                                      }\r                                      if (!postsize)\r                                 {\r                                              InternalState = HTTP_SERVE_SEND_DATA;\r                                          SendHeaders(0, 400, "");\r                                               Timeout = new HttpServerTimeout(this, Instance->SE);\r                                           Instance->Timers->AddTimer(Timeout);\r                                   }\r                                      else\r                                   {\r                                              std::string::size_type x = headers.str().find("\r\n\r\n");\r                                             postdata = headers.str().substr(x+4, headers.str().length());\r                                          /* Get content length and store */\r                                             if (postdata.length() >= postsize)\r                                                     ServeData();\r                                   }\r                              }\r                              else if (InternalState == HTTP_SERVE_RECV_POSTDATA)\r                            {\r                                      /* Add postdata, once we have it all, send the event */\r                                        postdata.append(data);\r                                 if (postdata.length() >= postsize)\r                                             ServeData();\r                           }\r                              else\r                           {\r                                      ServeData();\r                           }\r                              return true;\r                   }\r                      return true;\r           }\r              else\r           {\r                      return false;\r          }\r      }\r\r     void ServeData()\r       {\r              /* Headers are complete */\r             InternalState = HTTP_SERVE_SEND_DATA;\r\r         Instance->Timers->DelTimer(Timeout);\r           Timeout = NULL;\r        \r               if ((http_version != "HTTP/1.1") && (http_version != "HTTP/1.0"))\r              {\r                      SendHeaders(0, 505, "");\r               }\r              else\r           {\r                      if ((request_type == "GET") && (uri == "/"))\r                   {\r                              SendHeaders(index->ContentSize(), 200, "");\r                            this->Write(index->Contents());\r                        }\r                      else\r                   {\r                              claimed = false;\r                               HTTPRequest httpr(request_type,uri,&headers,this,this->GetIP(),postdata);\r                              Event e((char*)&httpr, (Module*)HttpModule, "httpd_url");\r                              e.Send(this->Instance);\r                                if (!claimed)\r                          {\r                                      SendHeaders(0, 404, "");\r                               }\r                      }\r              }\r              Timeout = new HttpServerTimeout(this, Instance->SE);\r           Instance->Timers->AddTimer(Timeout);\r   }\r\r     void Page(std::stringstream* n, int response, std::string& extraheaders)\r       {\r              SendHeaders(n->str().length(), response, extraheaders);\r                this->Write(n->str());\r }\r};\r\rHttpServerTimeout::HttpServerTimeout(HttpServerSocket* sock, SocketEngine* engine) : InspTimer(60, time(NULL)), s(sock), SE(engine)\r{\r}\r\rvoid HttpServerTimeout::Tick(time_t TIME)\r{\r     SE->DelFd(s);\r  s->Close();\r}\r\rclass ModuleHttpServer : public Module\r{\r        std::vector<HttpServerSocket*> httpsocks;\r public:\r\r    void ReadConfig()\r      {\r              int port;\r              std::string host;\r              std::string bindip;\r            std::string indexfile;\r         FileReader* index;\r             HttpServerSocket* http;\r                ConfigReader c(ServerInstance);\r\r               httpsocks.clear();\r\r            for (int i = 0; i < c.Enumerate("http"); i++)\r          {\r                      host = c.ReadValue("http", "host", i);\r                 bindip = c.ReadValue("http", "ip", i);\r                 port = c.ReadInteger("http", "port", i, true);\r                 indexfile = c.ReadValue("http", "index", i);\r                   index = new FileReader(ServerInstance, indexfile);\r                     if (!index->Exists())\r                          throw ModuleException("Can't read index file: "+indexfile);\r                    http = new HttpServerSocket(ServerInstance, bindip, port, true, 0, index);\r                     httpsocks.push_back(http);\r             }\r      }\r\r     ModuleHttpServer(InspIRCd* Me) : Module(Me)\r    {\r              ReadConfig();\r  }\r\r     void OnEvent(Event* event)\r     {\r      }\r\r     char* OnRequest(Request* request)\r      {\r              claimed = true;\r                HTTPDocument* doc = (HTTPDocument*)request->GetData();\r         HttpServerSocket* sock = (HttpServerSocket*)doc->sock;\r         sock->Page(doc->GetDocument(), doc->GetResponseCode(), doc->GetExtraHeaders());\r                return NULL;\r   }\r\r     void Implements(char* List)\r    {\r              List[I_OnEvent] = List[I_OnRequest] = 1;\r       }\r\r     virtual ~ModuleHttpServer()\r    {\r              for (size_t i = 0; i < httpsocks.size(); i++)\r          {\r                      ServerInstance->SE->DelFd(httpsocks[i]);\r                       delete httpsocks[i]->GetIndex();\r                       delete httpsocks[i];\r           }\r      }\r\r     virtual Version GetVersion()\r   {\r              return Version(1,1,0,0,VF_VENDOR|VF_SERVICEPROVIDER,API_VERSION);\r      }\r};\r\rMODULE_INIT(ModuleHttpServer)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include <algorithm>
+#include "modules.h"
+#include "httpd.h"
+
+/* $ModDesc: Provides HTTP serving facilities to modules */
+
+class ModuleHttpServer;
+
+static ModuleHttpServer* HttpModule;
+static bool claimed;
+
+/** HTTP socket states
+ */
+enum HttpState
+{
+       HTTP_LISTEN = 0,
+       HTTP_SERVE_WAIT_REQUEST = 1,
+       HTTP_SERVE_RECV_POSTDATA = 2,
+       HTTP_SERVE_SEND_DATA = 3
+};
+
+class HttpServerSocket;
+
+/** This class is used to handle HTTP socket timeouts
+ */
+class HttpServerTimeout : public InspTimer
+{
+ private:
+       /** HttpServerSocket we are attached to
+        */
+       HttpServerSocket* s;
+       /** Socketengine the file descriptor is in
+        */
+       SocketEngine* SE;
+ public:
+       /** Attach timeout to HttpServerSocket
+        */
+       HttpServerTimeout(HttpServerSocket* sock, SocketEngine* engine);
+       /** Handle timer tick
+        */
+       void Tick(time_t TIME);
+};
+
+/** A socket used for HTTP transport
+ */
+class HttpServerSocket : public InspSocket
+{
+       FileReader* index;
+       HttpState InternalState;
+       std::stringstream headers;
+       std::string postdata;
+       std::string request_type;
+       std::string uri;
+       std::string http_version;
+       unsigned int postsize;
+       HttpServerTimeout* Timeout;
+
+ public:
+
+       HttpServerSocket(InspIRCd* SI, std::string host, int port, bool listening, unsigned long maxtime, FileReader* index_page) : InspSocket(SI, host, port, listening, maxtime), index(index_page), postsize(0)
+       {
+               InternalState = HTTP_LISTEN;
+               Timeout = NULL;
+       }
+
+       HttpServerSocket(InspIRCd* SI, int newfd, char* ip, FileReader* ind) : InspSocket(SI, newfd, ip), index(ind), postsize(0)
+       {
+               InternalState = HTTP_SERVE_WAIT_REQUEST;
+               Timeout = new HttpServerTimeout(this, Instance->SE);
+               Instance->Timers->AddTimer(Timeout);
+       }
+
+       FileReader* GetIndex()
+       {
+               return index;
+       }
+
+       ~HttpServerSocket()
+       {
+               if (Timeout)
+               {
+                       if (Instance->Time() < Timeout->GetTimer())
+                               Instance->Timers->DelTimer(Timeout);
+                       Timeout = NULL;
+               }
+       }
+
+       virtual int OnIncomingConnection(int newsock, char* ip)
+       {
+               if (InternalState == HTTP_LISTEN)
+               {
+                       HttpServerSocket* s = new HttpServerSocket(this->Instance, newsock, ip, index);
+                       s = s; /* Stop GCC whining */
+               }
+               return true;
+       }
+
+       virtual void OnClose()
+       {
+       }
+
+       std::string Response(int response)
+       {
+               switch (response)
+               {
+                       case 100:
+                               return "CONTINUE";
+                       case 101:
+                               return "SWITCHING PROTOCOLS";
+                       case 200:
+                               return "OK";
+                       case 201:
+                               return "CREATED";
+                       case 202:
+                               return "ACCEPTED";
+                       case 203:
+                               return "NON-AUTHORITATIVE INFORMATION";
+                       case 204:
+                               return "NO CONTENT";
+                       case 205:
+                               return "RESET CONTENT";
+                       case 206:
+                               return "PARTIAL CONTENT";
+                       case 300:
+                               return "MULTIPLE CHOICES";
+                       case 301:
+                               return "MOVED PERMENANTLY";
+                       case 302:
+                               return "FOUND";
+                       case 303:
+                               return "SEE OTHER";
+                       case 304:
+                               return "NOT MODIFIED";
+                       case 305:
+                               return "USE PROXY";
+                       case 307:
+                               return "TEMPORARY REDIRECT";
+                       case 400:
+                               return "BAD REQUEST";
+                       case 401:
+                               return "UNAUTHORIZED";
+                       case 402:
+                               return "PAYMENT REQUIRED";
+                       case 403:
+                               return "FORBIDDEN";
+                       case 404:
+                               return "NOT FOUND";
+                       case 405:
+                               return "METHOD NOT ALLOWED";
+                       case 406:
+                               return "NOT ACCEPTABLE";
+                       case 407:
+                               return "PROXY AUTHENTICATION REQUIRED";
+                       case 408:
+                               return "REQUEST TIMEOUT";
+                       case 409:
+                               return "CONFLICT";
+                       case 410:
+                               return "GONE";
+                       case 411:
+                               return "LENGTH REQUIRED";
+                       case 412:
+                               return "PRECONDITION FAILED";
+                       case 413:
+                               return "REQUEST ENTITY TOO LARGE";
+                       case 414:
+                               return "REQUEST-URI TOO LONG";
+                       case 415:
+                               return "UNSUPPORTED MEDIA TYPE";
+                       case 416:
+                               return "REQUESTED RANGE NOT SATISFIABLE";
+                       case 417:
+                               return "EXPECTATION FAILED";
+                       case 500:
+                               return "INTERNAL SERVER ERROR";
+                       case 501:
+                               return "NOT IMPLEMENTED";
+                       case 502:
+                               return "BAD GATEWAY";
+                       case 503:
+                               return "SERVICE UNAVAILABLE";
+                       case 504:
+                               return "GATEWAY TIMEOUT";
+                       case 505:
+                               return "HTTP VERSION NOT SUPPORTED";
+                       default:
+                               return "WTF";
+                       break;
+                               
+               }
+       }
+
+       void SendHeaders(unsigned long size, int response, const std::string &extraheaders)
+       {
+               time_t local = this->Instance->Time();
+               struct tm *timeinfo = gmtime(&local);
+               this->Write("HTTP/1.1 "+ConvToStr(response)+" "+Response(response)+"\r\nDate: ");
+               this->Write(asctime(timeinfo));
+               if (extraheaders.empty())
+               {
+                       this->Write("Content-Type: text/html\r\n");
+               }
+               else
+               {
+                       this->Write(extraheaders);
+               }
+               this->Write("Server: InspIRCd/m_httpd.so/1.1\r\nContent-Length: "+ConvToStr(size)+
+                               "\r\nConnection: close\r\n\r\n");
+       }
+
+       virtual bool OnDataReady()
+       {
+               char* data = this->Read();
+
+               /* Check that the data read is a valid pointer and it has some content */
+               if (data && *data)
+               {
+                       headers << data;
+
+                       if (headers.str().find("\r\n\r\n") != std::string::npos)
+                       {
+                               if (request_type.empty())
+                               {
+                                       headers >> request_type;
+                                       headers >> uri;
+                                       headers >> http_version;
+
+                                       std::transform(request_type.begin(), request_type.end(), request_type.begin(), ::toupper);
+                                       std::transform(http_version.begin(), http_version.end(), http_version.begin(), ::toupper);
+                               }
+
+                               if ((InternalState == HTTP_SERVE_WAIT_REQUEST) && (request_type == "POST"))
+                               {
+                                       /* Do we need to fetch postdata? */
+                                       postdata.clear();
+                                       InternalState = HTTP_SERVE_RECV_POSTDATA;
+                                       std::string header_item;
+                                       while (headers >> header_item)
+                                       {
+                                               if (header_item == "Content-Length:")
+                                               {
+                                                       headers >> header_item;
+                                                       postsize = atoi(header_item.c_str());
+                                               }
+                                       }
+                                       if (!postsize)
+                                       {
+                                               InternalState = HTTP_SERVE_SEND_DATA;
+                                               SendHeaders(0, 400, "");
+                                               Timeout = new HttpServerTimeout(this, Instance->SE);
+                                               Instance->Timers->AddTimer(Timeout);
+                                       }
+                                       else
+                                       {
+                                               std::string::size_type x = headers.str().find("\r\n\r\n");
+                                               postdata = headers.str().substr(x+4, headers.str().length());
+                                               /* Get content length and store */
+                                               if (postdata.length() >= postsize)
+                                                       ServeData();
+                                       }
+                               }
+                               else if (InternalState == HTTP_SERVE_RECV_POSTDATA)
+                               {
+                                       /* Add postdata, once we have it all, send the event */
+                                       postdata.append(data);
+                                       if (postdata.length() >= postsize)
+                                               ServeData();
+                               }
+                               else
+                               {
+                                       ServeData();
+                               }
+                               return true;
+                       }
+                       return true;
+               }
+               else
+               {
+                       return false;
+               }
+       }
+
+       void ServeData()
+       {
+               /* Headers are complete */
+               InternalState = HTTP_SERVE_SEND_DATA;
+
+               Instance->Timers->DelTimer(Timeout);
+               Timeout = NULL;
+       
+               if ((http_version != "HTTP/1.1") && (http_version != "HTTP/1.0"))
+               {
+                       SendHeaders(0, 505, "");
+               }
+               else
+               {
+                       if ((request_type == "GET") && (uri == "/"))
+                       {
+                               SendHeaders(index->ContentSize(), 200, "");
+                               this->Write(index->Contents());
+                       }
+                       else
+                       {
+                               claimed = false;
+                               HTTPRequest httpr(request_type,uri,&headers,this,this->GetIP(),postdata);
+                               Event e((char*)&httpr, (Module*)HttpModule, "httpd_url");
+                               e.Send(this->Instance);
+                               if (!claimed)
+                               {
+                                       SendHeaders(0, 404, "");
+                               }
+                       }
+               }
+               Timeout = new HttpServerTimeout(this, Instance->SE);
+               Instance->Timers->AddTimer(Timeout);
+       }
+
+       void Page(std::stringstream* n, int response, std::string& extraheaders)
+       {
+               SendHeaders(n->str().length(), response, extraheaders);
+               this->Write(n->str());
+       }
+};
+
+HttpServerTimeout::HttpServerTimeout(HttpServerSocket* sock, SocketEngine* engine) : InspTimer(60, time(NULL)), s(sock), SE(engine)
+{
+}
+
+void HttpServerTimeout::Tick(time_t TIME)
+{
+       SE->DelFd(s);
+       s->Close();
+}
+
+class ModuleHttpServer : public Module
+{
+       std::vector<HttpServerSocket*> httpsocks;
+ public:
+
+       void ReadConfig()
+       {
+               int port;
+               std::string host;
+               std::string bindip;
+               std::string indexfile;
+               FileReader* index;
+               HttpServerSocket* http;
+               ConfigReader c(ServerInstance);
+
+               httpsocks.clear();
+
+               for (int i = 0; i < c.Enumerate("http"); i++)
+               {
+                       host = c.ReadValue("http", "host", i);
+                       bindip = c.ReadValue("http", "ip", i);
+                       port = c.ReadInteger("http", "port", i, true);
+                       indexfile = c.ReadValue("http", "index", i);
+                       index = new FileReader(ServerInstance, indexfile);
+                       if (!index->Exists())
+                               throw ModuleException("Can't read index file: "+indexfile);
+                       http = new HttpServerSocket(ServerInstance, bindip, port, true, 0, index);
+                       httpsocks.push_back(http);
+               }
+       }
+
+       ModuleHttpServer(InspIRCd* Me) : Module(Me)
+       {
+               ReadConfig();
+       }
+
+       void OnEvent(Event* event)
+       {
+       }
+
+       char* OnRequest(Request* request)
+       {
+               claimed = true;
+               HTTPDocument* doc = (HTTPDocument*)request->GetData();
+               HttpServerSocket* sock = (HttpServerSocket*)doc->sock;
+               sock->Page(doc->GetDocument(), doc->GetResponseCode(), doc->GetExtraHeaders());
+               return NULL;
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnEvent] = List[I_OnRequest] = 1;
+       }
+
+       virtual ~ModuleHttpServer()
+       {
+               for (size_t i = 0; i < httpsocks.size(); i++)
+               {
+                       ServerInstance->SE->DelFd(httpsocks[i]);
+                       delete httpsocks[i]->GetIndex();
+                       delete httpsocks[i];
+               }
+       }
+
+       virtual Version GetVersion()
+       {
+               return Version(1,1,0,0,VF_VENDOR|VF_SERVICEPROVIDER,API_VERSION);
+       }
+};
+
+MODULE_INIT(ModuleHttpServer)
index 49b5bbab5c90a5be7196ebfc406dbd52c96671d6..5c29123f8f4548b9c2f00537084dc950004f0929 100644 (file)
@@ -1 +1,241 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "configreader.h"\r#include "modules.h"\r#include "inspsocket.h"\r#include "httpd.h"\r\r/* $ModDesc: Provides statistics over HTTP via m_httpd.so */\r\rtypedef std::map<irc::string,int> StatsHash;\rtypedef StatsHash::iterator StatsIter;\r\rtypedef std::vector<std::pair<int,irc::string> > SortedList;\rtypedef SortedList::iterator SortedIter;\r\rstatic StatsHash* sh = new StatsHash();\rstatic SortedList* so = new SortedList();\r\rclass ModuleHttpStats : public Module\r{\r    \r       std::string stylesheet;\r        bool changed;\r\r public:\r\r       void ReadConfig()\r      {\r              ConfigReader c(ServerInstance);\r                this->stylesheet = c.ReadValue("httpstats", "stylesheet", 0);\r  }\r\r     ModuleHttpStats(InspIRCd* Me) : Module(Me)\r     {\r              \r               ReadConfig();\r          this->changed = false;\r }\r\r     void InsertOrder(irc::string channel, int count)\r       {\r              /* This function figures out where in the sorted list to put an item from the hash */\r          SortedIter a;\r          for (a = so->begin(); a != so->end(); a++)\r             {\r                      /* Found an item equal to or less than, we insert our item before it */\r                        if (a->first <= count)\r                 {\r                              so->insert(a,std::pair<int,irc::string>(count,channel));\r                               return;\r                        }\r              }\r              /* There are no items in the list yet, insert something at the beginning */\r            so->insert(so->begin(), std::pair<int,irc::string>(count,channel));\r    }\r\r     void SortList()\r        {\r              /* Sorts the hash into the sorted list using an insertion sort */\r              so->clear();\r           for (StatsIter a = sh->begin(); a != sh->end(); a++)\r                   InsertOrder(a->first, a->second);\r              this->changed = false;\r }\r\r     void OnEvent(Event* event)\r     {\r              std::stringstream data("");\r\r           if (event->GetEventID() == "httpd_url")\r                {\r                      HTTPRequest* http = (HTTPRequest*)event->GetData();\r\r                   if ((http->GetURI() == "/stats") || (http->GetURI() == "/stats/"))\r                     {\r                              data << "<!DOCTYPE html PUBLIC \\r                                       \"-//W3C//DTD XHTML 1.1//EN\" \\r                                        \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n\\r                                   <html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\">";\r\r                               data << "<head>";\r                              data << "<link rel='stylesheet' href='" << this->stylesheet << "' type='text/css' />";\r                         data << "<title>InspIRCd server statisitics for " << ServerInstance->Config->ServerName << " (" << ServerInstance->Config->ServerDesc << ")</title>";\r                          data << "</head><body>";\r                               data << "<h1>InspIRCd server statisitics for " << ServerInstance->Config->ServerName << " (" << ServerInstance->Config->ServerDesc << ")</h1>";\r\r                               data << "<div class='totals'>";\r                                data << "<h2>Totals</h2>";\r                             data << "<table>";\r                             data << "<tr><td>Users</td><td>" << ServerInstance->clientlist->size() << "</td></tr>";\r                                data << "<tr><td>Channels</td><td>" << ServerInstance->chanlist->size() << "</td></tr>";\r                               data << "<tr><td>Opers</td><td>" << ServerInstance->all_opers.size() << "</td></tr>";\r                          data << "<tr><td>Sockets</td><td>" << (ServerInstance->SE->GetMaxFds() - ServerInstance->SE->GetRemainingFds()) << " (Max: " << ServerInstance->SE->GetMaxFds() << " via socket engine '" << ServerInstance->SE->GetName() << "')</td></tr>";\r                          data << "</table>";\r                            data << "</div>";\r\r                             data << "<div class='modules'>";\r                               data << "<h2>Modules</h2>";\r                            data << "<table>";\r                             for (int i = 0; i <= ServerInstance->GetModuleCount(); i++)\r                            {\r                                      if (!ServerInstance->Config->module_names[i].empty())\r                                          data << "<tr><td>" << ServerInstance->Config->module_names[i] << "</td></tr>";\r                         }\r                              data << "</table>";\r                            data << "</div>";\r\r                             data << "<div class='channels'>";\r                              data << "<h2>Channels</h2>";\r                           data << "<table>";\r                             data << "<tr><th>Users</th><th>Name</th><th>@</th><th>%</th><th>+</th><th>Topic</th></tr>";\r\r                           /* If the list has changed since last time it was displayed, re-sort it\r                                 * this time only (not every time, as this would be moronic)\r                            */\r                            if (this->changed)\r                                     this->SortList();\r\r                             int n = 0;\r                             for (SortedIter a = so->begin(); ((a != so->end()) && (n < 25)); a++, n++)\r                             {\r                                      chanrec* c = ServerInstance->FindChan(a->second.c_str());\r                                      if (c)\r                                 {\r                                              data << "<tr><td>" << a->first << "</td><td>" << a->second << "</td>";\r                                         data << "<td>" << c->GetOppedUsers()->size() << "</td>";\r                                               data << "<td>" << c->GetHalfoppedUsers()->size() << "</td>";\r                                           data << "<td>" << c->GetVoicedUsers()->size() << "</td>";\r                                              data << "<td>" << c->topic << "</td>";\r                                         data << "</tr>";\r                                       }\r                              }\r\r                             data << "</table>";\r                            data << "</div>";\r\r\r\r\r\r                         data << "<div class='validion'>";\r                              data << "<p><a href='http://validator.w3.org/check?uri=referer'><img src='http://www.w3.org/Icons/valid-xhtml11' alt='Valid XHTML 1.1' height='31' width='88' /></a></p>";\r                             data << "</div>";\r                              \r                               data << "</body>";\r                             data << "</html>";\r\r                            /* Send the document back to m_httpd */\r                                HTTPDocument response(http->sock, &data, 200, "X-Powered-By: m_http_stats.so\r\nContent-Type: text/html; charset=iso-8859-1\r\n");\r                             Request req((char*)&response, (Module*)this, event->GetSource());\r                              req.Send();\r                    }\r              }\r      }\r\r     void OnChannelDelete(chanrec* chan)\r    {\r              StatsIter a = sh->find(chan->name);\r            if (a != sh->end())\r            {\r                      sh->erase(a);\r          }\r              this->changed = true;\r  }\r\r     void OnUserJoin(userrec* user, chanrec* channel, bool &silent)\r {\r              StatsIter a = sh->find(channel->name);\r         if (a != sh->end())\r            {\r                      a->second++;\r           }\r              else\r           {\r                      irc::string name = channel->name;\r                      sh->insert(std::pair<irc::string,int>(name,1));\r                }\r              this->changed = true;\r  }\r\r     void OnUserPart(userrec* user, chanrec* channel, const std::string &partmessage, bool &silent)\r {\r              StatsIter a = sh->find(channel->name);\r         if (a != sh->end())\r            {\r                      a->second--;\r           }\r              this->changed = true;\r  }\r\r     void OnUserQuit(userrec* user, const std::string &message, const std::string &oper_message)\r    {\r              for (UCListIter v = user->chans.begin(); v != user->chans.end(); v++)\r          {\r                      chanrec* c = v->first;\r                 StatsIter a = sh->find(c->name);\r                       if (a != sh->end())\r                    {\r                              a->second--;\r                   }\r              }\r              this->changed = true;\r  }\r\r     char* OnRequest(Request* request)\r      {\r              return NULL;\r   }\r\r     void Implements(char* List)\r    {\r              List[I_OnEvent] = List[I_OnRequest] = List[I_OnChannelDelete] = List[I_OnUserJoin] = List[I_OnUserPart] = List[I_OnUserQuit] = 1;\r      }\r\r     virtual ~ModuleHttpStats()\r     {\r              delete sh;\r             delete so;\r     }\r\r     virtual Version GetVersion()\r   {\r              return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION);\r    }\r};\r\rMODULE_INIT(ModuleHttpStats)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "configreader.h"
+#include "modules.h"
+#include "inspsocket.h"
+#include "httpd.h"
+
+/* $ModDesc: Provides statistics over HTTP via m_httpd.so */
+
+typedef std::map<irc::string,int> StatsHash;
+typedef StatsHash::iterator StatsIter;
+
+typedef std::vector<std::pair<int,irc::string> > SortedList;
+typedef SortedList::iterator SortedIter;
+
+static StatsHash* sh = new StatsHash();
+static SortedList* so = new SortedList();
+
+class ModuleHttpStats : public Module
+{
+       
+       std::string stylesheet;
+       bool changed;
+
+ public:
+
+       void ReadConfig()
+       {
+               ConfigReader c(ServerInstance);
+               this->stylesheet = c.ReadValue("httpstats", "stylesheet", 0);
+       }
+
+       ModuleHttpStats(InspIRCd* Me) : Module(Me)
+       {
+               
+               ReadConfig();
+               this->changed = false;
+       }
+
+       void InsertOrder(irc::string channel, int count)
+       {
+               /* This function figures out where in the sorted list to put an item from the hash */
+               SortedIter a;
+               for (a = so->begin(); a != so->end(); a++)
+               {
+                       /* Found an item equal to or less than, we insert our item before it */
+                       if (a->first <= count)
+                       {
+                               so->insert(a,std::pair<int,irc::string>(count,channel));
+                               return;
+                       }
+               }
+               /* There are no items in the list yet, insert something at the beginning */
+               so->insert(so->begin(), std::pair<int,irc::string>(count,channel));
+       }
+
+       void SortList()
+       {
+               /* Sorts the hash into the sorted list using an insertion sort */
+               so->clear();
+               for (StatsIter a = sh->begin(); a != sh->end(); a++)
+                       InsertOrder(a->first, a->second);
+               this->changed = false;
+       }
+
+       void OnEvent(Event* event)
+       {
+               std::stringstream data("");
+
+               if (event->GetEventID() == "httpd_url")
+               {
+                       HTTPRequest* http = (HTTPRequest*)event->GetData();
+
+                       if ((http->GetURI() == "/stats") || (http->GetURI() == "/stats/"))
+                       {
+                               data << "<!DOCTYPE html PUBLIC \
+                                       \"-//W3C//DTD XHTML 1.1//EN\" \
+                                       \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n\
+                                       <html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\">";
+
+                               data << "<head>";
+                               data << "<link rel='stylesheet' href='" << this->stylesheet << "' type='text/css' />";
+                               data << "<title>InspIRCd server statisitics for " << ServerInstance->Config->ServerName << " (" << ServerInstance->Config->ServerDesc << ")</title>";
+                               data << "</head><body>";
+                               data << "<h1>InspIRCd server statisitics for " << ServerInstance->Config->ServerName << " (" << ServerInstance->Config->ServerDesc << ")</h1>";
+
+                               data << "<div class='totals'>";
+                               data << "<h2>Totals</h2>";
+                               data << "<table>";
+                               data << "<tr><td>Users</td><td>" << ServerInstance->clientlist->size() << "</td></tr>";
+                               data << "<tr><td>Channels</td><td>" << ServerInstance->chanlist->size() << "</td></tr>";
+                               data << "<tr><td>Opers</td><td>" << ServerInstance->all_opers.size() << "</td></tr>";
+                               data << "<tr><td>Sockets</td><td>" << (ServerInstance->SE->GetMaxFds() - ServerInstance->SE->GetRemainingFds()) << " (Max: " << ServerInstance->SE->GetMaxFds() << " via socket engine '" << ServerInstance->SE->GetName() << "')</td></tr>";
+                               data << "</table>";
+                               data << "</div>";
+
+                               data << "<div class='modules'>";
+                               data << "<h2>Modules</h2>";
+                               data << "<table>";
+                               for (int i = 0; i <= ServerInstance->GetModuleCount(); i++)
+                               {
+                                       if (!ServerInstance->Config->module_names[i].empty())
+                                               data << "<tr><td>" << ServerInstance->Config->module_names[i] << "</td></tr>";
+                               }
+                               data << "</table>";
+                               data << "</div>";
+
+                               data << "<div class='channels'>";
+                               data << "<h2>Channels</h2>";
+                               data << "<table>";
+                               data << "<tr><th>Users</th><th>Name</th><th>@</th><th>%</th><th>+</th><th>Topic</th></tr>";
+
+                               /* If the list has changed since last time it was displayed, re-sort it
+                                * this time only (not every time, as this would be moronic)
+                                */
+                               if (this->changed)
+                                       this->SortList();
+
+                               int n = 0;
+                               for (SortedIter a = so->begin(); ((a != so->end()) && (n < 25)); a++, n++)
+                               {
+                                       chanrec* c = ServerInstance->FindChan(a->second.c_str());
+                                       if (c)
+                                       {
+                                               data << "<tr><td>" << a->first << "</td><td>" << a->second << "</td>";
+                                               data << "<td>" << c->GetOppedUsers()->size() << "</td>";
+                                               data << "<td>" << c->GetHalfoppedUsers()->size() << "</td>";
+                                               data << "<td>" << c->GetVoicedUsers()->size() << "</td>";
+                                               data << "<td>" << c->topic << "</td>";
+                                               data << "</tr>";
+                                       }
+                               }
+
+                               data << "</table>";
+                               data << "</div>";
+
+
+
+
+
+                               data << "<div class='validion'>";
+                               data << "<p><a href='http://validator.w3.org/check?uri=referer'><img src='http://www.w3.org/Icons/valid-xhtml11' alt='Valid XHTML 1.1' height='31' width='88' /></a></p>";
+                               data << "</div>";
+                               
+                               data << "</body>";
+                               data << "</html>";
+
+                               /* Send the document back to m_httpd */
+                               HTTPDocument response(http->sock, &data, 200, "X-Powered-By: m_http_stats.so\r\nContent-Type: text/html; charset=iso-8859-1\r\n");
+                               Request req((char*)&response, (Module*)this, event->GetSource());
+                               req.Send();
+                       }
+               }
+       }
+
+       void OnChannelDelete(chanrec* chan)
+       {
+               StatsIter a = sh->find(chan->name);
+               if (a != sh->end())
+               {
+                       sh->erase(a);
+               }
+               this->changed = true;
+       }
+
+       void OnUserJoin(userrec* user, chanrec* channel, bool &silent)
+       {
+               StatsIter a = sh->find(channel->name);
+               if (a != sh->end())
+               {
+                       a->second++;
+               }
+               else
+               {
+                       irc::string name = channel->name;
+                       sh->insert(std::pair<irc::string,int>(name,1));
+               }
+               this->changed = true;
+       }
+
+       void OnUserPart(userrec* user, chanrec* channel, const std::string &partmessage, bool &silent)
+       {
+               StatsIter a = sh->find(channel->name);
+               if (a != sh->end())
+               {
+                       a->second--;
+               }
+               this->changed = true;
+       }
+
+       void OnUserQuit(userrec* user, const std::string &message, const std::string &oper_message)
+       {
+               for (UCListIter v = user->chans.begin(); v != user->chans.end(); v++)
+               {
+                       chanrec* c = v->first;
+                       StatsIter a = sh->find(c->name);
+                       if (a != sh->end())
+                       {
+                               a->second--;
+                       }
+               }
+               this->changed = true;
+       }
+
+       char* OnRequest(Request* request)
+       {
+               return NULL;
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnEvent] = List[I_OnRequest] = List[I_OnChannelDelete] = List[I_OnUserJoin] = List[I_OnUserPart] = List[I_OnUserQuit] = 1;
+       }
+
+       virtual ~ModuleHttpStats()
+       {
+               delete sh;
+               delete so;
+       }
+
+       virtual Version GetVersion()
+       {
+               return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION);
+       }
+};
+
+MODULE_INIT(ModuleHttpStats)
index bf71f81898eedbcc71e75e1288877138651cde49..732c2eaee99b186c128f5b521815caa22bdee5cd 100644 (file)
@@ -1 +1,326 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r\r/* $ModDesc: Provides support for RFC 1413 ident lookups */\r\r// Version 1.5.0.0 - Updated to use InspSocket, faster and neater.\r\r/** Handles RFC1413 ident connections to users\r */\rclass RFC1413 : public InspSocket\r{\r protected:\r  socklen_t uslen;         // length of our port number\r  socklen_t themlen;       // length of their port number\r        char ident_request[128]; // buffer used to make up the request string\r public:\r\r        userrec* u;              // user record that the lookup is associated with\r     int ufd;\r\r      RFC1413(InspIRCd* SI, userrec* user, int maxtime, const std::string &bindto) : InspSocket(SI, user->GetIPString(), 113, false, maxtime, bindto), u(user)\r       {\r              ufd = user->GetFd();\r   }\r\r     virtual void OnTimeout()\r       {\r              // When we timeout, the connection failed within the allowed timeframe,\r                // so we just display a notice, and tidy off the ident_data.\r           if (u && (Instance->SE->GetRef(ufd) == u))\r             {\r                      u->Shrink("ident_data");\r                       Instance->next_call = Instance->Time();\r                }\r      }\r\r     virtual bool OnDataReady()\r     {\r              char* ibuf = this->Read();\r             if (ibuf)\r              {\r                      char* savept;\r                  char* section = strtok_r(ibuf,":",&savept);\r                    while (section)\r                        {\r                              if (strstr(section,"USERID"))\r                          {\r                                      section = strtok_r(NULL,":",&savept);\r                                  if (section)\r                                   {\r                                              // ID type, usually UNIX or OTHER... we dont want it, so read the next token\r                                           section = strtok_r(NULL,":",&savept);\r                                          if (section)\r                                           {\r                                                      while (*section == ' ') section++; // strip leading spaces\r                                                     for (char* j = section; *j; j++)\r                                                       if ((*j < 33) || (*j > 126))\r                                                           *j = '\0'; // truncate at invalid chars\r                                                        if (*section)\r                                                  {\r                                                              if (u && (Instance->SE->GetRef(ufd) == u))\r                                                             {\r                                                                      if (this->Instance->IsIdent(section))\r                                                                  {\r                                                                              u->Extend("IDENT", new std::string(std::string(section) + "," + std::string(u->ident)));\r                                                                               strlcpy(u->ident,section,IDENTMAX);\r                                                                            u->WriteServ("NOTICE "+std::string(u->nick)+" :*** Found your ident: "+std::string(u->ident));\r                                                                 }\r                                                              }\r                                                      }\r                                                      return false;\r                                          }\r                                      }\r                              }\r                              section = strtok_r(NULL,":",&savept);\r                  }\r              }\r              return false;\r  }\r\r     virtual void OnClose()\r {\r              // tidy up after ourselves when the connection is done.\r                // We receive this event straight after a timeout, too.\r                //\r             //\r             // OK, now listen up. The weird looking check here is\r          // REQUIRED. Don't try and optimize it away.\r           //\r             // When a socket is closed, it is not immediately removed\r              // from the socket list, there can be a short delay\r            // before it is culled from the list. This means that\r          // without this check, there is a chance that a user\r           // may not exist when we come to ::Shrink them, which\r          // results in a segfault. The value of "u" may not\r             // always be NULL at this point, so, what we do is\r             // check against the fd_ref_table, to see if (1) the user\r              // exists, and (2) its the SAME user, on the same file\r         // descriptor that they were when the lookup began.\r            //\r             // Fixes issue reported by webs, 7 Jun 2006\r            if (u && (Instance->SE->GetRef(ufd) == u))\r             {\r                      Instance->next_call = Instance->Time();\r                        u->Shrink("ident_data");\r               }\r      }\r\r     virtual void OnError(InspSocketError e)\r        {\r              if (u && (Instance->SE->GetRef(ufd) == u))\r             {\r                      if (*u->ident == '~')\r                          u->WriteServ("NOTICE "+std::string(u->nick)+" :*** Could not find your ident, using "+std::string(u->ident)+" instead.");\r\r                     Instance->next_call = Instance->Time();\r                        u->Shrink("ident_data");\r               }\r      }\r\r     virtual bool OnConnected()\r     {\r              if (u && (Instance->SE->GetRef(ufd) == u))\r             {\r                      sockaddr* sock_us = new sockaddr[2];\r                   sockaddr* sock_them = new sockaddr[2];\r                 bool success = false;\r                  uslen = sizeof(sockaddr_in);\r                   themlen = sizeof(sockaddr_in);\r#ifdef IPV6\r                     if (this->u->GetProtocolFamily() == AF_INET6)\r                  {\r                              themlen = sizeof(sockaddr_in6);\r                                uslen = sizeof(sockaddr_in6);\r                  }\r#endif\r                       success = ((getsockname(this->u->GetFd(),sock_us,&uslen) || getpeername(this->u->GetFd(), sock_them, &themlen)));\r                      if (success)\r                   {\r                              delete[] sock_us;\r                              delete[] sock_them;\r                            return false;\r                  }\r                      else\r                   {\r                              // send the request in the following format: theirsocket,oursocket\r#ifdef IPV6\r                         if (this->u->GetProtocolFamily() == AF_INET6)\r                                  snprintf(ident_request,127,"%d,%d\r\n",ntohs(((sockaddr_in6*)sock_them)->sin6_port),ntohs(((sockaddr_in6*)sock_us)->sin6_port));\r                               else\r#endif\r                            snprintf(ident_request,127,"%d,%d\r\n",ntohs(((sockaddr_in*)sock_them)->sin_port),ntohs(((sockaddr_in*)sock_us)->sin_port));\r                           this->Write(ident_request);\r                            delete[] sock_us;\r                              delete[] sock_them;\r                            return true;\r                   }\r              }\r              else\r           {\r                      Instance->next_call = Instance->Time();\r                        return true;\r           }\r      }\r};\r\rclass ModuleIdent : public Module\r{\r\r     ConfigReader* Conf;\r    int IdentTimeout;\r      std::string PortBind;\r\r public:\r        void ReadSettings()\r    {\r              Conf = new ConfigReader(ServerInstance);\r               IdentTimeout = Conf->ReadInteger("ident", "timeout", 0, true);\r         PortBind = Conf->ReadValue("ident", "bind", 0);\r                if (!IdentTimeout)\r                     IdentTimeout = 1;\r              DELETE(Conf);\r  }\r\r     ModuleIdent(InspIRCd* Me)\r              : Module(Me)\r   {\r\r             ReadSettings();\r        }\r\r     void Implements(char* List)\r    {\r              List[I_OnCleanup] = List[I_OnRehash] = List[I_OnUserRegister] = List[I_OnCheckReady] = List[I_OnUserDisconnect] = 1;\r   }\r\r     void OnSyncUserMetaData(userrec* user, Module* proto,void* opaque, const std::string &extname, bool displayable)\r       {\r              if ((displayable) && (extname == "IDENT"))\r             {\r                      std::string* ident;\r                    if (GetExt("IDENT", ident))\r                            proto->ProtoSendMetaData(opaque, TYPE_USER, user, extname, *ident);\r            }\r      }\r\r\r    virtual void OnRehash(userrec* user, const std::string &parameter)\r     {\r              ReadSettings();\r        }\r\r     virtual int OnUserRegister(userrec* user)\r      {\r              /*\r              * when the new user connects, before they authenticate with USER/NICK/PASS, we do\r              * their ident lookup. We do this by instantiating an object of type RFC1413, which\r             * is derived from InspSocket, and inserting it into the socket engine using the\r                * Server::AddSocket() call.\r            */\r            char newident[MAXBUF];\r         strcpy(newident,"~");\r          strlcat(newident,user->ident,IDENTMAX);\r                strlcpy(user->ident,newident,IDENTMAX);\r                \r\r              user->WriteServ("NOTICE "+std::string(user->nick)+" :*** Looking up your ident...");\r           RFC1413* ident = new RFC1413(ServerInstance, user, IdentTimeout, PortBind);\r            if ((ident->GetState() == I_CONNECTING) || (ident->GetState() == I_CONNECTED))\r         {\r                      user->Extend("ident_data", (char*)ident);\r              }\r              else\r           {\r                      user->WriteServ("NOTICE "+std::string(user->nick)+" :*** Could not find your ident, using "+std::string(user->ident)+" instead.");\r                     ServerInstance->next_call = ServerInstance->Time();\r            }\r              return 0;\r      }\r\r     virtual bool OnCheckReady(userrec* user)\r       {\r              /*\r              * The socket engine will clean up their ident request for us when it completes,\r                * either due to timeout or due to closing, so, we just hold them until they dont\r               * have an ident field any more.\r                */\r            RFC1413* ident;\r                return (!user->GetExt("ident_data", ident));\r   }\r\r     virtual void OnCleanup(int target_type, void* item)\r    {\r              if (target_type == TYPE_USER)\r          {\r                      userrec* user = (userrec*)item;\r                        RFC1413* ident;\r                        std::string* identstr;\r                 if (user->GetExt("ident_data", ident))\r                 {\r                              // FIX: If the user record is deleted, the socket wont be removed\r                              // immediately so there is chance of the socket trying to write to\r                             // a user which has now vanished! To prevent this, set ident::u\r                                // to NULL and check it so that we dont write users who have gone away.\r                                ident->u = NULL;\r                               ServerInstance->SE->DelFd(ident);\r                              //delete ident;\r                        }\r                      if (user->GetExt("IDENT", identstr))\r                   {\r                              delete identstr;\r                       }\r              }\r      }\r\r     virtual void OnUserDisconnect(userrec* user)\r   {\r              /*\r              * when the user quits tidy up any ident lookup they have pending to keep things tidy.\r          * When we call RemoveSocket, the abstractions tied into the system evnetually work their\r               * way to RFC1459::OnClose(), which shrinks off the ident_data for us, so we dont need\r          * to do it here. If we don't tidy this up, there may still be lingering idents for users\r               * who have quit, as class RFC1459 is only loosely bound to userrec* via a pair of pointers\r             * and this would leave at least one of the invalid ;)\r          */\r            RFC1413* ident;\r                std::string* identstr;\r         if (user->GetExt("ident_data", ident))\r         {\r                      ident->u = NULL;\r                       ServerInstance->SE->DelFd(ident);\r              }\r              if (user->GetExt("IDENT", identstr))\r           {\r                      delete identstr;\r               }\r      }\r\r     virtual ~ModuleIdent()\r {\r              ServerInstance->next_call = ServerInstance->Time();\r    }\r\r     virtual Version GetVersion()\r   {\r              return Version(1,1,0,0,VF_VENDOR,API_VERSION);\r }\r\r};\r\rMODULE_INIT(ModuleIdent)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+
+/* $ModDesc: Provides support for RFC 1413 ident lookups */
+
+// Version 1.5.0.0 - Updated to use InspSocket, faster and neater.
+
+/** Handles RFC1413 ident connections to users
+ */
+class RFC1413 : public InspSocket
+{
+ protected:
+       socklen_t uslen;         // length of our port number
+       socklen_t themlen;       // length of their port number
+       char ident_request[128]; // buffer used to make up the request string
+ public:
+
+       userrec* u;              // user record that the lookup is associated with
+       int ufd;
+
+       RFC1413(InspIRCd* SI, userrec* user, int maxtime, const std::string &bindto) : InspSocket(SI, user->GetIPString(), 113, false, maxtime, bindto), u(user)
+       {
+               ufd = user->GetFd();
+       }
+
+       virtual void OnTimeout()
+       {
+               // When we timeout, the connection failed within the allowed timeframe,
+               // so we just display a notice, and tidy off the ident_data.
+               if (u && (Instance->SE->GetRef(ufd) == u))
+               {
+                       u->Shrink("ident_data");
+                       Instance->next_call = Instance->Time();
+               }
+       }
+
+       virtual bool OnDataReady()
+       {
+               char* ibuf = this->Read();
+               if (ibuf)
+               {
+                       char* savept;
+                       char* section = strtok_r(ibuf,":",&savept);
+                       while (section)
+                       {
+                               if (strstr(section,"USERID"))
+                               {
+                                       section = strtok_r(NULL,":",&savept);
+                                       if (section)
+                                       {
+                                               // ID type, usually UNIX or OTHER... we dont want it, so read the next token
+                                               section = strtok_r(NULL,":",&savept);
+                                               if (section)
+                                               {
+                                                       while (*section == ' ') section++; // strip leading spaces
+                                                       for (char* j = section; *j; j++)
+                                                       if ((*j < 33) || (*j > 126))
+                                                               *j = '\0'; // truncate at invalid chars
+                                                       if (*section)
+                                                       {
+                                                               if (u && (Instance->SE->GetRef(ufd) == u))
+                                                               {
+                                                                       if (this->Instance->IsIdent(section))
+                                                                       {
+                                                                               u->Extend("IDENT", new std::string(std::string(section) + "," + std::string(u->ident)));
+                                                                               strlcpy(u->ident,section,IDENTMAX);
+                                                                               u->WriteServ("NOTICE "+std::string(u->nick)+" :*** Found your ident: "+std::string(u->ident));
+                                                                       }
+                                                               }
+                                                       }
+                                                       return false;
+                                               }
+                                       }
+                               }
+                               section = strtok_r(NULL,":",&savept);
+                       }
+               }
+               return false;
+       }
+
+       virtual void OnClose()
+       {
+               // tidy up after ourselves when the connection is done.
+               // We receive this event straight after a timeout, too.
+               //
+               //
+               // OK, now listen up. The weird looking check here is
+               // REQUIRED. Don't try and optimize it away.
+               //
+               // When a socket is closed, it is not immediately removed
+               // from the socket list, there can be a short delay
+               // before it is culled from the list. This means that
+               // without this check, there is a chance that a user
+               // may not exist when we come to ::Shrink them, which
+               // results in a segfault. The value of "u" may not
+               // always be NULL at this point, so, what we do is
+               // check against the fd_ref_table, to see if (1) the user
+               // exists, and (2) its the SAME user, on the same file
+               // descriptor that they were when the lookup began.
+               //
+               // Fixes issue reported by webs, 7 Jun 2006
+               if (u && (Instance->SE->GetRef(ufd) == u))
+               {
+                       Instance->next_call = Instance->Time();
+                       u->Shrink("ident_data");
+               }
+       }
+
+       virtual void OnError(InspSocketError e)
+       {
+               if (u && (Instance->SE->GetRef(ufd) == u))
+               {
+                       if (*u->ident == '~')
+                               u->WriteServ("NOTICE "+std::string(u->nick)+" :*** Could not find your ident, using "+std::string(u->ident)+" instead.");
+
+                       Instance->next_call = Instance->Time();
+                       u->Shrink("ident_data");
+               }
+       }
+
+       virtual bool OnConnected()
+       {
+               if (u && (Instance->SE->GetRef(ufd) == u))
+               {
+                       sockaddr* sock_us = new sockaddr[2];
+                       sockaddr* sock_them = new sockaddr[2];
+                       bool success = false;
+                       uslen = sizeof(sockaddr_in);
+                       themlen = sizeof(sockaddr_in);
+#ifdef IPV6
+                       if (this->u->GetProtocolFamily() == AF_INET6)
+                       {
+                               themlen = sizeof(sockaddr_in6);
+                               uslen = sizeof(sockaddr_in6);
+                       }
+#endif
+                       success = ((getsockname(this->u->GetFd(),sock_us,&uslen) || getpeername(this->u->GetFd(), sock_them, &themlen)));
+                       if (success)
+                       {
+                               delete[] sock_us;
+                               delete[] sock_them;
+                               return false;
+                       }
+                       else
+                       {
+                               // send the request in the following format: theirsocket,oursocket
+#ifdef IPV6
+                               if (this->u->GetProtocolFamily() == AF_INET6)
+                                       snprintf(ident_request,127,"%d,%d\r\n",ntohs(((sockaddr_in6*)sock_them)->sin6_port),ntohs(((sockaddr_in6*)sock_us)->sin6_port));
+                               else
+#endif
+                               snprintf(ident_request,127,"%d,%d\r\n",ntohs(((sockaddr_in*)sock_them)->sin_port),ntohs(((sockaddr_in*)sock_us)->sin_port));
+                               this->Write(ident_request);
+                               delete[] sock_us;
+                               delete[] sock_them;
+                               return true;
+                       }
+               }
+               else
+               {
+                       Instance->next_call = Instance->Time();
+                       return true;
+               }
+       }
+};
+
+class ModuleIdent : public Module
+{
+
+       ConfigReader* Conf;
+       int IdentTimeout;
+       std::string PortBind;
+
+ public:
+       void ReadSettings()
+       {
+               Conf = new ConfigReader(ServerInstance);
+               IdentTimeout = Conf->ReadInteger("ident", "timeout", 0, true);
+               PortBind = Conf->ReadValue("ident", "bind", 0);
+               if (!IdentTimeout)
+                       IdentTimeout = 1;
+               DELETE(Conf);
+       }
+
+       ModuleIdent(InspIRCd* Me)
+               : Module(Me)
+       {
+
+               ReadSettings();
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnCleanup] = List[I_OnRehash] = List[I_OnUserRegister] = List[I_OnCheckReady] = List[I_OnUserDisconnect] = 1;
+       }
+
+       void OnSyncUserMetaData(userrec* user, Module* proto,void* opaque, const std::string &extname, bool displayable)
+       {
+               if ((displayable) && (extname == "IDENT"))
+               {
+                       std::string* ident;
+                       if (GetExt("IDENT", ident))
+                               proto->ProtoSendMetaData(opaque, TYPE_USER, user, extname, *ident);
+               }
+       }
+
+
+       virtual void OnRehash(userrec* user, const std::string &parameter)
+       {
+               ReadSettings();
+       }
+
+       virtual int OnUserRegister(userrec* user)
+       {
+               /*
+                * when the new user connects, before they authenticate with USER/NICK/PASS, we do
+                * their ident lookup. We do this by instantiating an object of type RFC1413, which
+                * is derived from InspSocket, and inserting it into the socket engine using the
+                * Server::AddSocket() call.
+                */
+               char newident[MAXBUF];
+               strcpy(newident,"~");
+               strlcat(newident,user->ident,IDENTMAX);
+               strlcpy(user->ident,newident,IDENTMAX);
+               
+
+               user->WriteServ("NOTICE "+std::string(user->nick)+" :*** Looking up your ident...");
+               RFC1413* ident = new RFC1413(ServerInstance, user, IdentTimeout, PortBind);
+               if ((ident->GetState() == I_CONNECTING) || (ident->GetState() == I_CONNECTED))
+               {
+                       user->Extend("ident_data", (char*)ident);
+               }
+               else
+               {
+                       user->WriteServ("NOTICE "+std::string(user->nick)+" :*** Could not find your ident, using "+std::string(user->ident)+" instead.");
+                       ServerInstance->next_call = ServerInstance->Time();
+               }
+               return 0;
+       }
+
+       virtual bool OnCheckReady(userrec* user)
+       {
+               /*
+                * The socket engine will clean up their ident request for us when it completes,
+                * either due to timeout or due to closing, so, we just hold them until they dont
+                * have an ident field any more.
+                */
+               RFC1413* ident;
+               return (!user->GetExt("ident_data", ident));
+       }
+
+       virtual void OnCleanup(int target_type, void* item)
+       {
+               if (target_type == TYPE_USER)
+               {
+                       userrec* user = (userrec*)item;
+                       RFC1413* ident;
+                       std::string* identstr;
+                       if (user->GetExt("ident_data", ident))
+                       {
+                               // FIX: If the user record is deleted, the socket wont be removed
+                               // immediately so there is chance of the socket trying to write to
+                               // a user which has now vanished! To prevent this, set ident::u
+                               // to NULL and check it so that we dont write users who have gone away.
+                               ident->u = NULL;
+                               ServerInstance->SE->DelFd(ident);
+                               //delete ident;
+                       }
+                       if (user->GetExt("IDENT", identstr))
+                       {
+                               delete identstr;
+                       }
+               }
+       }
+
+       virtual void OnUserDisconnect(userrec* user)
+       {
+               /*
+                * when the user quits tidy up any ident lookup they have pending to keep things tidy.
+                * When we call RemoveSocket, the abstractions tied into the system evnetually work their
+                * way to RFC1459::OnClose(), which shrinks off the ident_data for us, so we dont need
+                * to do it here. If we don't tidy this up, there may still be lingering idents for users
+                * who have quit, as class RFC1459 is only loosely bound to userrec* via a pair of pointers
+                * and this would leave at least one of the invalid ;)
+                */
+               RFC1413* ident;
+               std::string* identstr;
+               if (user->GetExt("ident_data", ident))
+               {
+                       ident->u = NULL;
+                       ServerInstance->SE->DelFd(ident);
+               }
+               if (user->GetExt("IDENT", identstr))
+               {
+                       delete identstr;
+               }
+       }
+
+       virtual ~ModuleIdent()
+       {
+               ServerInstance->next_call = ServerInstance->Time();
+       }
+
+       virtual Version GetVersion()
+       {
+               return Version(1,1,0,0,VF_VENDOR,API_VERSION);
+       }
+
+};
+
+MODULE_INIT(ModuleIdent)
index ce2f2062bff2de795bb85ecf918a6ad6f4678fc4..e1fb88ca02946827536ac6b364ab1234310fbf27 100644 (file)
@@ -1 +1,277 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r#include <stdarg.h>\r\r/* $ModDesc: Allows for opered clients to join channels without being seen, similar to unreal 3.1 +I mode */\r\rstatic ConfigReader* conf;\r\rclass QuietOper : public VisData\r{\r public:\r    QuietOper()\r    {\r      }\r\r     virtual ~QuietOper()\r   {\r      }\r\r     virtual bool VisibleTo(userrec* user)\r  {\r              return IS_OPER(user);\r  }\r};\r\r\rclass InvisibleMode : public ModeHandler\r{\r      QuietOper* qo;\r public:\r        InvisibleMode(InspIRCd* Instance) : ModeHandler(Instance, 'Q', 0, 0, false, MODETYPE_USER, true)\r       {\r              qo = new QuietOper();\r  }\r\r     ~InvisibleMode()\r       {\r              for (user_hash::iterator i = ServerInstance->clientlist->begin(); i != ServerInstance->clientlist->end(); i++)\r                 if (i->second->Visibility == qo)\r                               i->second->Visibility = NULL;\r          delete qo;\r     }\r\r     ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)\r {\r              if (source != dest)\r                    return MODEACTION_DENY;\r\r               if (dest->IsModeSet('Q') != adding)\r            {\r                      bool ok = false;\r\r                      for (int j = 0; j < conf->Enumerate("type"); j++)\r                      {\r                              std::string opertype = conf->ReadValue("type","name",j);\r                               if (opertype == source->oper)\r                          {\r                                      ok = conf->ReadFlag("type", "canquiet", j);\r                                    break;\r                         }\r                      }\r\r                     if (!ok)\r                       {\r                              source->WriteServ("481 %s :Permission Denied - You do not have access to become invisible via user mode +Q", source->nick);\r                            return MODEACTION_DENY;\r                        }\r\r                     dest->SetMode('Q', adding);\r\r                   /* Set visibility handler object */\r                    dest->Visibility = adding ? qo : NULL;\r\r                        /* User appears to vanish or appear from nowhere */\r                    for (UCListIter f = dest->chans.begin(); f != dest->chans.end(); f++)\r                  {\r                              CUList *ulist = f->first->GetUsers();\r                          char tb[MAXBUF];\r\r                              snprintf(tb,MAXBUF,":%s %s %s", dest->GetFullHost(), adding ? "PART" : "JOIN", f->first->name);\r                                std::string out = tb;\r                          std::string n = this->ServerInstance->Modes->ModeString(dest, f->first);\r\r                              for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)\r                              {\r                                      /* User only appears to vanish for non-opers */\r                                        if (IS_LOCAL(i->first) && !IS_OPER(i->first))\r                                  {\r                                              i->first->Write(out);\r                                          if (!n.empty() && !adding)\r                                                     i->first->WriteServ("MODE %s +%s", f->first->name, n.c_str());\r                                 }\r                              }\r\r                             ServerInstance->WriteOpers("*** \2NOTICE\2: Oper %s has become %svisible (%sQ)", dest->GetFullHost(), adding ? "in" : "", adding ? "+" : "-");\r                 }\r                      return MODEACTION_ALLOW;\r               }\r              else\r           {\r                      return MODEACTION_DENY;\r                }\r      }\r};\r\rclass InvisibleDeOper : public ModeWatcher\r{\r private:\r   InspIRCd* Srv;\r public:\r        InvisibleDeOper(InspIRCd* Instance) : ModeWatcher(Instance, 'o', MODETYPE_USER), Srv(Instance)\r {\r      }\r\r     bool BeforeMode(userrec* source, userrec* dest, chanrec* channel, std::string &param, bool adding, ModeType type)\r      {\r              /* Users who are opers and have +Q get their +Q removed when they deoper */\r            if ((!adding) && (dest->IsModeSet('Q')))\r               {\r                      const char* newmodes[] = { dest->nick, "-Q" };\r                 ServerInstance->Modes->Process(newmodes, 2, source, true);\r             }\r              return true;\r   }\r};\r\r\rclass ModuleInvisible : public Module\r{\r private:\r       InvisibleMode* qm;\r     InvisibleDeOper* ido;\r public:\r ModuleInvisible(InspIRCd* Me)\r          : Module(Me)\r   {\r              conf = new ConfigReader(ServerInstance);\r               qm = new InvisibleMode(ServerInstance);\r                if (!ServerInstance->AddMode(qm, 'Q'))\r                 throw ModuleException("Could not add new modes!");\r             ido = new InvisibleDeOper(ServerInstance);\r             if (!ServerInstance->AddModeWatcher(ido))\r                      throw ModuleException("Could not add new mode watcher on usermode +o!");\r       }\r\r     virtual ~ModuleInvisible()\r     {\r              ServerInstance->Modes->DelMode(qm);\r            ServerInstance->Modes->DelModeWatcher(ido);\r            DELETE(qm);\r            DELETE(ido);\r           DELETE(conf);\r  }\r\r     virtual Version GetVersion()\r   {\r              return Version(1, 1, 0, 0, VF_COMMON | VF_VENDOR, API_VERSION);\r        }\r\r     void Implements(char* List)\r    {\r              List[I_OnUserPreMessage] = List[I_OnUserPreNotice] = List[I_OnUserJoin] = List[I_OnUserPart] = List[I_OnUserQuit] = List[I_OnRehash] = 1;\r      }\r      \r       virtual void OnUserJoin(userrec* user, chanrec* channel, bool &silent)\r {\r              if (user->IsModeSet('Q'))\r              {\r                      silent = true;\r                 /* Because we silenced the event, make sure it reaches the user whos joining (but only them of course) */\r                      this->WriteCommonFrom(user, channel, "JOIN %s", channel->name);\r                        ServerInstance->WriteOpers("*** \2NOTICE\2: Oper %s has joined %s invisibly (+Q)", user->GetFullHost(), channel->name);\r                }\r      }\r\r     virtual void OnRehash(userrec* user, const std::string &parameter)\r     {\r              DELETE(conf);\r          conf = new ConfigReader(ServerInstance);\r       }\r\r     void OnUserPart(userrec* user, chanrec* channel, const std::string &partmessage, bool &silent)\r {\r              if (user->IsModeSet('Q'))\r              {\r                      silent = true;\r                 /* Because we silenced the event, make sure it reaches the user whos leaving (but only them of course) */\r                      this->WriteCommonFrom(user, channel, "PART %s%s%s", channel->name,\r                                     partmessage.empty() ? "" : " :",\r                                       partmessage.empty() ? "" : partmessage.c_str());\r               }\r      }\r\r     void OnUserQuit(userrec* user, const std::string &reason, const std::string &oper_message)\r     {\r              if (user->IsModeSet('Q'))\r              {\r                      command_t* parthandler = ServerInstance->Parser->GetHandler("PART");\r                   std::vector<std::string> to_leave;\r                     const char* parameters[2];\r                     if (parthandler)\r                       {\r                              for (UCListIter f = user->chans.begin(); f != user->chans.end(); f++)\r                                          to_leave.push_back(f->first->name);\r                            /* We cant do this neatly in one loop, as we are modifying the map we are iterating */\r                         for (std::vector<std::string>::iterator n = to_leave.begin(); n != to_leave.end(); n++)\r                                {\r                                      parameters[0] = n->c_str();\r                                    /* This triggers our OnUserPart, above, making the PART silent */\r                                      parthandler->Handle(parameters, 1, user);\r                              }\r                      }\r              }\r      }\r\r     /* No privmsg response when hiding - submitted by Eric at neowin */\r    virtual int OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)\r     {\r              if ((target_type == TYPE_USER) && (IS_LOCAL(user)))\r            {\r                      userrec* target = (userrec*)dest;\r                      if(target->IsModeSet('Q') && !*user->oper)\r                     {\r                              user->WriteServ("401 %s %s :No such nick/channel",user->nick, target->nick);\r                           return 1;\r                      }\r              }\r              return 0;\r      }\r      \r       virtual int OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)\r    {\r              return OnUserPreNotice(user, dest, target_type, text, status, exempt_list);\r    }\r\r     /* Fix by Eric @ neowin.net, thanks :) -- Brain */\r     void WriteCommonFrom(userrec *user, chanrec* channel, const char* text, ...)\r   {\r              va_list argsPtr;\r               char textbuffer[MAXBUF];\r               char tb[MAXBUF];\r       \r               va_start(argsPtr, text);\r               vsnprintf(textbuffer, MAXBUF, text, argsPtr);\r          va_end(argsPtr);\r               snprintf(tb,MAXBUF,":%s %s",user->GetFullHost(),textbuffer);\r           \r               CUList *ulist = channel->GetUsers();\r           \r               for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)\r              {\r                      /* User only appears to vanish for non-opers */\r                        if (IS_LOCAL(i->first) && IS_OPER(i->first))\r                   {\r                              i->first->Write(std::string(tb));\r                      }\r              }\r      }\r\r};\r\rMODULE_INIT(ModuleInvisible)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+#include <stdarg.h>
+
+/* $ModDesc: Allows for opered clients to join channels without being seen, similar to unreal 3.1 +I mode */
+
+static ConfigReader* conf;
+
+class QuietOper : public VisData
+{
+ public:
+       QuietOper()
+       {
+       }
+
+       virtual ~QuietOper()
+       {
+       }
+
+       virtual bool VisibleTo(userrec* user)
+       {
+               return IS_OPER(user);
+       }
+};
+
+
+class InvisibleMode : public ModeHandler
+{
+       QuietOper* qo;
+ public:
+       InvisibleMode(InspIRCd* Instance) : ModeHandler(Instance, 'Q', 0, 0, false, MODETYPE_USER, true)
+       {
+               qo = new QuietOper();
+       }
+
+       ~InvisibleMode()
+       {
+               for (user_hash::iterator i = ServerInstance->clientlist->begin(); i != ServerInstance->clientlist->end(); i++)
+                       if (i->second->Visibility == qo)
+                               i->second->Visibility = NULL;
+               delete qo;
+       }
+
+       ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)
+       {
+               if (source != dest)
+                       return MODEACTION_DENY;
+
+               if (dest->IsModeSet('Q') != adding)
+               {
+                       bool ok = false;
+
+                       for (int j = 0; j < conf->Enumerate("type"); j++)
+                       {
+                               std::string opertype = conf->ReadValue("type","name",j);
+                               if (opertype == source->oper)
+                               {
+                                       ok = conf->ReadFlag("type", "canquiet", j);
+                                       break;
+                               }
+                       }
+
+                       if (!ok)
+                       {
+                               source->WriteServ("481 %s :Permission Denied - You do not have access to become invisible via user mode +Q", source->nick);
+                               return MODEACTION_DENY;
+                       }
+
+                       dest->SetMode('Q', adding);
+
+                       /* Set visibility handler object */
+                       dest->Visibility = adding ? qo : NULL;
+
+                       /* User appears to vanish or appear from nowhere */
+                       for (UCListIter f = dest->chans.begin(); f != dest->chans.end(); f++)
+                       {
+                               CUList *ulist = f->first->GetUsers();
+                               char tb[MAXBUF];
+
+                               snprintf(tb,MAXBUF,":%s %s %s", dest->GetFullHost(), adding ? "PART" : "JOIN", f->first->name);
+                               std::string out = tb;
+                               std::string n = this->ServerInstance->Modes->ModeString(dest, f->first);
+
+                               for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
+                               {
+                                       /* User only appears to vanish for non-opers */
+                                       if (IS_LOCAL(i->first) && !IS_OPER(i->first))
+                                       {
+                                               i->first->Write(out);
+                                               if (!n.empty() && !adding)
+                                                       i->first->WriteServ("MODE %s +%s", f->first->name, n.c_str());
+                                       }
+                               }
+
+                               ServerInstance->WriteOpers("*** \2NOTICE\2: Oper %s has become %svisible (%sQ)", dest->GetFullHost(), adding ? "in" : "", adding ? "+" : "-");
+                       }
+                       return MODEACTION_ALLOW;
+               }
+               else
+               {
+                       return MODEACTION_DENY;
+               }
+       }
+};
+
+class InvisibleDeOper : public ModeWatcher
+{
+ private:
+       InspIRCd* Srv;
+ public:
+       InvisibleDeOper(InspIRCd* Instance) : ModeWatcher(Instance, 'o', MODETYPE_USER), Srv(Instance)
+       {
+       }
+
+       bool BeforeMode(userrec* source, userrec* dest, chanrec* channel, std::string &param, bool adding, ModeType type)
+       {
+               /* Users who are opers and have +Q get their +Q removed when they deoper */
+               if ((!adding) && (dest->IsModeSet('Q')))
+               {
+                       const char* newmodes[] = { dest->nick, "-Q" };
+                       ServerInstance->Modes->Process(newmodes, 2, source, true);
+               }
+               return true;
+       }
+};
+
+
+class ModuleInvisible : public Module
+{
+ private:
+       InvisibleMode* qm;
+       InvisibleDeOper* ido;
+ public:
+       ModuleInvisible(InspIRCd* Me)
+               : Module(Me)
+       {
+               conf = new ConfigReader(ServerInstance);
+               qm = new InvisibleMode(ServerInstance);
+               if (!ServerInstance->AddMode(qm, 'Q'))
+                       throw ModuleException("Could not add new modes!");
+               ido = new InvisibleDeOper(ServerInstance);
+               if (!ServerInstance->AddModeWatcher(ido))
+                       throw ModuleException("Could not add new mode watcher on usermode +o!");
+       }
+
+       virtual ~ModuleInvisible()
+       {
+               ServerInstance->Modes->DelMode(qm);
+               ServerInstance->Modes->DelModeWatcher(ido);
+               DELETE(qm);
+               DELETE(ido);
+               DELETE(conf);
+       }
+
+       virtual Version GetVersion()
+       {
+               return Version(1, 1, 0, 0, VF_COMMON | VF_VENDOR, API_VERSION);
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnUserPreMessage] = List[I_OnUserPreNotice] = List[I_OnUserJoin] = List[I_OnUserPart] = List[I_OnUserQuit] = List[I_OnRehash] = 1;
+       }
+       
+       virtual void OnUserJoin(userrec* user, chanrec* channel, bool &silent)
+       {
+               if (user->IsModeSet('Q'))
+               {
+                       silent = true;
+                       /* Because we silenced the event, make sure it reaches the user whos joining (but only them of course) */
+                       this->WriteCommonFrom(user, channel, "JOIN %s", channel->name);
+                       ServerInstance->WriteOpers("*** \2NOTICE\2: Oper %s has joined %s invisibly (+Q)", user->GetFullHost(), channel->name);
+               }
+       }
+
+       virtual void OnRehash(userrec* user, const std::string &parameter)
+       {
+               DELETE(conf);
+               conf = new ConfigReader(ServerInstance);
+       }
+
+       void OnUserPart(userrec* user, chanrec* channel, const std::string &partmessage, bool &silent)
+       {
+               if (user->IsModeSet('Q'))
+               {
+                       silent = true;
+                       /* Because we silenced the event, make sure it reaches the user whos leaving (but only them of course) */
+                       this->WriteCommonFrom(user, channel, "PART %s%s%s", channel->name,
+                                       partmessage.empty() ? "" : " :",
+                                       partmessage.empty() ? "" : partmessage.c_str());
+               }
+       }
+
+       void OnUserQuit(userrec* user, const std::string &reason, const std::string &oper_message)
+       {
+               if (user->IsModeSet('Q'))
+               {
+                       command_t* parthandler = ServerInstance->Parser->GetHandler("PART");
+                       std::vector<std::string> to_leave;
+                       const char* parameters[2];
+                       if (parthandler)
+                       {
+                               for (UCListIter f = user->chans.begin(); f != user->chans.end(); f++)
+                                               to_leave.push_back(f->first->name);
+                               /* We cant do this neatly in one loop, as we are modifying the map we are iterating */
+                               for (std::vector<std::string>::iterator n = to_leave.begin(); n != to_leave.end(); n++)
+                               {
+                                       parameters[0] = n->c_str();
+                                       /* This triggers our OnUserPart, above, making the PART silent */
+                                       parthandler->Handle(parameters, 1, user);
+                               }
+                       }
+               }
+       }
+
+       /* No privmsg response when hiding - submitted by Eric at neowin */
+       virtual int OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
+       {
+               if ((target_type == TYPE_USER) && (IS_LOCAL(user)))
+               {
+                       userrec* target = (userrec*)dest;
+                       if(target->IsModeSet('Q') && !*user->oper)
+                       {
+                               user->WriteServ("401 %s %s :No such nick/channel",user->nick, target->nick);
+                               return 1;
+                       }
+               }
+               return 0;
+       }
+       
+       virtual int OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
+       {
+               return OnUserPreNotice(user, dest, target_type, text, status, exempt_list);
+       }
+
+       /* Fix by Eric @ neowin.net, thanks :) -- Brain */
+       void WriteCommonFrom(userrec *user, chanrec* channel, const char* text, ...)
+       {
+               va_list argsPtr;
+               char textbuffer[MAXBUF];
+               char tb[MAXBUF];
+       
+               va_start(argsPtr, text);
+               vsnprintf(textbuffer, MAXBUF, text, argsPtr);
+               va_end(argsPtr);
+               snprintf(tb,MAXBUF,":%s %s",user->GetFullHost(),textbuffer);
+               
+               CUList *ulist = channel->GetUsers();
+               
+               for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
+               {
+                       /* User only appears to vanish for non-opers */
+                       if (IS_LOCAL(i->first) && IS_OPER(i->first))
+                       {
+                               i->first->Write(std::string(tb));
+                       }
+               }
+       }
+
+};
+
+MODULE_INIT(ModuleInvisible)
index e51503b26cff2c801b21c7dc3897c4d46f6c1b6d..b7b9920c596bce62e282a56da8deda7766da13e2 100644 (file)
@@ -1 +1,150 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *        the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r#include "mode.h"\r#include "u_listmode.h"\r\r/* $ModDesc: Provides support for the +I channel mode */\r/* $ModDep: ../../include/u_listmode.h */\r\r/*\r * Written by Om <om@inspircd.org>, April 2005.\r * Based on m_exception, which was originally based on m_chanprotect and m_silence\r *\r * The +I channel mode takes a nick!ident@host, glob patterns allowed,\r * and if a user matches an entry on the +I list then they can join the channel,\r * ignoring if +i is set on the channel\r * Now supports CIDR and IP addresses -- Brain\r */\r\rclass InspIRCd* ServerInstance;\r\r/** Handles channel mode +I\r */\rclass InviteException : public ListModeBase\r{\r public:\r       InviteException(InspIRCd* Instance) : ListModeBase(Instance, 'I', "End of Channel Invite Exception List", "346", "347", true) { }\r};\r\rclass ModuleInviteException : public Module\r{\r    InviteException* ie;\rpublic:\r   ModuleInviteException(InspIRCd* Me) : Module(Me)\r       {\r              ie = new InviteException(ServerInstance);\r              if (!ServerInstance->AddMode(ie, 'I'))\r                 throw ModuleException("Could not add new modes!");\r             ServerInstance->PublishInterface("ChannelBanList", this);\r      }\r\r     virtual void Implements(char* List)\r    {\r              ie->DoImplements(List);\r                List[I_OnRequest] = List[I_On005Numeric] = List[I_OnCheckInvite] = 1;\r  }\r      \r       virtual void On005Numeric(std::string &output)\r {\r              output.append(" INVEX=I");\r     }\r       \r      virtual int OnCheckInvite(userrec* user, chanrec* chan)\r        {\r              if(chan != NULL)\r               {\r                      modelist* list;\r                        chan->GetExt(ie->GetInfoKey(), list);\r                  if (list)\r                      {\r                              char mask[MAXBUF];\r                             snprintf(mask, MAXBUF, "%s!%s@%s", user->nick, user->ident, user->GetIPString());\r                              for (modelist::iterator it = list->begin(); it != list->end(); it++)\r                           {\r                                      if(match(user->GetFullRealHost(), it->mask.c_str()) || match(user->GetFullHost(), it->mask.c_str()) || (match(mask, it->mask.c_str(), true)))\r                                  {\r                                              // They match an entry on the list, so let them in.\r                                            return 1;\r                                      }\r                              }\r                      }\r                      // or if there wasn't a list, there can't be anyone on it, so we don't need to do anything.\r            }\r\r             return 0;               \r       }\r\r     virtual char* OnRequest(Request* request)\r      {\r              ListModeRequest* LM = (ListModeRequest*)request;\r               if (strcmp("LM_CHECKLIST", request->GetId()) == 0)\r             {\r                      modelist* list;\r                        LM->chan->GetExt(ie->GetInfoKey(), list);\r                      if (list)\r                      {\r                              char mask[MAXBUF];\r                             snprintf(mask, MAXBUF, "%s!%s@%s", LM->user->nick, LM->user->ident, LM->user->GetIPString());\r                          for (modelist::iterator it = list->begin(); it != list->end(); it++)\r                           {\r                                      if (match(LM->user->GetFullRealHost(), it->mask.c_str()) || match(LM->user->GetFullHost(), it->mask.c_str()) || (match(mask, it->mask.c_str(), true)))\r                                 {\r                                              // They match an entry\r                                         return (char*)it->mask.c_str();\r                                        }\r                              }\r                              return NULL;\r                   }\r              }\r              return NULL;\r   }\r\r     virtual void OnCleanup(int target_type, void* item)\r    {\r              ie->DoCleanup(target_type, item);\r      }\r\r     virtual void OnSyncChannel(chanrec* chan, Module* proto, void* opaque)\r {\r              ie->DoSyncChannel(chan, proto, opaque);\r        }\r\r     virtual void OnChannelDelete(chanrec* chan)\r    {\r              ie->DoChannelDelete(chan);\r     }\r\r     virtual void OnRehash(userrec* user, const std::string &param)\r {\r              ie->DoRehash();\r        }\r              \r       virtual Version GetVersion()\r   {\r              return Version(1, 1, 0, 3, VF_VENDOR | VF_COMMON, API_VERSION);\r        }\r\r     ~ModuleInviteException()\r       {\r              ServerInstance->Modes->DelMode(ie);\r            DELETE(ie);\r            ServerInstance->UnpublishInterface("ChannelBanList", this);\r    }\r};\r\rMODULE_INIT(ModuleInviteException)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *         the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+#include "mode.h"
+#include "u_listmode.h"
+
+/* $ModDesc: Provides support for the +I channel mode */
+/* $ModDep: ../../include/u_listmode.h */
+
+/*
+ * Written by Om <om@inspircd.org>, April 2005.
+ * Based on m_exception, which was originally based on m_chanprotect and m_silence
+ *
+ * The +I channel mode takes a nick!ident@host, glob patterns allowed,
+ * and if a user matches an entry on the +I list then they can join the channel,
+ * ignoring if +i is set on the channel
+ * Now supports CIDR and IP addresses -- Brain
+ */
+
+class InspIRCd* ServerInstance;
+
+/** Handles channel mode +I
+ */
+class InviteException : public ListModeBase
+{
+ public:
+       InviteException(InspIRCd* Instance) : ListModeBase(Instance, 'I', "End of Channel Invite Exception List", "346", "347", true) { }
+};
+
+class ModuleInviteException : public Module
+{
+       InviteException* ie;
+public:
+       ModuleInviteException(InspIRCd* Me) : Module(Me)
+       {
+               ie = new InviteException(ServerInstance);
+               if (!ServerInstance->AddMode(ie, 'I'))
+                       throw ModuleException("Could not add new modes!");
+               ServerInstance->PublishInterface("ChannelBanList", this);
+       }
+
+       virtual void Implements(char* List)
+       {
+               ie->DoImplements(List);
+               List[I_OnRequest] = List[I_On005Numeric] = List[I_OnCheckInvite] = 1;
+       }
+       
+       virtual void On005Numeric(std::string &output)
+       {
+               output.append(" INVEX=I");
+       }
+        
+       virtual int OnCheckInvite(userrec* user, chanrec* chan)
+       {
+               if(chan != NULL)
+               {
+                       modelist* list;
+                       chan->GetExt(ie->GetInfoKey(), list);
+                       if (list)
+                       {
+                               char mask[MAXBUF];
+                               snprintf(mask, MAXBUF, "%s!%s@%s", user->nick, user->ident, user->GetIPString());
+                               for (modelist::iterator it = list->begin(); it != list->end(); it++)
+                               {
+                                       if(match(user->GetFullRealHost(), it->mask.c_str()) || match(user->GetFullHost(), it->mask.c_str()) || (match(mask, it->mask.c_str(), true)))
+                                       {
+                                               // They match an entry on the list, so let them in.
+                                               return 1;
+                                       }
+                               }
+                       }
+                       // or if there wasn't a list, there can't be anyone on it, so we don't need to do anything.
+               }
+
+               return 0;               
+       }
+
+       virtual char* OnRequest(Request* request)
+       {
+               ListModeRequest* LM = (ListModeRequest*)request;
+               if (strcmp("LM_CHECKLIST", request->GetId()) == 0)
+               {
+                       modelist* list;
+                       LM->chan->GetExt(ie->GetInfoKey(), list);
+                       if (list)
+                       {
+                               char mask[MAXBUF];
+                               snprintf(mask, MAXBUF, "%s!%s@%s", LM->user->nick, LM->user->ident, LM->user->GetIPString());
+                               for (modelist::iterator it = list->begin(); it != list->end(); it++)
+                               {
+                                       if (match(LM->user->GetFullRealHost(), it->mask.c_str()) || match(LM->user->GetFullHost(), it->mask.c_str()) || (match(mask, it->mask.c_str(), true)))
+                                       {
+                                               // They match an entry
+                                               return (char*)it->mask.c_str();
+                                       }
+                               }
+                               return NULL;
+                       }
+               }
+               return NULL;
+       }
+
+       virtual void OnCleanup(int target_type, void* item)
+       {
+               ie->DoCleanup(target_type, item);
+       }
+
+       virtual void OnSyncChannel(chanrec* chan, Module* proto, void* opaque)
+       {
+               ie->DoSyncChannel(chan, proto, opaque);
+       }
+
+       virtual void OnChannelDelete(chanrec* chan)
+       {
+               ie->DoChannelDelete(chan);
+       }
+
+       virtual void OnRehash(userrec* user, const std::string &param)
+       {
+               ie->DoRehash();
+       }
+               
+       virtual Version GetVersion()
+       {
+               return Version(1, 1, 0, 3, VF_VENDOR | VF_COMMON, API_VERSION);
+       }
+
+       ~ModuleInviteException()
+       {
+               ServerInstance->Modes->DelMode(ie);
+               DELETE(ie);
+               ServerInstance->UnpublishInterface("ChannelBanList", this);
+       }
+};
+
+MODULE_INIT(ModuleInviteException)
index 26339e2079dda02a798642184b52e69ef1b3aeda..3d342b636357f3efd72bb29ed750fff8de765c81 100644 (file)
@@ -1 +1,285 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r\r/* $ModDesc: Provides channel mode +j (join flood protection) */\r\r/** Holds settings and state associated with channel mode +j\r */\rclass joinfloodsettings : public classbase\r{\r public:\r\r    int secs;\r      int joins;\r     time_t reset;\r  time_t unlocktime;\r     int counter;\r   bool locked;\r   InspIRCd* ServerInstance;\r\r     joinfloodsettings() : secs(0), joins(0) {};\r\r   joinfloodsettings(int b, int c) : secs(b), joins(c)\r    {\r              reset = time(NULL) + secs;\r             counter = 0;\r           locked = false;\r        };\r\r    void addjoin()\r {\r              counter++;\r             if (time(NULL) > reset)\r                {\r                      counter = 0;\r                   reset = time(NULL) + secs;\r             }\r      }\r\r     bool shouldlock()\r      {\r              return (counter >= this->joins);\r       }\r\r     void clear()\r   {\r              counter = 0;\r   }\r\r     bool islocked()\r        {\r              if (locked)\r            {\r                      if (time(NULL) > unlocktime)\r                   {\r                              locked = false;\r                                return false;\r                  }\r                      else\r                   {\r                              return true;\r                   }\r              }\r              return false;\r  }\r\r     void lock()\r    {\r              locked = true;\r         unlocktime = time(NULL) + 60;\r  }\r\r};\r\r/** Handles channel mode +j\r */\rclass JoinFlood : public ModeHandler\r{\r public:\r JoinFlood(InspIRCd* Instance) : ModeHandler(Instance, 'j', 1, 0, false, MODETYPE_CHANNEL, false) { }\r\r  ModePair ModeSet(userrec* source, userrec* dest, chanrec* channel, const std::string &parameter)\r       {\r              joinfloodsettings* x;\r          if (channel->GetExt("joinflood",x))\r                    return std::make_pair(true, ConvToStr(x->joins)+":"+ConvToStr(x->secs));\r               else\r                   return std::make_pair(false, parameter);\r       } \r\r    bool CheckTimeStamp(time_t theirs, time_t ours, const std::string &their_param, const std::string &our_param, chanrec* channel)\r        {\r              /* When TS is equal, the alphabetically later one wins */\r              return (their_param < our_param);\r      }\r\r     ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)\r {\r              joinfloodsettings* dummy;\r\r             if (adding)\r            {\r                      char ndata[MAXBUF];\r                    char* data = ndata;\r                    strlcpy(ndata,parameter.c_str(),MAXBUF);\r                       char* joins = data;\r                    char* secs = NULL;\r                     while (*data)\r                  {\r                              if (*data == ':')\r                              {\r                                      *data = 0;\r                                     data++;\r                                        secs = data;\r                                   break;\r                         }\r                              else data++;\r                   }\r                      if (secs)\r\r                     {\r                              /* Set up the flood parameters for this channel */\r                             int njoins = atoi(joins);\r                              int nsecs = atoi(secs);\r                                if ((njoins<1) || (nsecs<1))\r                           {\r                                      source->WriteServ("608 %s %s :Invalid flood parameter",source->nick,channel->name);\r                                    parameter.clear();\r                                     return MODEACTION_DENY;\r                                }\r                              else\r                           {\r                                      if (!channel->GetExt("joinflood", dummy))\r                                      {\r                                              parameter = ConvToStr(njoins) + ":" +ConvToStr(nsecs);\r                                         joinfloodsettings *f = new joinfloodsettings(nsecs,njoins);\r                                            channel->Extend("joinflood", f);\r                                               channel->SetMode('j', true);\r                                           channel->SetModeParam('j', parameter.c_str(), true);\r                                           return MODEACTION_ALLOW;\r                                       }\r                                      else\r                                   {\r                                              std::string cur_param = channel->GetModeParameter('j');\r                                                parameter = ConvToStr(njoins) + ":" +ConvToStr(nsecs);\r                                         if (cur_param == parameter)\r                                            {\r                                                      // mode params match\r                                                   return MODEACTION_DENY;\r                                                }\r                                              else\r                                           {\r                                                      // new mode param, replace old with new\r                                                        if ((nsecs > 0) && (njoins > 0))\r                                                       {\r                                                              joinfloodsettings* f;\r                                                          channel->GetExt("joinflood", f);\r                                                               delete f;\r                                                              f = new joinfloodsettings(nsecs,njoins);\r                                                               channel->Shrink("joinflood");\r                                                          channel->Extend("joinflood", f);\r                                                               channel->SetModeParam('j', cur_param.c_str(), false);\r                                                          channel->SetModeParam('j', parameter.c_str(), true);\r                                                           return MODEACTION_ALLOW;\r                                                       }\r                                                      else\r                                                   {\r                                                              return MODEACTION_DENY;\r                                                        }\r                                              }\r                                      }\r                              }\r                      }\r                      else\r                   {\r                              source->WriteServ("608 %s %s :Invalid flood parameter",source->nick,channel->name);\r                            return MODEACTION_DENY;\r                        }\r              }\r              else\r           {\r                      if (channel->GetExt("joinflood", dummy))\r                       {\r                              joinfloodsettings *f;\r                          channel->GetExt("joinflood", f);\r                               DELETE(f);\r                             channel->Shrink("joinflood");\r                          channel->SetMode('j', false);\r                          return MODEACTION_ALLOW;\r                       }\r              }\r              return MODEACTION_DENY;\r        }\r};\r\rclass ModuleJoinFlood : public Module\r{\r  \r       JoinFlood* jf;\r \r public:\r \r    ModuleJoinFlood(InspIRCd* Me)\r          : Module(Me)\r   {\r              \r               jf = new JoinFlood(ServerInstance);\r            if (!ServerInstance->AddMode(jf, 'j'))\r                 throw ModuleException("Could not add new modes!");\r     }\r      \r       virtual int OnUserPreJoin(userrec* user, chanrec* chan, const char* cname, std::string &privs)\r {\r              if (chan)\r              {\r                      joinfloodsettings *f;\r                  if (chan->GetExt("joinflood", f))\r                      {\r                              if (f->islocked())\r                             {\r                                      user->WriteServ("609 %s %s :This channel is temporarily unavailable (+j). Please try again later.",user->nick,chan->name);\r                                     return 1;\r                              }\r                      }\r              }\r              return 0;\r      }\r\r     virtual void OnUserJoin(userrec* user, chanrec* channel, bool &silent)\r {\r              joinfloodsettings *f;\r          if (channel->GetExt("joinflood",f))\r            {\r                      f->addjoin();\r                  if (f->shouldlock())\r                   {\r                              f->clear();\r                            f->lock();\r                             channel->WriteChannelWithServ((char*)ServerInstance->Config->ServerName, "NOTICE %s :This channel has been closed to new users for 60 seconds because there have been more than %d joins in %d seconds.", channel->name, f->joins, f->secs);\r                   }\r              }\r      }\r\r     void OnChannelDelete(chanrec* chan)\r    {\r              joinfloodsettings *f;\r          if (chan->GetExt("joinflood",f))\r               {\r                      DELETE(f);\r                     chan->Shrink("joinflood");\r             }\r      }\r\r     void Implements(char* List)\r    {\r              List[I_OnChannelDelete] = List[I_OnUserPreJoin] = List[I_OnUserJoin] = 1;\r      }\r\r     virtual ~ModuleJoinFlood()\r     {\r              ServerInstance->Modes->DelMode(jf);\r            DELETE(jf);\r    }\r      \r       virtual Version GetVersion()\r   {\r              return Version(1, 1, 0, 0, VF_COMMON | VF_VENDOR, API_VERSION);\r        }\r};\r\rMODULE_INIT(ModuleJoinFlood)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+
+/* $ModDesc: Provides channel mode +j (join flood protection) */
+
+/** Holds settings and state associated with channel mode +j
+ */
+class joinfloodsettings : public classbase
+{
+ public:
+
+       int secs;
+       int joins;
+       time_t reset;
+       time_t unlocktime;
+       int counter;
+       bool locked;
+       InspIRCd* ServerInstance;
+
+       joinfloodsettings() : secs(0), joins(0) {};
+
+       joinfloodsettings(int b, int c) : secs(b), joins(c)
+       {
+               reset = time(NULL) + secs;
+               counter = 0;
+               locked = false;
+       };
+
+       void addjoin()
+       {
+               counter++;
+               if (time(NULL) > reset)
+               {
+                       counter = 0;
+                       reset = time(NULL) + secs;
+               }
+       }
+
+       bool shouldlock()
+       {
+               return (counter >= this->joins);
+       }
+
+       void clear()
+       {
+               counter = 0;
+       }
+
+       bool islocked()
+       {
+               if (locked)
+               {
+                       if (time(NULL) > unlocktime)
+                       {
+                               locked = false;
+                               return false;
+                       }
+                       else
+                       {
+                               return true;
+                       }
+               }
+               return false;
+       }
+
+       void lock()
+       {
+               locked = true;
+               unlocktime = time(NULL) + 60;
+       }
+
+};
+
+/** Handles channel mode +j
+ */
+class JoinFlood : public ModeHandler
+{
+ public:
+       JoinFlood(InspIRCd* Instance) : ModeHandler(Instance, 'j', 1, 0, false, MODETYPE_CHANNEL, false) { }
+
+       ModePair ModeSet(userrec* source, userrec* dest, chanrec* channel, const std::string &parameter)
+       {
+               joinfloodsettings* x;
+               if (channel->GetExt("joinflood",x))
+                       return std::make_pair(true, ConvToStr(x->joins)+":"+ConvToStr(x->secs));
+               else
+                       return std::make_pair(false, parameter);
+       } 
+
+       bool CheckTimeStamp(time_t theirs, time_t ours, const std::string &their_param, const std::string &our_param, chanrec* channel)
+       {
+               /* When TS is equal, the alphabetically later one wins */
+               return (their_param < our_param);
+       }
+
+       ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)
+       {
+               joinfloodsettings* dummy;
+
+               if (adding)
+               {
+                       char ndata[MAXBUF];
+                       char* data = ndata;
+                       strlcpy(ndata,parameter.c_str(),MAXBUF);
+                       char* joins = data;
+                       char* secs = NULL;
+                       while (*data)
+                       {
+                               if (*data == ':')
+                               {
+                                       *data = 0;
+                                       data++;
+                                       secs = data;
+                                       break;
+                               }
+                               else data++;
+                       }
+                       if (secs)
+
+                       {
+                               /* Set up the flood parameters for this channel */
+                               int njoins = atoi(joins);
+                               int nsecs = atoi(secs);
+                               if ((njoins<1) || (nsecs<1))
+                               {
+                                       source->WriteServ("608 %s %s :Invalid flood parameter",source->nick,channel->name);
+                                       parameter.clear();
+                                       return MODEACTION_DENY;
+                               }
+                               else
+                               {
+                                       if (!channel->GetExt("joinflood", dummy))
+                                       {
+                                               parameter = ConvToStr(njoins) + ":" +ConvToStr(nsecs);
+                                               joinfloodsettings *f = new joinfloodsettings(nsecs,njoins);
+                                               channel->Extend("joinflood", f);
+                                               channel->SetMode('j', true);
+                                               channel->SetModeParam('j', parameter.c_str(), true);
+                                               return MODEACTION_ALLOW;
+                                       }
+                                       else
+                                       {
+                                               std::string cur_param = channel->GetModeParameter('j');
+                                               parameter = ConvToStr(njoins) + ":" +ConvToStr(nsecs);
+                                               if (cur_param == parameter)
+                                               {
+                                                       // mode params match
+                                                       return MODEACTION_DENY;
+                                               }
+                                               else
+                                               {
+                                                       // new mode param, replace old with new
+                                                       if ((nsecs > 0) && (njoins > 0))
+                                                       {
+                                                               joinfloodsettings* f;
+                                                               channel->GetExt("joinflood", f);
+                                                               delete f;
+                                                               f = new joinfloodsettings(nsecs,njoins);
+                                                               channel->Shrink("joinflood");
+                                                               channel->Extend("joinflood", f);
+                                                               channel->SetModeParam('j', cur_param.c_str(), false);
+                                                               channel->SetModeParam('j', parameter.c_str(), true);
+                                                               return MODEACTION_ALLOW;
+                                                       }
+                                                       else
+                                                       {
+                                                               return MODEACTION_DENY;
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+                       else
+                       {
+                               source->WriteServ("608 %s %s :Invalid flood parameter",source->nick,channel->name);
+                               return MODEACTION_DENY;
+                       }
+               }
+               else
+               {
+                       if (channel->GetExt("joinflood", dummy))
+                       {
+                               joinfloodsettings *f;
+                               channel->GetExt("joinflood", f);
+                               DELETE(f);
+                               channel->Shrink("joinflood");
+                               channel->SetMode('j', false);
+                               return MODEACTION_ALLOW;
+                       }
+               }
+               return MODEACTION_DENY;
+       }
+};
+
+class ModuleJoinFlood : public Module
+{
+       
+       JoinFlood* jf;
+       
+ public:
+       ModuleJoinFlood(InspIRCd* Me)
+               : Module(Me)
+       {
+               
+               jf = new JoinFlood(ServerInstance);
+               if (!ServerInstance->AddMode(jf, 'j'))
+                       throw ModuleException("Could not add new modes!");
+       }
+       
+       virtual int OnUserPreJoin(userrec* user, chanrec* chan, const char* cname, std::string &privs)
+       {
+               if (chan)
+               {
+                       joinfloodsettings *f;
+                       if (chan->GetExt("joinflood", f))
+                       {
+                               if (f->islocked())
+                               {
+                                       user->WriteServ("609 %s %s :This channel is temporarily unavailable (+j). Please try again later.",user->nick,chan->name);
+                                       return 1;
+                               }
+                       }
+               }
+               return 0;
+       }
+
+       virtual void OnUserJoin(userrec* user, chanrec* channel, bool &silent)
+       {
+               joinfloodsettings *f;
+               if (channel->GetExt("joinflood",f))
+               {
+                       f->addjoin();
+                       if (f->shouldlock())
+                       {
+                               f->clear();
+                               f->lock();
+                               channel->WriteChannelWithServ((char*)ServerInstance->Config->ServerName, "NOTICE %s :This channel has been closed to new users for 60 seconds because there have been more than %d joins in %d seconds.", channel->name, f->joins, f->secs);
+                       }
+               }
+       }
+
+       void OnChannelDelete(chanrec* chan)
+       {
+               joinfloodsettings *f;
+               if (chan->GetExt("joinflood",f))
+               {
+                       DELETE(f);
+                       chan->Shrink("joinflood");
+               }
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnChannelDelete] = List[I_OnUserPreJoin] = List[I_OnUserJoin] = 1;
+       }
+
+       virtual ~ModuleJoinFlood()
+       {
+               ServerInstance->Modes->DelMode(jf);
+               DELETE(jf);
+       }
+       
+       virtual Version GetVersion()
+       {
+               return Version(1, 1, 0, 0, VF_COMMON | VF_VENDOR, API_VERSION);
+       }
+};
+
+MODULE_INIT(ModuleJoinFlood)
index 5a823b44cdc17f7b687ee16412ae61cdfb05e452..28bbd056ec8846f77ef8542ebab12dade995afcd 100644 (file)
@@ -1 +1,164 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r\r/* $ModDesc: Provides support for unreal-style SAPART command */\r\r/** Handle /SAPART\r */\rclass cmd_jumpserver : public command_t\r{\r public:\r  bool redirect_all_immediately;\r bool redirect_new_users;\r       bool direction;\r        std::string redirect_to;\r       std::string reason;\r    int port;\r\r     cmd_jumpserver (InspIRCd* Instance) : command_t(Instance, "JUMPSERVER", 'o', 0)\r        {\r              this->source = "m_jumpserver.so";\r              syntax = "[<server> <port> <+/-a> :<reason>]";\r         redirect_to.clear();\r           reason.clear();\r                port = 0;\r              redirect_all_immediately = redirect_new_users = false;\r }\r\r     CmdResult Handle (const char** parameters, int pcnt, userrec *user)\r    {\r              int n_done = 0;\r                reason = (pcnt < 4) ? "Please use this server/port instead" : parameters[3];\r           redirect_all_immediately = false;\r              redirect_new_users = true;\r             direction = true;\r              std::string n_done_s;\r\r         /* No parameters: jumpserver disabled */\r               if (!pcnt)\r             {\r                      if (port)\r                              user->WriteServ("NOTICE %s :*** Disabled jumpserver (previously set to '%s:%d')", user->nick, redirect_to.c_str(), port);\r                      else\r                           user->WriteServ("NOTICE %s :*** jumpserver was not enabled.", user->nick);\r\r                    port = 0;\r                      redirect_to.clear();\r                   return CMD_LOCALONLY;\r          }\r\r             port = 0;\r              redirect_to.clear();\r\r          for (const char* n = parameters[2]; *n; n++)\r           {\r                      switch (*n)\r                    {\r                              case '+':\r                                      direction = true;\r                              break;\r                         case '-':\r                                      direction = false;\r                             break;\r                         case 'a':\r                                      redirect_all_immediately = direction;\r                          break;\r                         case 'n':\r                                      redirect_new_users = direction;\r                                break;\r                 }\r              }\r\r             if (redirect_all_immediately)\r          {\r                      /* Redirect everyone but the oper sending the command */\r                       for (std::vector<userrec*>::const_iterator i = ServerInstance->local_users.begin(); i != ServerInstance->local_users.end(); i++)\r                       {\r                              userrec* t = *i;\r                               if (!IS_OPER(t))\r                               {\r                                      t->WriteServ("010 %s %s %s :Please use this Server/Port instead", user->nick, parameters[0], parameters[1]);\r                                   userrec::QuitUser(ServerInstance, t, reason);\r                                  n_done++;\r                              }\r                      }\r                      if (n_done)\r                    {\r                              n_done_s = ConvToStr(n_done);\r                  }\r              }\r\r             if (redirect_new_users)\r                {\r                      redirect_to = parameters[0];\r                   port = atoi(parameters[1]);\r            }\r\r             user->WriteServ("NOTICE %s :*** Set jumpserver to server '%s' port '%s', flags '+%s%s'%s%s%s: %s", user->nick, parameters[0], parameters[1],\r                           redirect_all_immediately ? "a" : "",\r                           redirect_new_users ? "n" : "",\r                         n_done ? " (" : "",\r                            n_done ? n_done_s.c_str() : "",\r                                n_done ? " user(s) redirected)" : "",\r                          reason.c_str());\r\r              return CMD_LOCALONLY;\r  }\r};\r\r\rclass ModuleJumpServer : public Module\r{\r        cmd_jumpserver* js;\r public:\r   ModuleJumpServer(InspIRCd* Me)\r         : Module(Me)\r   {\r              \r               js = new cmd_jumpserver(ServerInstance);\r               ServerInstance->AddCommand(js);\r        }\r      \r       virtual ~ModuleJumpServer()\r    {\r      }\r\r     virtual int OnUserRegister(userrec* user)\r      {\r              if (js->port && js->redirect_new_users)\r                {\r                      user->WriteServ("010 %s %s %d :Please use this Server/Port instead", user->nick, js->redirect_to.c_str(), js->port);\r                   userrec::QuitUser(ServerInstance, user, js->reason);\r                   return 0;\r              }\r              return 0;\r      }\r\r     virtual void Implements(char* List)\r    {\r              List[I_OnUserRegister] = 1;\r    }\r\r     virtual Version GetVersion()\r   {\r              return Version(1,1,0,1,VF_VENDOR,API_VERSION);\r }\r      \r};\r\rMODULE_INIT(ModuleJumpServer)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+
+/* $ModDesc: Provides support for unreal-style SAPART command */
+
+/** Handle /SAPART
+ */
+class cmd_jumpserver : public command_t
+{
+ public:
+       bool redirect_all_immediately;
+       bool redirect_new_users;
+       bool direction;
+       std::string redirect_to;
+       std::string reason;
+       int port;
+
+       cmd_jumpserver (InspIRCd* Instance) : command_t(Instance, "JUMPSERVER", 'o', 0)
+       {
+               this->source = "m_jumpserver.so";
+               syntax = "[<server> <port> <+/-a> :<reason>]";
+               redirect_to.clear();
+               reason.clear();
+               port = 0;
+               redirect_all_immediately = redirect_new_users = false;
+       }
+
+       CmdResult Handle (const char** parameters, int pcnt, userrec *user)
+       {
+               int n_done = 0;
+               reason = (pcnt < 4) ? "Please use this server/port instead" : parameters[3];
+               redirect_all_immediately = false;
+               redirect_new_users = true;
+               direction = true;
+               std::string n_done_s;
+
+               /* No parameters: jumpserver disabled */
+               if (!pcnt)
+               {
+                       if (port)
+                               user->WriteServ("NOTICE %s :*** Disabled jumpserver (previously set to '%s:%d')", user->nick, redirect_to.c_str(), port);
+                       else
+                               user->WriteServ("NOTICE %s :*** jumpserver was not enabled.", user->nick);
+
+                       port = 0;
+                       redirect_to.clear();
+                       return CMD_LOCALONLY;
+               }
+
+               port = 0;
+               redirect_to.clear();
+
+               for (const char* n = parameters[2]; *n; n++)
+               {
+                       switch (*n)
+                       {
+                               case '+':
+                                       direction = true;
+                               break;
+                               case '-':
+                                       direction = false;
+                               break;
+                               case 'a':
+                                       redirect_all_immediately = direction;
+                               break;
+                               case 'n':
+                                       redirect_new_users = direction;
+                               break;
+                       }
+               }
+
+               if (redirect_all_immediately)
+               {
+                       /* Redirect everyone but the oper sending the command */
+                       for (std::vector<userrec*>::const_iterator i = ServerInstance->local_users.begin(); i != ServerInstance->local_users.end(); i++)
+                       {
+                               userrec* t = *i;
+                               if (!IS_OPER(t))
+                               {
+                                       t->WriteServ("010 %s %s %s :Please use this Server/Port instead", user->nick, parameters[0], parameters[1]);
+                                       userrec::QuitUser(ServerInstance, t, reason);
+                                       n_done++;
+                               }
+                       }
+                       if (n_done)
+                       {
+                               n_done_s = ConvToStr(n_done);
+                       }
+               }
+
+               if (redirect_new_users)
+               {
+                       redirect_to = parameters[0];
+                       port = atoi(parameters[1]);
+               }
+
+               user->WriteServ("NOTICE %s :*** Set jumpserver to server '%s' port '%s', flags '+%s%s'%s%s%s: %s", user->nick, parameters[0], parameters[1],
+                               redirect_all_immediately ? "a" : "",
+                               redirect_new_users ? "n" : "",
+                               n_done ? " (" : "",
+                               n_done ? n_done_s.c_str() : "",
+                               n_done ? " user(s) redirected)" : "",
+                               reason.c_str());
+
+               return CMD_LOCALONLY;
+       }
+};
+
+
+class ModuleJumpServer : public Module
+{
+       cmd_jumpserver* js;
+ public:
+       ModuleJumpServer(InspIRCd* Me)
+               : Module(Me)
+       {
+               
+               js = new cmd_jumpserver(ServerInstance);
+               ServerInstance->AddCommand(js);
+       }
+       
+       virtual ~ModuleJumpServer()
+       {
+       }
+
+       virtual int OnUserRegister(userrec* user)
+       {
+               if (js->port && js->redirect_new_users)
+               {
+                       user->WriteServ("010 %s %s %d :Please use this Server/Port instead", user->nick, js->redirect_to.c_str(), js->port);
+                       userrec::QuitUser(ServerInstance, user, js->reason);
+                       return 0;
+               }
+               return 0;
+       }
+
+       virtual void Implements(char* List)
+       {
+               List[I_OnUserRegister] = 1;
+       }
+
+       virtual Version GetVersion()
+       {
+               return Version(1,1,0,1,VF_VENDOR,API_VERSION);
+       }
+       
+};
+
+MODULE_INIT(ModuleJumpServer)
index 97d88786ff13640247a44e99b5d7abcf8df8450d..bdb988ad245c2fc1e8bfa22f19fd6259a5aa4a22 100644 (file)
@@ -1 +1,224 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include <sstream>\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r\r/* $ModDesc: Provides channel mode +J (delay rejoin after kick) */\r\rinline int strtoint(const std::string &str)\r{\r std::istringstream ss(str);\r    int result;\r    ss >> result;\r  return result;\r}\r\rtypedef std::map<userrec*, time_t> delaylist;\r\r/** Handles channel mode +J\r */\rclass KickRejoin : public ModeHandler\r{\r public:\r      KickRejoin(InspIRCd* Instance) : ModeHandler(Instance, 'J', 1, 0, false, MODETYPE_CHANNEL, false) { }\r\r ModePair ModeSet(userrec* source, userrec* dest, chanrec* channel, const std::string &parameter)\r       {\r              if (channel->IsModeSet('J'))\r                   return std::make_pair(true, channel->GetModeParameter('J'));\r           else\r                   return std::make_pair(false, parameter);\r       } \r\r    bool CheckTimeStamp(time_t theirs, time_t ours, const std::string &their_param, const std::string &our_param, chanrec* channel)\r        {\r              /* When TS is equal, the alphabetically later one wins */\r              return (their_param < our_param);\r      }\r      \r       ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)\r {\r              if (!adding)\r           {\r                      // Taking the mode off, we need to clean up.\r                   delaylist* dl;\r                 \r                       if (channel->GetExt("norejoinusers", dl))\r                      {\r                              DELETE(dl);\r                            channel->Shrink("norejoinusers");\r                      }\r                      \r                       if (!channel->IsModeSet('J'))\r                  {\r                              return MODEACTION_DENY;\r                        }\r                      else\r                   {\r                              channel->SetMode('J', false);\r                          return MODEACTION_ALLOW;\r                       }\r              }\r              else if (atoi(parameter.c_str()) > 0)\r          {\r                      if (!channel->IsModeSet('J'))\r                  {\r                              parameter = ConvToStr(atoi(parameter.c_str()));\r                                channel->SetModeParam('J', parameter.c_str(), adding);\r                         channel->SetMode('J', adding);\r                         return MODEACTION_ALLOW;\r                       }\r                      else\r                   {\r                              std::string cur_param = channel->GetModeParameter('J');\r                                if (cur_param == parameter)\r                            {\r                                      // mode params match, don't change mode\r                                        return MODEACTION_DENY;\r                                }\r                              else\r                           {\r                                      // new mode param, replace old with new\r                                        parameter = ConvToStr(atoi(parameter.c_str()));\r                                        cur_param = ConvToStr(atoi(cur_param.c_str()));\r                                        if (parameter != "0")\r                                  {\r                                              channel->SetModeParam('J', cur_param.c_str(), false);\r                                          channel->SetModeParam('J', parameter.c_str(), adding);\r                                         return MODEACTION_ALLOW;\r                                       }\r                                      else\r                                   {\r                                              /* Fix to jamie's fix, dont allow +J 0 on the new value! */\r                                            return MODEACTION_DENY;\r                                        }\r                              }\r                      }\r              }\r              else\r           {\r                      return MODEACTION_DENY;\r                }\r      }\r};\r\rclass ModuleKickNoRejoin : public Module\r{\r       \r       KickRejoin* kr;\r        \rpublic:\r \r     ModuleKickNoRejoin(InspIRCd* Me)\r               : Module(Me)\r   {\r              \r               kr = new KickRejoin(ServerInstance);\r           if (!ServerInstance->AddMode(kr, 'J'))\r                 throw ModuleException("Could not add new modes!");\r     }\r\r     virtual int OnUserPreJoin(userrec* user, chanrec* chan, const char* cname, std::string &privs)\r {\r              if (chan)\r              {\r                      delaylist* dl;\r                 if (chan->GetExt("norejoinusers", dl))\r                 {\r                              std::vector<userrec*> itemstoremove;\r                   \r                               for (delaylist::iterator iter = dl->begin(); iter != dl->end(); iter++)\r                                {\r                                      if (iter->second > time(NULL))\r                                 {\r                                              if (iter->first == user)                                        \r                                               {\r                                                      user->WriteServ( "495 %s %s :You cannot rejoin this channel yet after being kicked (+J)", user->nick, chan->name);\r                                                     return 1;\r                                              }\r                                      }\r                                      else\r                                   {\r                                              // Expired record, remove.\r                                             itemstoremove.push_back(iter->first);\r                                  }\r                              }\r                              \r                               for (unsigned int i = 0; i < itemstoremove.size(); i++)\r                                        dl->erase(itemstoremove[i]);\r                                                                                                                                   \r                               if (!dl->size())\r                               {\r                                      // Now it's empty..\r                                    DELETE(dl);\r                                    chan->Shrink("norejoinusers");\r                         }\r                      }\r              }\r              return 0;\r      }\r              \r       virtual void OnUserKick(userrec* source, userrec* user, chanrec* chan, const std::string &reason, bool &silent)\r        {\r              if (chan->IsModeSet('J') && (source != user))\r          {\r                      delaylist* dl;\r                 if (!chan->GetExt("norejoinusers", dl))\r                        {\r                              dl = new delaylist;\r                            chan->Extend("norejoinusers", dl);\r                     }\r                      (*dl)[user] = time(NULL) + strtoint(chan->GetModeParameter('J'));\r              }\r      }\r      \r       virtual void OnChannelDelete(chanrec* chan)\r    {\r              delaylist* dl;\r                 \r               if (chan->GetExt("norejoinusers", dl))\r         {\r                      DELETE(dl);\r                    chan->Shrink("norejoinusers");\r         }\r      }\r      \r       virtual void OnCleanup(int target_type, void* item)\r    {\r              if(target_type == TYPE_CHANNEL)\r                        OnChannelDelete((chanrec*)item);\r       }\r\r     virtual void Implements(char* List)\r    {\r              List[I_OnCleanup] = List[I_OnChannelDelete] = List[I_OnUserPreJoin] = List[I_OnUserKick] = 1;\r  }\r\r     virtual ~ModuleKickNoRejoin()\r  {\r              ServerInstance->Modes->DelMode(kr);\r            DELETE(kr);\r    }\r      \r       virtual Version GetVersion()\r   {\r              return Version(1, 1, 0, 0, VF_COMMON | VF_VENDOR, API_VERSION);\r        }\r};\r\r\rMODULE_INIT(ModuleKickNoRejoin)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include <sstream>
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+
+/* $ModDesc: Provides channel mode +J (delay rejoin after kick) */
+
+inline int strtoint(const std::string &str)
+{
+       std::istringstream ss(str);
+       int result;
+       ss >> result;
+       return result;
+}
+
+typedef std::map<userrec*, time_t> delaylist;
+
+/** Handles channel mode +J
+ */
+class KickRejoin : public ModeHandler
+{
+ public:
+       KickRejoin(InspIRCd* Instance) : ModeHandler(Instance, 'J', 1, 0, false, MODETYPE_CHANNEL, false) { }
+
+       ModePair ModeSet(userrec* source, userrec* dest, chanrec* channel, const std::string &parameter)
+       {
+               if (channel->IsModeSet('J'))
+                       return std::make_pair(true, channel->GetModeParameter('J'));
+               else
+                       return std::make_pair(false, parameter);
+       } 
+
+       bool CheckTimeStamp(time_t theirs, time_t ours, const std::string &their_param, const std::string &our_param, chanrec* channel)
+       {
+               /* When TS is equal, the alphabetically later one wins */
+               return (their_param < our_param);
+       }
+       
+       ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)
+       {
+               if (!adding)
+               {
+                       // Taking the mode off, we need to clean up.
+                       delaylist* dl;
+                       
+                       if (channel->GetExt("norejoinusers", dl))
+                       {
+                               DELETE(dl);
+                               channel->Shrink("norejoinusers");
+                       }
+                       
+                       if (!channel->IsModeSet('J'))
+                       {
+                               return MODEACTION_DENY;
+                       }
+                       else
+                       {
+                               channel->SetMode('J', false);
+                               return MODEACTION_ALLOW;
+                       }
+               }
+               else if (atoi(parameter.c_str()) > 0)
+               {
+                       if (!channel->IsModeSet('J'))
+                       {
+                               parameter = ConvToStr(atoi(parameter.c_str()));
+                               channel->SetModeParam('J', parameter.c_str(), adding);
+                               channel->SetMode('J', adding);
+                               return MODEACTION_ALLOW;
+                       }
+                       else
+                       {
+                               std::string cur_param = channel->GetModeParameter('J');
+                               if (cur_param == parameter)
+                               {
+                                       // mode params match, don't change mode
+                                       return MODEACTION_DENY;
+                               }
+                               else
+                               {
+                                       // new mode param, replace old with new
+                                       parameter = ConvToStr(atoi(parameter.c_str()));
+                                       cur_param = ConvToStr(atoi(cur_param.c_str()));
+                                       if (parameter != "0")
+                                       {
+                                               channel->SetModeParam('J', cur_param.c_str(), false);
+                                               channel->SetModeParam('J', parameter.c_str(), adding);
+                                               return MODEACTION_ALLOW;
+                                       }
+                                       else
+                                       {
+                                               /* Fix to jamie's fix, dont allow +J 0 on the new value! */
+                                               return MODEACTION_DENY;
+                                       }
+                               }
+                       }
+               }
+               else
+               {
+                       return MODEACTION_DENY;
+               }
+       }
+};
+
+class ModuleKickNoRejoin : public Module
+{
+       
+       KickRejoin* kr;
+       
+public:
+       ModuleKickNoRejoin(InspIRCd* Me)
+               : Module(Me)
+       {
+               
+               kr = new KickRejoin(ServerInstance);
+               if (!ServerInstance->AddMode(kr, 'J'))
+                       throw ModuleException("Could not add new modes!");
+       }
+
+       virtual int OnUserPreJoin(userrec* user, chanrec* chan, const char* cname, std::string &privs)
+       {
+               if (chan)
+               {
+                       delaylist* dl;
+                       if (chan->GetExt("norejoinusers", dl))
+                       {
+                               std::vector<userrec*> itemstoremove;
+                       
+                               for (delaylist::iterator iter = dl->begin(); iter != dl->end(); iter++)
+                               {
+                                       if (iter->second > time(NULL))
+                                       {
+                                               if (iter->first == user)                                        
+                                               {
+                                                       user->WriteServ( "495 %s %s :You cannot rejoin this channel yet after being kicked (+J)", user->nick, chan->name);
+                                                       return 1;
+                                               }
+                                       }
+                                       else
+                                       {
+                                               // Expired record, remove.
+                                               itemstoremove.push_back(iter->first);
+                                       }
+                               }
+                               
+                               for (unsigned int i = 0; i < itemstoremove.size(); i++)
+                                       dl->erase(itemstoremove[i]);
+                                                                                                                                       
+                               if (!dl->size())
+                               {
+                                       // Now it's empty..
+                                       DELETE(dl);
+                                       chan->Shrink("norejoinusers");
+                               }
+                       }
+               }
+               return 0;
+       }
+               
+       virtual void OnUserKick(userrec* source, userrec* user, chanrec* chan, const std::string &reason, bool &silent)
+       {
+               if (chan->IsModeSet('J') && (source != user))
+               {
+                       delaylist* dl;
+                       if (!chan->GetExt("norejoinusers", dl))
+                       {
+                               dl = new delaylist;
+                               chan->Extend("norejoinusers", dl);
+                       }
+                       (*dl)[user] = time(NULL) + strtoint(chan->GetModeParameter('J'));
+               }
+       }
+       
+       virtual void OnChannelDelete(chanrec* chan)
+       {
+               delaylist* dl;
+                       
+               if (chan->GetExt("norejoinusers", dl))
+               {
+                       DELETE(dl);
+                       chan->Shrink("norejoinusers");
+               }
+       }
+       
+       virtual void OnCleanup(int target_type, void* item)
+       {
+               if(target_type == TYPE_CHANNEL)
+                       OnChannelDelete((chanrec*)item);
+       }
+
+       virtual void Implements(char* List)
+       {
+               List[I_OnCleanup] = List[I_OnChannelDelete] = List[I_OnUserPreJoin] = List[I_OnUserKick] = 1;
+       }
+
+       virtual ~ModuleKickNoRejoin()
+       {
+               ServerInstance->Modes->DelMode(kr);
+               DELETE(kr);
+       }
+       
+       virtual Version GetVersion()
+       {
+               return Version(1, 1, 0, 0, VF_COMMON | VF_VENDOR, API_VERSION);
+       }
+};
+
+
+MODULE_INIT(ModuleKickNoRejoin)
index 9beaa699eb58a4237668d07b84dc5132b7c4e7d4..3bc45cceb20c8f67f67c8e31686d88d84c24dd7a 100644 (file)
@@ -1 +1,129 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r\r/* $ModDesc: Provides support for /KNOCK and mode +K */\r\r/** Handles the /KNOCK command\r */\rclass cmd_knock : public command_t\r{\r public:\r    cmd_knock (InspIRCd* Instance) : command_t(Instance,"KNOCK", 0, 2)\r     {\r              this->source = "m_knock.so";\r           syntax = "<channel> <reason>";\r }\r      \r       CmdResult Handle (const char** parameters, int pcnt, userrec *user)\r    {\r              chanrec* c = ServerInstance->FindChan(parameters[0]);\r\r         if (!c)\r                {\r                      user->WriteServ("401 %s %s :No such channel",user->nick, parameters[0]);\r                       return CMD_FAILURE;\r            }\r\r             std::string line;\r\r             if (c->IsModeSet('K'))\r         {\r                      user->WriteServ("480 %s :Can't KNOCK on %s, +K is set.",user->nick, c->name);\r                  return CMD_FAILURE;\r            }\r\r             for (int i = 1; i < pcnt - 1; i++)\r             {\r                      line = line + std::string(parameters[i]) + " ";\r                }\r              line = line + std::string(parameters[pcnt-1]);\r\r                if (!c->modes[CM_INVITEONLY])\r          {\r                      user->WriteServ("480 %s :Can't KNOCK on %s, channel is not invite only so knocking is pointless!",user->nick, c->name);\r                        return CMD_FAILURE;\r            }\r\r             c->WriteChannelWithServ((char*)ServerInstance->Config->ServerName,  "NOTICE %s :User %s is KNOCKing on %s (%s)", c->name, user->nick, c->name, line.c_str());\r          user->WriteServ("NOTICE %s :KNOCKing on %s",user->nick,c->name);\r               return CMD_SUCCESS;\r    }\r};\r\r/** Handles channel mode +K\r */\rclass Knock : public ModeHandler\r{\r public:\r      Knock(InspIRCd* Instance) : ModeHandler(Instance, 'K', 0, 0, false, MODETYPE_CHANNEL, false) { }\r\r      ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)\r {\r              if (adding)\r            {\r                      if (!channel->IsModeSet('K'))\r                  {\r                              channel->SetMode('K',true);\r                            return MODEACTION_ALLOW;\r                       }\r              }\r              else\r           {\r                      if (channel->IsModeSet('K'))\r                   {\r                              channel->SetMode('K',false);\r                           return MODEACTION_ALLOW;\r                       }\r              }\r\r             return MODEACTION_DENY;\r        }\r};\r\rclass ModuleKnock : public Module\r{\r      cmd_knock* mycommand;\r  Knock* kn;\r public:\r    ModuleKnock(InspIRCd* Me) : Module(Me)\r {\r              \r               kn = new Knock(ServerInstance);\r                if (!ServerInstance->AddMode(kn, 'K'))\r                 throw ModuleException("Could not add new modes!");\r             mycommand = new cmd_knock(ServerInstance);\r             ServerInstance->AddCommand(mycommand);\r }\r\r     void Implements(char* List)\r    {\r      }\r\r     virtual ~ModuleKnock()\r {\r              ServerInstance->Modes->DelMode(kn);\r            DELETE(kn);\r    }\r\r     virtual Version GetVersion()\r   {\r              return Version(1,1,0,1,VF_COMMON|VF_VENDOR,API_VERSION);\r       }\r};\r\rMODULE_INIT(ModuleKnock)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+
+/* $ModDesc: Provides support for /KNOCK and mode +K */
+
+/** Handles the /KNOCK command
+ */
+class cmd_knock : public command_t
+{
+ public:
+       cmd_knock (InspIRCd* Instance) : command_t(Instance,"KNOCK", 0, 2)
+       {
+               this->source = "m_knock.so";
+               syntax = "<channel> <reason>";
+       }
+       
+       CmdResult Handle (const char** parameters, int pcnt, userrec *user)
+       {
+               chanrec* c = ServerInstance->FindChan(parameters[0]);
+
+               if (!c)
+               {
+                       user->WriteServ("401 %s %s :No such channel",user->nick, parameters[0]);
+                       return CMD_FAILURE;
+               }
+
+               std::string line;
+
+               if (c->IsModeSet('K'))
+               {
+                       user->WriteServ("480 %s :Can't KNOCK on %s, +K is set.",user->nick, c->name);
+                       return CMD_FAILURE;
+               }
+
+               for (int i = 1; i < pcnt - 1; i++)
+               {
+                       line = line + std::string(parameters[i]) + " ";
+               }
+               line = line + std::string(parameters[pcnt-1]);
+
+               if (!c->modes[CM_INVITEONLY])
+               {
+                       user->WriteServ("480 %s :Can't KNOCK on %s, channel is not invite only so knocking is pointless!",user->nick, c->name);
+                       return CMD_FAILURE;
+               }
+
+               c->WriteChannelWithServ((char*)ServerInstance->Config->ServerName,  "NOTICE %s :User %s is KNOCKing on %s (%s)", c->name, user->nick, c->name, line.c_str());
+               user->WriteServ("NOTICE %s :KNOCKing on %s",user->nick,c->name);
+               return CMD_SUCCESS;
+       }
+};
+
+/** Handles channel mode +K
+ */
+class Knock : public ModeHandler
+{
+ public:
+       Knock(InspIRCd* Instance) : ModeHandler(Instance, 'K', 0, 0, false, MODETYPE_CHANNEL, false) { }
+
+       ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)
+       {
+               if (adding)
+               {
+                       if (!channel->IsModeSet('K'))
+                       {
+                               channel->SetMode('K',true);
+                               return MODEACTION_ALLOW;
+                       }
+               }
+               else
+               {
+                       if (channel->IsModeSet('K'))
+                       {
+                               channel->SetMode('K',false);
+                               return MODEACTION_ALLOW;
+                       }
+               }
+
+               return MODEACTION_DENY;
+       }
+};
+
+class ModuleKnock : public Module
+{
+       cmd_knock* mycommand;
+       Knock* kn;
+ public:
+       ModuleKnock(InspIRCd* Me) : Module(Me)
+       {
+               
+               kn = new Knock(ServerInstance);
+               if (!ServerInstance->AddMode(kn, 'K'))
+                       throw ModuleException("Could not add new modes!");
+               mycommand = new cmd_knock(ServerInstance);
+               ServerInstance->AddCommand(mycommand);
+       }
+
+       void Implements(char* List)
+       {
+       }
+
+       virtual ~ModuleKnock()
+       {
+               ServerInstance->Modes->DelMode(kn);
+               DELETE(kn);
+       }
+
+       virtual Version GetVersion()
+       {
+               return Version(1,1,0,1,VF_COMMON|VF_VENDOR,API_VERSION);
+       }
+};
+
+MODULE_INIT(ModuleKnock)
index d83961233413bc52c14038e5f7121375d7f109bf..2ca2e3f4412e9935957bec90eafd079d312e3123 100644 (file)
@@ -1 +1,131 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r\r/* $ModDesc: Allows locking of the server to stop all incoming connections till unlocked again */\r\r/** Adds numerics\r * 988 <nick> <servername> :Closed for new connections\r * 989 <nick> <servername> :Open for new connections\r*/\r\r\rclass cmd_lockserv : public command_t\r{\rprivate:\r       bool& locked;\r\rpublic:\r cmd_lockserv (InspIRCd* Instance, bool &lock)\r  : command_t(Instance, "LOCKSERV", 'o', 0), locked(lock)\r        {\r              this->source = "m_lockserv.so";\r                syntax.clear();\r        }\r\r     CmdResult Handle (const char** parameters, int pcnt, userrec *user)\r    {\r              locked = true;\r         user->WriteServ("988 %s %s :Closed for new connections", user->nick, user->server);\r            ServerInstance->WriteOpers("*** Oper %s used LOCKSERV to temporarily close for new connections", user->nick);\r          /* Dont send to the network */\r         return CMD_LOCALONLY;\r  }\r};\r\rclass cmd_unlockserv : public command_t\r{\rprivate:\r       bool& locked;\r\rpublic:\r cmd_unlockserv (InspIRCd* Instance, bool &lock)\r        : command_t(Instance, "UNLOCKSERV", 'o', 0), locked(lock)\r      {\r              this->source = "m_lockserv.so";\r                syntax.clear();\r        }\r\r     CmdResult Handle (const char** parameters, int pcnt, userrec *user)\r    {\r              locked = false;\r                user->WriteServ("989 %s %s :Open for new connections", user->nick, user->server);\r              ServerInstance->WriteOpers("*** Oper %s used UNLOCKSERV to allow for new connections", user->nick);\r            /* Dont send to the network */\r         return CMD_LOCALONLY;\r  }\r};\r\rclass ModuleLockserv : public Module\r{\rprivate:\r  bool locked;\r   cmd_lockserv* lockcommand;\r     cmd_unlockserv* unlockcommand;\r\r        virtual void ResetLocked()\r     {\r              locked = false;\r        }\r\rpublic:\r     ModuleLockserv(InspIRCd* Me) : Module(Me)\r      {\r              ResetLocked();\r         lockcommand = new cmd_lockserv(ServerInstance, locked);\r                ServerInstance->AddCommand(lockcommand);\r\r              unlockcommand = new cmd_unlockserv(ServerInstance, locked);\r            ServerInstance->AddCommand(unlockcommand);\r     }\r\r     virtual ~ModuleLockserv()\r      {\r      }\r\r     void Implements(char* List)\r    {\r              List[I_OnUserRegister] = List[I_OnRehash] = List[I_OnCheckReady] = 1;\r  }\r\r     virtual void OnRehash(userrec* user, const std::string &parameter)\r     {\r              ResetLocked();\r }\r\r     virtual int OnUserRegister(userrec* user)\r      {\r              if (locked)\r            {\r                      userrec::QuitUser(ServerInstance, user, "Server is temporarily closed. Please try again later.");\r                      return 1;\r              }\r              return 0;\r      }\r\r     virtual bool OnCheckReady(userrec* user)\r       {\r              return !locked;\r        }\r\r     virtual Version GetVersion()\r   {\r              return Version(1, 0, 0, 1, VF_VENDOR, API_VERSION);\r    }\r};\r\rMODULE_INIT(ModuleLockserv)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+
+/* $ModDesc: Allows locking of the server to stop all incoming connections till unlocked again */
+
+/** Adds numerics
+ * 988 <nick> <servername> :Closed for new connections
+ * 989 <nick> <servername> :Open for new connections
+*/
+
+
+class cmd_lockserv : public command_t
+{
+private:
+       bool& locked;
+
+public:
+       cmd_lockserv (InspIRCd* Instance, bool &lock)
+       : command_t(Instance, "LOCKSERV", 'o', 0), locked(lock)
+       {
+               this->source = "m_lockserv.so";
+               syntax.clear();
+       }
+
+       CmdResult Handle (const char** parameters, int pcnt, userrec *user)
+       {
+               locked = true;
+               user->WriteServ("988 %s %s :Closed for new connections", user->nick, user->server);
+               ServerInstance->WriteOpers("*** Oper %s used LOCKSERV to temporarily close for new connections", user->nick);
+               /* Dont send to the network */
+               return CMD_LOCALONLY;
+       }
+};
+
+class cmd_unlockserv : public command_t
+{
+private:
+       bool& locked;
+
+public:
+       cmd_unlockserv (InspIRCd* Instance, bool &lock)
+       : command_t(Instance, "UNLOCKSERV", 'o', 0), locked(lock)
+       {
+               this->source = "m_lockserv.so";
+               syntax.clear();
+       }
+
+       CmdResult Handle (const char** parameters, int pcnt, userrec *user)
+       {
+               locked = false;
+               user->WriteServ("989 %s %s :Open for new connections", user->nick, user->server);
+               ServerInstance->WriteOpers("*** Oper %s used UNLOCKSERV to allow for new connections", user->nick);
+               /* Dont send to the network */
+               return CMD_LOCALONLY;
+       }
+};
+
+class ModuleLockserv : public Module
+{
+private:
+       bool locked;
+       cmd_lockserv* lockcommand;
+       cmd_unlockserv* unlockcommand;
+
+       virtual void ResetLocked()
+       {
+               locked = false;
+       }
+
+public:
+       ModuleLockserv(InspIRCd* Me) : Module(Me)
+       {
+               ResetLocked();
+               lockcommand = new cmd_lockserv(ServerInstance, locked);
+               ServerInstance->AddCommand(lockcommand);
+
+               unlockcommand = new cmd_unlockserv(ServerInstance, locked);
+               ServerInstance->AddCommand(unlockcommand);
+       }
+
+       virtual ~ModuleLockserv()
+       {
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnUserRegister] = List[I_OnRehash] = List[I_OnCheckReady] = 1;
+       }
+
+       virtual void OnRehash(userrec* user, const std::string &parameter)
+       {
+               ResetLocked();
+       }
+
+       virtual int OnUserRegister(userrec* user)
+       {
+               if (locked)
+               {
+                       userrec::QuitUser(ServerInstance, user, "Server is temporarily closed. Please try again later.");
+                       return 1;
+               }
+               return 0;
+       }
+
+       virtual bool OnCheckReady(userrec* user)
+       {
+               return !locked;
+       }
+
+       virtual Version GetVersion()
+       {
+               return Version(1, 0, 0, 1, VF_VENDOR, API_VERSION);
+       }
+};
+
+MODULE_INIT(ModuleLockserv)
index c9b062e43e15b849aef2fe165b8b42e6abce6c2e..3b7df836994ce1d24219d95184745cd9206919d7 100644 (file)
@@ -1 +1,322 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r/* $ModDesc: Allows for MD5 encrypted oper passwords */\r/* $ModDep: m_hash.h */\r\r#include "inspircd.h"\r#ifdef HAS_STDINT\r#include <stdint.h>\r#endif\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r#include "m_hash.h"\r\r/* The four core functions - F1 is optimized somewhat */\r#define F1(x, y, z) (z ^ (x & (y ^ z)))\r#define F2(x, y, z) F1(z, x, y)\r#define F3(x, y, z) (x ^ y ^ z)\r#define F4(x, y, z) (y ^ (x | ~z))\r\r/* This is the central step in the MD5 algorithm. */\r#define MD5STEP(f,w,x,y,z,in,s) \\r        (w += f(x,y,z) + in, w = (w<<s | w>>(32-s)) + x)\r\r#ifndef HAS_STDINT\rtypedef unsigned int uint32_t;\r#endif\r\rtypedef uint32_t word32; /* NOT unsigned long. We don't support 16 bit platforms, anyway. */\rtypedef unsigned char byte;\r\r/** An MD5 context, used by m_opermd5\r */\rclass MD5Context : public classbase\r{\r public:\r word32 buf[4];\r word32 bytes[2];\r       word32 in[16];\r};\r\rclass ModuleMD5 : public Module\r{\r   void byteSwap(word32 *buf, unsigned words)\r     {\r              byte *p = (byte *)buf;\r \r               do\r             {\r                      *buf++ = (word32)((unsigned)p[3] << 8 | p[2]) << 16 |\r                          ((unsigned)p[1] << 8 | p[0]);\r                  p += 4;\r                } while (--words);\r     }\r\r     void MD5Init(MD5Context *ctx, unsigned int* key = NULL)\r        {\r              /* These are the defaults for md5 */\r           if (!key)\r              {\r                      ctx->buf[0] = 0x67452301;\r                      ctx->buf[1] = 0xefcdab89;\r                      ctx->buf[2] = 0x98badcfe;\r                      ctx->buf[3] = 0x10325476;\r              }\r              else\r           {\r                      ctx->buf[0] = key[0];\r                  ctx->buf[1] = key[1];\r                  ctx->buf[2] = key[2];\r                  ctx->buf[3] = key[3];\r          }\r      \r               ctx->bytes[0] = 0;\r             ctx->bytes[1] = 0;\r     }\r\r     void MD5Update(MD5Context *ctx, byte const *buf, int len)\r      {\r              word32 t;\r      \r               /* Update byte count */\r        \r               t = ctx->bytes[0];\r             if ((ctx->bytes[0] = t + len) < t)\r                     ctx->bytes[1]++;        /* Carry from low to high */\r   \r               t = 64 - (t & 0x3f);    /* Space available in ctx->in (at least 1) */\r          if ((unsigned)t > (unsigned)len)\r               {\r                      memcpy((byte *)ctx->in + 64 - (unsigned)t, buf, len);\r                  return;\r                }\r              /* First chunk is an odd size */\r               memcpy((byte *)ctx->in + 64 - (unsigned)t, buf, (unsigned)t);\r          byteSwap(ctx->in, 16);\r         MD5Transform(ctx->buf, ctx->in);\r               buf += (unsigned)t;\r            len -= (unsigned)t;\r    \r               /* Process data in 64-byte chunks */\r           while (len >= 64)\r              {\r                      memcpy(ctx->in, buf, 64);\r                      byteSwap(ctx->in, 16);\r                 MD5Transform(ctx->buf, ctx->in);\r                       buf += 64;\r                     len -= 64;\r             }\r      \r               /* Handle any remaining bytes of data. */\r              memcpy(ctx->in, buf, len);\r     }\r      \r       void MD5Final(byte digest[16], MD5Context *ctx)\r        {\r              int count = (int)(ctx->bytes[0] & 0x3f); /* Bytes in ctx->in */\r                byte *p = (byte *)ctx->in + count;      /* First unused byte */\r        \r               /* Set the first char of padding to 0x80.  There is always room. */\r            *p++ = 0x80;\r   \r               /* Bytes of padding needed to make 56 bytes (-8..55) */\r                count = 56 - 1 - count;\r        \r               if (count < 0)\r         {       /* Padding forces an extra block */\r                    memset(p, 0, count+8);\r                 byteSwap(ctx->in, 16);\r                 MD5Transform(ctx->buf, ctx->in);\r                       p = (byte *)ctx->in;\r                   count = 56;\r            }\r              memset(p, 0, count+8);\r         byteSwap(ctx->in, 14);\r \r               /* Append length in bits and transform */\r              ctx->in[14] = ctx->bytes[0] << 3;\r              ctx->in[15] = ctx->bytes[1] << 3 | ctx->bytes[0] >> 29;\r                MD5Transform(ctx->buf, ctx->in);\r       \r               byteSwap(ctx->buf, 4);\r         memcpy(digest, ctx->buf, 16);\r          memset(ctx, 0, sizeof(ctx));\r   }\r      \r       void MD5Transform(word32 buf[4], word32 const in[16])\r  {\r              register word32 a, b, c, d;\r    \r               a = buf[0];\r            b = buf[1];\r            c = buf[2];\r            d = buf[3];\r    \r               MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);\r                MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);\r               MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);\r               MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);\r               MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);\r                MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);\r               MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);\r               MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);\r               MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);\r                MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);\r               MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);\r              MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);\r              MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);\r               MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);\r              MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);\r              MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);\r      \r               MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);\r                MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);\r                MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);\r              MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);\r               MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);\r                MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);\r               MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);\r              MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);\r               MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);\r                MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);\r               MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);\r               MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);\r               MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);\r               MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);\r                MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);\r               MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);\r      \r               MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);\r                MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);\r               MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);\r              MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);\r              MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);\r                MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);\r               MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);\r               MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);\r              MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);\r               MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);\r               MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);\r               MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);\r               MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);\r                MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);\r              MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);\r              MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);\r       \r               MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);\r                MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);\r               MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);\r              MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);\r               MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);\r               MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);\r               MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);\r              MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);\r               MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);\r                MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);\r              MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);\r               MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);\r              MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);\r                MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);\r              MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);\r               MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);\r       \r               buf[0] += a;\r           buf[1] += b;\r           buf[2] += c;\r           buf[3] += d;\r   }\r      \r       \r       void MyMD5(void *dest, void *orig, int len, unsigned int* key)\r {\r              MD5Context context;\r            MD5Init(&context, key);\r                MD5Update(&context, (const unsigned char*)orig, len);\r          MD5Final((unsigned char*)dest, &context);\r      }\r      \r       \r       void GenHash(const char* src, char* dest, const char* xtab, unsigned int* key)\r {\r              unsigned char bytes[16];\r\r              MyMD5((char*)bytes, (void*)src, strlen(src), key);\r\r            for (int i = 0; i < 16; i++)\r           {\r                      *dest++ = xtab[bytes[i] / 16];\r                 *dest++ = xtab[bytes[i] % 16];\r         }\r              *dest++ = 0;\r   }\r\r     unsigned int *key;\r     char* chars;\r\r public:\r\r        ModuleMD5(InspIRCd* Me)\r                : Module(Me), key(NULL), chars(NULL)\r   {\r              ServerInstance->PublishInterface("HashRequest", this);\r }\r      \r       virtual ~ModuleMD5()\r   {\r              ServerInstance->UnpublishInterface("HashRequest", this);\r       }\r\r     void Implements(char* List)\r    {\r              List[I_OnRequest] = 1;\r }\r      \r       virtual char* OnRequest(Request* request)\r      {\r              HashRequest* MD5 = (HashRequest*)request;\r\r             if (strcmp("KEY", request->GetId()) == 0)\r              {\r                      this->key = (unsigned int*)MD5->GetKeyData();\r          }\r              else if (strcmp("HEX", request->GetId()) == 0)\r         {\r                      this->chars = (char*)MD5->GetOutputs();\r                }\r              else if (strcmp("SUM", request->GetId()) == 0)\r         {\r                      static char data[MAXBUF];\r                      GenHash((const char*)MD5->GetHashData(), data, chars ? chars : "0123456789abcdef", key);\r                       return data;\r           }\r              else if (strcmp("NAME", request->GetId()) == 0)\r                {\r                      return "md5";\r          }\r              else if (strcmp("RESET", request->GetId()) == 0)\r               {\r                      this->chars = NULL;\r                    this->key = NULL;\r              }\r              return NULL;\r   }\r\r     virtual Version GetVersion()\r   {\r              return Version(1,1,0,1,VF_VENDOR|VF_SERVICEPROVIDER,API_VERSION);\r      }\r};\r\rMODULE_INIT(ModuleMD5)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+/* $ModDesc: Allows for MD5 encrypted oper passwords */
+/* $ModDep: m_hash.h */
+
+#include "inspircd.h"
+#ifdef HAS_STDINT
+#include <stdint.h>
+#endif
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+#include "m_hash.h"
+
+/* The four core functions - F1 is optimized somewhat */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f,w,x,y,z,in,s) \
+       (w += f(x,y,z) + in, w = (w<<s | w>>(32-s)) + x)
+
+#ifndef HAS_STDINT
+typedef unsigned int uint32_t;
+#endif
+
+typedef uint32_t word32; /* NOT unsigned long. We don't support 16 bit platforms, anyway. */
+typedef unsigned char byte;
+
+/** An MD5 context, used by m_opermd5
+ */
+class MD5Context : public classbase
+{
+ public:
+       word32 buf[4];
+       word32 bytes[2];
+       word32 in[16];
+};
+
+class ModuleMD5 : public Module
+{
+       void byteSwap(word32 *buf, unsigned words)
+       {
+               byte *p = (byte *)buf;
+       
+               do
+               {
+                       *buf++ = (word32)((unsigned)p[3] << 8 | p[2]) << 16 |
+                               ((unsigned)p[1] << 8 | p[0]);
+                       p += 4;
+               } while (--words);
+       }
+
+       void MD5Init(MD5Context *ctx, unsigned int* key = NULL)
+       {
+               /* These are the defaults for md5 */
+               if (!key)
+               {
+                       ctx->buf[0] = 0x67452301;
+                       ctx->buf[1] = 0xefcdab89;
+                       ctx->buf[2] = 0x98badcfe;
+                       ctx->buf[3] = 0x10325476;
+               }
+               else
+               {
+                       ctx->buf[0] = key[0];
+                       ctx->buf[1] = key[1];
+                       ctx->buf[2] = key[2];
+                       ctx->buf[3] = key[3];
+               }
+       
+               ctx->bytes[0] = 0;
+               ctx->bytes[1] = 0;
+       }
+
+       void MD5Update(MD5Context *ctx, byte const *buf, int len)
+       {
+               word32 t;
+       
+               /* Update byte count */
+       
+               t = ctx->bytes[0];
+               if ((ctx->bytes[0] = t + len) < t)
+                       ctx->bytes[1]++;        /* Carry from low to high */
+       
+               t = 64 - (t & 0x3f);    /* Space available in ctx->in (at least 1) */
+               if ((unsigned)t > (unsigned)len)
+               {
+                       memcpy((byte *)ctx->in + 64 - (unsigned)t, buf, len);
+                       return;
+               }
+               /* First chunk is an odd size */
+               memcpy((byte *)ctx->in + 64 - (unsigned)t, buf, (unsigned)t);
+               byteSwap(ctx->in, 16);
+               MD5Transform(ctx->buf, ctx->in);
+               buf += (unsigned)t;
+               len -= (unsigned)t;
+       
+               /* Process data in 64-byte chunks */
+               while (len >= 64)
+               {
+                       memcpy(ctx->in, buf, 64);
+                       byteSwap(ctx->in, 16);
+                       MD5Transform(ctx->buf, ctx->in);
+                       buf += 64;
+                       len -= 64;
+               }
+       
+               /* Handle any remaining bytes of data. */
+               memcpy(ctx->in, buf, len);
+       }
+       
+       void MD5Final(byte digest[16], MD5Context *ctx)
+       {
+               int count = (int)(ctx->bytes[0] & 0x3f); /* Bytes in ctx->in */
+               byte *p = (byte *)ctx->in + count;      /* First unused byte */
+       
+               /* Set the first char of padding to 0x80.  There is always room. */
+               *p++ = 0x80;
+       
+               /* Bytes of padding needed to make 56 bytes (-8..55) */
+               count = 56 - 1 - count;
+       
+               if (count < 0)
+               {       /* Padding forces an extra block */
+                       memset(p, 0, count+8);
+                       byteSwap(ctx->in, 16);
+                       MD5Transform(ctx->buf, ctx->in);
+                       p = (byte *)ctx->in;
+                       count = 56;
+               }
+               memset(p, 0, count+8);
+               byteSwap(ctx->in, 14);
+       
+               /* Append length in bits and transform */
+               ctx->in[14] = ctx->bytes[0] << 3;
+               ctx->in[15] = ctx->bytes[1] << 3 | ctx->bytes[0] >> 29;
+               MD5Transform(ctx->buf, ctx->in);
+       
+               byteSwap(ctx->buf, 4);
+               memcpy(digest, ctx->buf, 16);
+               memset(ctx, 0, sizeof(ctx));
+       }
+       
+       void MD5Transform(word32 buf[4], word32 const in[16])
+       {
+               register word32 a, b, c, d;
+       
+               a = buf[0];
+               b = buf[1];
+               c = buf[2];
+               d = buf[3];
+       
+               MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
+               MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
+               MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
+               MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
+               MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
+               MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
+               MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
+               MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
+               MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
+               MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
+               MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+               MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+               MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
+               MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+               MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+               MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+       
+               MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
+               MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
+               MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+               MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
+               MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
+               MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
+               MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+               MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
+               MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
+               MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+               MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
+               MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
+               MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+               MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
+               MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
+               MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+       
+               MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
+               MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
+               MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+               MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+               MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
+               MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
+               MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
+               MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+               MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+               MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
+               MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
+               MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
+               MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
+               MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+               MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+               MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
+       
+               MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
+               MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
+               MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+               MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
+               MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+               MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
+               MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+               MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
+               MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
+               MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+               MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
+               MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+               MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
+               MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+               MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
+               MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
+       
+               buf[0] += a;
+               buf[1] += b;
+               buf[2] += c;
+               buf[3] += d;
+       }
+       
+       
+       void MyMD5(void *dest, void *orig, int len, unsigned int* key)
+       {
+               MD5Context context;
+               MD5Init(&context, key);
+               MD5Update(&context, (const unsigned char*)orig, len);
+               MD5Final((unsigned char*)dest, &context);
+       }
+       
+       
+       void GenHash(const char* src, char* dest, const char* xtab, unsigned int* key)
+       {
+               unsigned char bytes[16];
+
+               MyMD5((char*)bytes, (void*)src, strlen(src), key);
+
+               for (int i = 0; i < 16; i++)
+               {
+                       *dest++ = xtab[bytes[i] / 16];
+                       *dest++ = xtab[bytes[i] % 16];
+               }
+               *dest++ = 0;
+       }
+
+       unsigned int *key;
+       char* chars;
+
+ public:
+
+       ModuleMD5(InspIRCd* Me)
+               : Module(Me), key(NULL), chars(NULL)
+       {
+               ServerInstance->PublishInterface("HashRequest", this);
+       }
+       
+       virtual ~ModuleMD5()
+       {
+               ServerInstance->UnpublishInterface("HashRequest", this);
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnRequest] = 1;
+       }
+       
+       virtual char* OnRequest(Request* request)
+       {
+               HashRequest* MD5 = (HashRequest*)request;
+
+               if (strcmp("KEY", request->GetId()) == 0)
+               {
+                       this->key = (unsigned int*)MD5->GetKeyData();
+               }
+               else if (strcmp("HEX", request->GetId()) == 0)
+               {
+                       this->chars = (char*)MD5->GetOutputs();
+               }
+               else if (strcmp("SUM", request->GetId()) == 0)
+               {
+                       static char data[MAXBUF];
+                       GenHash((const char*)MD5->GetHashData(), data, chars ? chars : "0123456789abcdef", key);
+                       return data;
+               }
+               else if (strcmp("NAME", request->GetId()) == 0)
+               {
+                       return "md5";
+               }
+               else if (strcmp("RESET", request->GetId()) == 0)
+               {
+                       this->chars = NULL;
+                       this->key = NULL;
+               }
+               return NULL;
+       }
+
+       virtual Version GetVersion()
+       {
+               return Version(1,1,0,1,VF_VENDOR|VF_SERVICEPROVIDER,API_VERSION);
+       }
+};
+
+MODULE_INIT(ModuleMD5)
index e5263719b3c5d106e4e98166316139fbb14972d1..a942262ed6ff1c1fb5f598bd8a78934de1bd08ca 100644 (file)
@@ -1 +1,304 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r\r/* $ModDesc: Provides channel mode +f (message flood protection) */\r\r/** Holds flood settings and state for mode +f\r */\rclass floodsettings : public classbase\r{\r public:\r    bool ban;\r      int secs;\r      int lines;\r     time_t reset;\r  std::map<userrec*,int> counters;\r\r      floodsettings() : ban(0), secs(0), lines(0) {};\r        floodsettings(bool a, int b, int c) : ban(a), secs(b), lines(c)\r        {\r              reset = time(NULL) + secs;\r     };\r\r    void addmessage(userrec* who)\r  {\r              std::map<userrec*,int>::iterator iter = counters.find(who);\r            if (iter != counters.end())\r            {\r                      iter->second++;\r                }\r              else\r           {\r                      counters[who] = 1;\r             }\r              if (time(NULL) > reset)\r                {\r                      counters.clear();\r                      reset = time(NULL) + secs;\r             }\r      }\r\r     bool shouldkick(userrec* who)\r  {\r              std::map<userrec*,int>::iterator iter = counters.find(who);\r            if (iter != counters.end())\r            {\r                      return (iter->second >= this->lines);\r          }\r              else return false;\r     }\r\r     void clear(userrec* who)\r       {\r              std::map<userrec*,int>::iterator iter = counters.find(who);\r            if (iter != counters.end())\r            {\r                      counters.erase(iter);\r          }\r      }\r};\r\r/** Handles channel mode +f\r */\rclass MsgFlood : public ModeHandler\r{\r public:\r   MsgFlood(InspIRCd* Instance) : ModeHandler(Instance, 'f', 1, 0, false, MODETYPE_CHANNEL, false) { }\r\r   ModePair ModeSet(userrec* source, userrec* dest, chanrec* channel, const std::string &parameter)\r       {\r              floodsettings* x;\r              if (channel->GetExt("flood",x))\r                        return std::make_pair(true, (x->ban ? "*" : "")+ConvToStr(x->lines)+":"+ConvToStr(x->secs));\r           else\r                   return std::make_pair(false, parameter);\r       }\r\r     bool CheckTimeStamp(time_t theirs, time_t ours, const std::string &their_param, const std::string &our_param, chanrec* channel)\r        {\r              /* When TS is equal, the alphabetically later one wins */\r              return (their_param < our_param);\r      }\r\r     ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)\r {\r              floodsettings *f;\r\r             if (adding)\r            {\r                      char ndata[MAXBUF];\r                    char* data = ndata;\r                    strlcpy(ndata,parameter.c_str(),MAXBUF);\r                       char* lines = data;\r                    char* secs = NULL;\r                     bool ban = false;\r                      if (*data == '*')\r                      {\r                              ban = true;\r                            lines++;\r                       }\r                      else\r                   {\r                              ban = false;\r                   }\r                      while (*data)\r                  {\r                              if (*data == ':')\r                              {\r                                      *data = 0;\r                                     data++;\r                                        secs = data;\r                                   break;\r                         }\r                              else data++;\r                   }\r                      if (secs)\r                      {\r                              /* Set up the flood parameters for this channel */\r                             int nlines = atoi(lines);\r                              int nsecs = atoi(secs);\r                                if ((nlines<1) || (nsecs<1))\r                           {\r                                      source->WriteServ("608 %s %s :Invalid flood parameter",source->nick,channel->name);\r                                    parameter.clear();\r                                     return MODEACTION_DENY;\r                                }\r                              else\r                           {\r                                      if (!channel->GetExt("flood", f))\r                                      {\r                                              parameter = std::string(ban ? "*" : "") + ConvToStr(nlines) + ":" +ConvToStr(nsecs);\r                                           floodsettings *f = new floodsettings(ban,nsecs,nlines);\r                                                channel->Extend("flood",f);\r                                            channel->SetMode('f', true);\r                                           channel->SetModeParam('f', parameter.c_str(), true);\r                                           return MODEACTION_ALLOW;\r                                       }\r                                      else\r                                   {\r                                              std::string cur_param = channel->GetModeParameter('f');\r                                                parameter = std::string(ban ? "*" : "") + ConvToStr(nlines) + ":" +ConvToStr(nsecs);\r                                           if (cur_param == parameter)\r                                            {\r                                                      // mode params match\r                                                   return MODEACTION_DENY;\r                                                }\r                                              else\r                                           {\r                                                      if (((nlines != f->lines) || (nsecs != f->secs)) && ((nsecs > 0) && (nlines > 0)) || (ban != f->ban))\r                                                  {\r                                                              delete f;\r                                                              floodsettings *f = new floodsettings(ban,nsecs,nlines);\r                                                                channel->Shrink("flood");\r                                                              channel->Extend("flood",f);\r                                                            channel->SetModeParam('f', cur_param.c_str(), false);\r                                                          channel->SetModeParam('f', parameter.c_str(), true);\r                                                           return MODEACTION_ALLOW;\r                                                       }\r                                                      else\r                                                   {\r                                                              return MODEACTION_DENY;\r                                                        }\r                                              }\r                                      }\r                              }\r                      }\r                      else\r                   {\r                              source->WriteServ("608 %s %s :Invalid flood parameter",source->nick,channel->name);\r                            parameter.clear();\r                             return MODEACTION_DENY;\r                        }\r              }\r              else\r           {\r                      if (channel->GetExt("flood", f))\r                       {\r                              DELETE(f);\r                             channel->Shrink("flood");\r                              channel->SetMode('f', false);\r                          return MODEACTION_ALLOW;\r                       }\r              }\r              \r               return MODEACTION_DENY;\r        }\r};\r\rclass ModuleMsgFlood : public Module\r{\r   \r       MsgFlood* mf;\r  \r public:\r \r    ModuleMsgFlood(InspIRCd* Me)\r           : Module(Me)\r   {\r              \r               mf = new MsgFlood(ServerInstance);\r             if (!ServerInstance->AddMode(mf, 'f'))\r                 throw ModuleException("Could not add new modes!");\r     }\r      \r       void ProcessMessages(userrec* user,chanrec* dest, const std::string &text)\r     {\r              if (!IS_LOCAL(user) || CHANOPS_EXEMPT(ServerInstance, 'f') && dest->GetStatus(user) == STATUS_OP)\r              {\r                      return;\r                }\r\r             floodsettings *f;\r              if (dest->GetExt("flood", f))\r          {\r                      f->addmessage(user);\r                   if (f->shouldkick(user))\r                       {\r                              /* Youre outttta here! */\r                              f->clear(user);\r                                if (f->ban)\r                            {\r                                      const char* parameters[3];\r                                     parameters[0] = dest->name;\r                                    parameters[1] = "+b";\r                                  parameters[2] = user->MakeWildHost();\r                                  ServerInstance->SendMode(parameters,3,user);\r                                   std::deque<std::string> n;\r                                     /* Propogate the ban to other servers.\r                                  * We dont know what protocol we may be using,\r                                  * so this event is picked up by our protocol\r                                   * module and formed into a ban command that\r                                    * suits the protocol in use.\r                                   */\r                                    n.push_back(dest->name);\r                                       n.push_back("+b");\r                                     n.push_back(user->MakeWildHost());\r                                     Event rmode((char *)&n, NULL, "send_mode");\r                                    rmode.Send(ServerInstance);\r                            }\r                              char kickmessage[MAXBUF];\r                              snprintf(kickmessage, MAXBUF, "Channel flood triggered (limit is %d lines in %d secs)", f->lines, f->secs);\r                            dest->ServerKickUser(user, kickmessage, true);\r                 }\r              }\r      }\r\r     virtual void OnUserMessage(userrec* user, void* dest, int target_type, const std::string &text, char status, const CUList &exempt_list)\r        {\r              if (target_type == TYPE_CHANNEL)\r               {\r                      ProcessMessages(user,(chanrec*)dest,text);\r             }\r      }\r\r     virtual void OnUserNotice(userrec* user, void* dest, int target_type, const std::string &text, char status, const CUList &exempt_list)\r {\r              if (target_type == TYPE_CHANNEL)\r               {\r                      ProcessMessages(user,(chanrec*)dest,text);\r             }\r      }\r\r     void OnChannelDelete(chanrec* chan)\r    {\r              floodsettings* f;\r              if (chan->GetExt("flood", f))\r          {\r                      DELETE(f);\r                     chan->Shrink("flood");\r         }\r      }\r\r     void Implements(char* List)\r    {\r              List[I_OnChannelDelete] = List[I_OnUserNotice] = List[I_OnUserMessage] = 1;\r    }\r\r     virtual ~ModuleMsgFlood()\r      {\r              ServerInstance->Modes->DelMode(mf);\r            DELETE(mf);\r    }\r      \r       virtual Version GetVersion()\r   {\r              return Version(1, 1, 0, 0, VF_COMMON | VF_VENDOR, API_VERSION);\r        }\r};\r\rMODULE_INIT(ModuleMsgFlood)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+
+/* $ModDesc: Provides channel mode +f (message flood protection) */
+
+/** Holds flood settings and state for mode +f
+ */
+class floodsettings : public classbase
+{
+ public:
+       bool ban;
+       int secs;
+       int lines;
+       time_t reset;
+       std::map<userrec*,int> counters;
+
+       floodsettings() : ban(0), secs(0), lines(0) {};
+       floodsettings(bool a, int b, int c) : ban(a), secs(b), lines(c)
+       {
+               reset = time(NULL) + secs;
+       };
+
+       void addmessage(userrec* who)
+       {
+               std::map<userrec*,int>::iterator iter = counters.find(who);
+               if (iter != counters.end())
+               {
+                       iter->second++;
+               }
+               else
+               {
+                       counters[who] = 1;
+               }
+               if (time(NULL) > reset)
+               {
+                       counters.clear();
+                       reset = time(NULL) + secs;
+               }
+       }
+
+       bool shouldkick(userrec* who)
+       {
+               std::map<userrec*,int>::iterator iter = counters.find(who);
+               if (iter != counters.end())
+               {
+                       return (iter->second >= this->lines);
+               }
+               else return false;
+       }
+
+       void clear(userrec* who)
+       {
+               std::map<userrec*,int>::iterator iter = counters.find(who);
+               if (iter != counters.end())
+               {
+                       counters.erase(iter);
+               }
+       }
+};
+
+/** Handles channel mode +f
+ */
+class MsgFlood : public ModeHandler
+{
+ public:
+       MsgFlood(InspIRCd* Instance) : ModeHandler(Instance, 'f', 1, 0, false, MODETYPE_CHANNEL, false) { }
+
+       ModePair ModeSet(userrec* source, userrec* dest, chanrec* channel, const std::string &parameter)
+       {
+               floodsettings* x;
+               if (channel->GetExt("flood",x))
+                       return std::make_pair(true, (x->ban ? "*" : "")+ConvToStr(x->lines)+":"+ConvToStr(x->secs));
+               else
+                       return std::make_pair(false, parameter);
+       }
+
+       bool CheckTimeStamp(time_t theirs, time_t ours, const std::string &their_param, const std::string &our_param, chanrec* channel)
+       {
+               /* When TS is equal, the alphabetically later one wins */
+               return (their_param < our_param);
+       }
+
+       ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)
+       {
+               floodsettings *f;
+
+               if (adding)
+               {
+                       char ndata[MAXBUF];
+                       char* data = ndata;
+                       strlcpy(ndata,parameter.c_str(),MAXBUF);
+                       char* lines = data;
+                       char* secs = NULL;
+                       bool ban = false;
+                       if (*data == '*')
+                       {
+                               ban = true;
+                               lines++;
+                       }
+                       else
+                       {
+                               ban = false;
+                       }
+                       while (*data)
+                       {
+                               if (*data == ':')
+                               {
+                                       *data = 0;
+                                       data++;
+                                       secs = data;
+                                       break;
+                               }
+                               else data++;
+                       }
+                       if (secs)
+                       {
+                               /* Set up the flood parameters for this channel */
+                               int nlines = atoi(lines);
+                               int nsecs = atoi(secs);
+                               if ((nlines<1) || (nsecs<1))
+                               {
+                                       source->WriteServ("608 %s %s :Invalid flood parameter",source->nick,channel->name);
+                                       parameter.clear();
+                                       return MODEACTION_DENY;
+                               }
+                               else
+                               {
+                                       if (!channel->GetExt("flood", f))
+                                       {
+                                               parameter = std::string(ban ? "*" : "") + ConvToStr(nlines) + ":" +ConvToStr(nsecs);
+                                               floodsettings *f = new floodsettings(ban,nsecs,nlines);
+                                               channel->Extend("flood",f);
+                                               channel->SetMode('f', true);
+                                               channel->SetModeParam('f', parameter.c_str(), true);
+                                               return MODEACTION_ALLOW;
+                                       }
+                                       else
+                                       {
+                                               std::string cur_param = channel->GetModeParameter('f');
+                                               parameter = std::string(ban ? "*" : "") + ConvToStr(nlines) + ":" +ConvToStr(nsecs);
+                                               if (cur_param == parameter)
+                                               {
+                                                       // mode params match
+                                                       return MODEACTION_DENY;
+                                               }
+                                               else
+                                               {
+                                                       if (((nlines != f->lines) || (nsecs != f->secs)) && ((nsecs > 0) && (nlines > 0)) || (ban != f->ban))
+                                                       {
+                                                               delete f;
+                                                               floodsettings *f = new floodsettings(ban,nsecs,nlines);
+                                                               channel->Shrink("flood");
+                                                               channel->Extend("flood",f);
+                                                               channel->SetModeParam('f', cur_param.c_str(), false);
+                                                               channel->SetModeParam('f', parameter.c_str(), true);
+                                                               return MODEACTION_ALLOW;
+                                                       }
+                                                       else
+                                                       {
+                                                               return MODEACTION_DENY;
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+                       else
+                       {
+                               source->WriteServ("608 %s %s :Invalid flood parameter",source->nick,channel->name);
+                               parameter.clear();
+                               return MODEACTION_DENY;
+                       }
+               }
+               else
+               {
+                       if (channel->GetExt("flood", f))
+                       {
+                               DELETE(f);
+                               channel->Shrink("flood");
+                               channel->SetMode('f', false);
+                               return MODEACTION_ALLOW;
+                       }
+               }
+               
+               return MODEACTION_DENY;
+       }
+};
+
+class ModuleMsgFlood : public Module
+{
+       
+       MsgFlood* mf;
+       
+ public:
+       ModuleMsgFlood(InspIRCd* Me)
+               : Module(Me)
+       {
+               
+               mf = new MsgFlood(ServerInstance);
+               if (!ServerInstance->AddMode(mf, 'f'))
+                       throw ModuleException("Could not add new modes!");
+       }
+       
+       void ProcessMessages(userrec* user,chanrec* dest, const std::string &text)
+       {
+               if (!IS_LOCAL(user) || CHANOPS_EXEMPT(ServerInstance, 'f') && dest->GetStatus(user) == STATUS_OP)
+               {
+                       return;
+               }
+
+               floodsettings *f;
+               if (dest->GetExt("flood", f))
+               {
+                       f->addmessage(user);
+                       if (f->shouldkick(user))
+                       {
+                               /* Youre outttta here! */
+                               f->clear(user);
+                               if (f->ban)
+                               {
+                                       const char* parameters[3];
+                                       parameters[0] = dest->name;
+                                       parameters[1] = "+b";
+                                       parameters[2] = user->MakeWildHost();
+                                       ServerInstance->SendMode(parameters,3,user);
+                                       std::deque<std::string> n;
+                                       /* Propogate the ban to other servers.
+                                        * We dont know what protocol we may be using,
+                                        * so this event is picked up by our protocol
+                                        * module and formed into a ban command that
+                                        * suits the protocol in use.
+                                        */
+                                       n.push_back(dest->name);
+                                       n.push_back("+b");
+                                       n.push_back(user->MakeWildHost());
+                                       Event rmode((char *)&n, NULL, "send_mode");
+                                       rmode.Send(ServerInstance);
+                               }
+                               char kickmessage[MAXBUF];
+                               snprintf(kickmessage, MAXBUF, "Channel flood triggered (limit is %d lines in %d secs)", f->lines, f->secs);
+                               dest->ServerKickUser(user, kickmessage, true);
+                       }
+               }
+       }
+
+       virtual void OnUserMessage(userrec* user, void* dest, int target_type, const std::string &text, char status, const CUList &exempt_list)
+       {
+               if (target_type == TYPE_CHANNEL)
+               {
+                       ProcessMessages(user,(chanrec*)dest,text);
+               }
+       }
+
+       virtual void OnUserNotice(userrec* user, void* dest, int target_type, const std::string &text, char status, const CUList &exempt_list)
+       {
+               if (target_type == TYPE_CHANNEL)
+               {
+                       ProcessMessages(user,(chanrec*)dest,text);
+               }
+       }
+
+       void OnChannelDelete(chanrec* chan)
+       {
+               floodsettings* f;
+               if (chan->GetExt("flood", f))
+               {
+                       DELETE(f);
+                       chan->Shrink("flood");
+               }
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnChannelDelete] = List[I_OnUserNotice] = List[I_OnUserMessage] = 1;
+       }
+
+       virtual ~ModuleMsgFlood()
+       {
+               ServerInstance->Modes->DelMode(mf);
+               DELETE(mf);
+       }
+       
+       virtual Version GetVersion()
+       {
+               return Version(1, 1, 0, 0, VF_COMMON | VF_VENDOR, API_VERSION);
+       }
+};
+
+MODULE_INIT(ModuleMsgFlood)
index 37f5843314a72f7b4451b0d14a872503aebcaef8..c45d777f857c2cba161005b7bf6bf386e0f60818 100644 (file)
@@ -1 +1,127 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r\rstatic const char* dummy = "ON";\r\r/* $ModDesc: Provides aliases of commands. */\r\rclass ModuleNamesX : public Module\r{\r public:\r       \r       ModuleNamesX(InspIRCd* Me)\r             : Module(Me)\r   {\r      }\r\r     void Implements(char* List)\r    {\r              List[I_OnSyncUserMetaData] = List[I_OnPreCommand] = List[I_OnUserList] = List[I_On005Numeric] = 1;\r     }\r\r     virtual ~ModuleNamesX()\r        {\r      }\r\r     void OnSyncUserMetaData(userrec* user, Module* proto,void* opaque, const std::string &extname, bool displayable)\r       {\r              if ((displayable) && (extname == "NAMESX"))\r                    proto->ProtoSendMetaData(opaque, TYPE_USER, user, extname, "Enabled");\r }\r\r     virtual Version GetVersion()\r   {\r              return Version(1,1,0,1,VF_VENDOR,API_VERSION);\r }\r\r     virtual void On005Numeric(std::string &output)\r {\r              output.append(" NAMESX");\r      }\r\r     virtual int OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line)\r       {\r              irc::string c = command.c_str();\r               /* We don't actually create a proper command handler class for PROTOCTL,\r                * because other modules might want to have PROTOCTL hooks too.\r                 * Therefore, we just hook its as an unvalidated command therefore we\r           * can capture it even if it doesnt exist! :-)\r          */\r            if (c == "PROTOCTL")\r           {\r                      if ((pcnt) && (!strcasecmp(parameters[0],"NAMESX")))\r                   {\r                              user->Extend("NAMESX",dummy);\r                          return 1;\r                      }\r              }\r              return 0;\r      }\r\r     virtual int OnUserList(userrec* user, chanrec* Ptr, CUList* &ulist)\r    {\r              if (user->GetExt("NAMESX"))\r            {\r                      char list[MAXBUF];\r                     size_t dlen, curlen;\r                   dlen = curlen = snprintf(list,MAXBUF,"353 %s = %s :", user->nick, Ptr->name);\r                  int numusers = 0;\r                      char* ptr = list + dlen;\r\r                      if (!ulist)\r                            ulist = Ptr->GetUsers();\r\r                      bool has_user = Ptr->HasUser(user);\r                    for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)\r                      {\r                              if ((!has_user) && (i->first->IsModeSet('i')))\r                                 continue;\r\r                             if (i->first->Visibility && !i->first->Visibility->VisibleTo(user))\r                                    continue;\r\r                             size_t ptrlen = snprintf(ptr, MAXBUF, "%s%s ", Ptr->GetAllPrefixChars(i->first), i->second.c_str());\r                           /* OnUserList can change this - reset it back to normal */\r                             i->second = i->first->nick;\r                            curlen += ptrlen;\r                              ptr += ptrlen;\r                         numusers++;\r                            if (curlen > (480-NICKMAX))\r                            {\r                                      /* list overflowed into multiple numerics */\r                                   user->WriteServ(std::string(list));\r                                    /* reset our lengths */\r                                        dlen = curlen = snprintf(list,MAXBUF,"353 %s = %s :", user->nick, Ptr->name);\r                                  ptr = list + dlen;\r                                     ptrlen = 0;\r                                    numusers = 0;\r                          }\r                      }\r                      /* if whats left in the list isnt empty, send it */\r                    if (numusers)\r                  {\r                              user->WriteServ(std::string(list));\r                    }\r                      user->WriteServ("366 %s %s :End of /NAMES list.", user->nick, Ptr->name);\r                      return 1;\r              }\r              return 0;               \r       }\r};\r\rMODULE_INIT(ModuleNamesX)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+
+static const char* dummy = "ON";
+
+/* $ModDesc: Provides aliases of commands. */
+
+class ModuleNamesX : public Module
+{
+ public:
+       
+       ModuleNamesX(InspIRCd* Me)
+               : Module(Me)
+       {
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnSyncUserMetaData] = List[I_OnPreCommand] = List[I_OnUserList] = List[I_On005Numeric] = 1;
+       }
+
+       virtual ~ModuleNamesX()
+       {
+       }
+
+       void OnSyncUserMetaData(userrec* user, Module* proto,void* opaque, const std::string &extname, bool displayable)
+       {
+               if ((displayable) && (extname == "NAMESX"))
+                       proto->ProtoSendMetaData(opaque, TYPE_USER, user, extname, "Enabled");
+       }
+
+       virtual Version GetVersion()
+       {
+               return Version(1,1,0,1,VF_VENDOR,API_VERSION);
+       }
+
+       virtual void On005Numeric(std::string &output)
+       {
+               output.append(" NAMESX");
+       }
+
+       virtual int OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line)
+       {
+               irc::string c = command.c_str();
+               /* We don't actually create a proper command handler class for PROTOCTL,
+                * because other modules might want to have PROTOCTL hooks too.
+                * Therefore, we just hook its as an unvalidated command therefore we
+                * can capture it even if it doesnt exist! :-)
+                */
+               if (c == "PROTOCTL")
+               {
+                       if ((pcnt) && (!strcasecmp(parameters[0],"NAMESX")))
+                       {
+                               user->Extend("NAMESX",dummy);
+                               return 1;
+                       }
+               }
+               return 0;
+       }
+
+       virtual int OnUserList(userrec* user, chanrec* Ptr, CUList* &ulist)
+       {
+               if (user->GetExt("NAMESX"))
+               {
+                       char list[MAXBUF];
+                       size_t dlen, curlen;
+                       dlen = curlen = snprintf(list,MAXBUF,"353 %s = %s :", user->nick, Ptr->name);
+                       int numusers = 0;
+                       char* ptr = list + dlen;
+
+                       if (!ulist)
+                               ulist = Ptr->GetUsers();
+
+                       bool has_user = Ptr->HasUser(user);
+                       for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
+                       {
+                               if ((!has_user) && (i->first->IsModeSet('i')))
+                                       continue;
+
+                               if (i->first->Visibility && !i->first->Visibility->VisibleTo(user))
+                                       continue;
+
+                               size_t ptrlen = snprintf(ptr, MAXBUF, "%s%s ", Ptr->GetAllPrefixChars(i->first), i->second.c_str());
+                               /* OnUserList can change this - reset it back to normal */
+                               i->second = i->first->nick;
+                               curlen += ptrlen;
+                               ptr += ptrlen;
+                               numusers++;
+                               if (curlen > (480-NICKMAX))
+                               {
+                                       /* list overflowed into multiple numerics */
+                                       user->WriteServ(std::string(list));
+                                       /* reset our lengths */
+                                       dlen = curlen = snprintf(list,MAXBUF,"353 %s = %s :", user->nick, Ptr->name);
+                                       ptr = list + dlen;
+                                       ptrlen = 0;
+                                       numusers = 0;
+                               }
+                       }
+                       /* if whats left in the list isnt empty, send it */
+                       if (numusers)
+                       {
+                               user->WriteServ(std::string(list));
+                       }
+                       user->WriteServ("366 %s %s :End of /NAMES list.", user->nick, Ptr->name);
+                       return 1;
+               }
+               return 0;               
+       }
+};
+
+MODULE_INIT(ModuleNamesX)
index 94c934e6ffb491c0db7533b15a858d945594b3b3..26d5bfbd7f1c1c6f55d0f95c37de059bfe83fa88 100644 (file)
@@ -1 +1,159 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r#include "hashcomp.h"\r\r/* $ModDesc: Provides the NICKLOCK command, allows an oper to chage a users nick and lock them to it until they quit */\r\r/** Handle /NICKLOCK\r */\rclass cmd_nicklock : public command_t\r{\r      char* dummy;\r public:\r cmd_nicklock (InspIRCd* Instance) : command_t(Instance,"NICKLOCK", 'o', 2)\r      {\r              this->source = "m_nicklock.so";\r                syntax = "<oldnick> <newnick>";\r        }\r\r     CmdResult Handle(const char** parameters, int pcnt, userrec *user)\r     {\r              userrec* source = ServerInstance->FindNick(parameters[0]);\r             irc::string server;\r            irc::string me;\r\r               // check user exists\r           if (!source)\r           {\r                      return CMD_FAILURE;\r            }\r\r             // check if user is locked\r             if (source->GetExt("nick_locked", dummy))\r              {\r                      user->WriteServ("946 %s %s :This user's nickname is already locked.",user->nick,source->nick);\r                 return CMD_FAILURE;\r            }\r\r             // check nick is valid\r         if (!ServerInstance->IsNick(parameters[1]))\r            {\r                      return CMD_FAILURE;\r            }\r\r             // let others know\r             ServerInstance->WriteOpers(std::string(user->nick)+" used NICKLOCK to change and hold "+parameters[0]+" to "+parameters[1]);\r\r          if (!source->ForceNickChange(parameters[1]))\r           {\r                      // ugh, nickchange failed for some reason -- possibly existing nick?\r                   userrec::QuitUser(ServerInstance, source, "Nickname collision");\r                       return CMD_FAILURE;\r            }\r\r             // give them a lock flag\r               source->Extend("nick_locked", "ON");\r\r          /* route */\r            return CMD_SUCCESS;\r    }\r};\r\r/** Handle /NICKUNLOCK\r */\rclass cmd_nickunlock : public command_t\r{\r public:\r cmd_nickunlock (InspIRCd* Instance) : command_t(Instance,"NICKUNLOCK", 'o', 1)\r    {\r              this->source = "m_nickunlock.so";\r              syntax = "<locked-nick>";\r      }\r\r     CmdResult Handle (const char** parameters, int pcnt, userrec *user)\r    {\r              userrec* source = ServerInstance->FindNick(parameters[0]);\r             if (source)\r            {\r                      source->Shrink("nick_locked");\r                 user->WriteServ("945 %s %s :Nickname now unlocked.",user->nick,source->nick);\r                  ServerInstance->WriteOpers(std::string(user->nick)+" used NICKUNLOCK on "+parameters[0]);\r                      return CMD_SUCCESS;\r            }\r\r             return CMD_FAILURE;\r    }\r};\r\r\rclass ModuleNickLock : public Module\r{\r  cmd_nicklock*   cmd1;\r  cmd_nickunlock* cmd2;\r  char* n;\r public:\r      ModuleNickLock(InspIRCd* Me)\r           : Module(Me)\r   {\r              \r               cmd1 = new cmd_nicklock(ServerInstance);\r               cmd2 = new cmd_nickunlock(ServerInstance);\r             ServerInstance->AddCommand(cmd1);\r              ServerInstance->AddCommand(cmd2);\r      }\r      \r       virtual ~ModuleNickLock()\r      {\r      }\r      \r       virtual Version GetVersion()\r   {\r              return Version(1,1,0,1,VF_VENDOR,API_VERSION);\r }\r\r     void Implements(char* List)\r    {\r              List[I_OnUserPreNick] = List[I_OnUserQuit] = List[I_OnCleanup] = 1;\r    }\r\r     virtual int OnUserPreNick(userrec* user, const std::string &newnick)\r   {\r              if (user->GetExt("nick_locked", n))\r            {\r                      user->WriteServ("447 %s :You cannot change your nickname (your nick is locked)",user->nick);\r                   return 1;\r              }\r              return 0;\r      }\r\r     virtual void OnUserQuit(userrec* user, const std::string &reason, const std::string &oper_message)\r     {\r              user->Shrink("nick_locked");\r   }\r\r     virtual void OnCleanup(int target_type, void* item)\r    {\r              if(target_type == TYPE_USER)\r           {\r                      userrec* user = (userrec*)item;\r                        user->Shrink("nick_locked");\r           }\r      }\r};\r\rMODULE_INIT(ModuleNickLock)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+#include "hashcomp.h"
+
+/* $ModDesc: Provides the NICKLOCK command, allows an oper to chage a users nick and lock them to it until they quit */
+
+/** Handle /NICKLOCK
+ */
+class cmd_nicklock : public command_t
+{
+       char* dummy;
+ public:
+ cmd_nicklock (InspIRCd* Instance) : command_t(Instance,"NICKLOCK", 'o', 2)
+       {
+               this->source = "m_nicklock.so";
+               syntax = "<oldnick> <newnick>";
+       }
+
+       CmdResult Handle(const char** parameters, int pcnt, userrec *user)
+       {
+               userrec* source = ServerInstance->FindNick(parameters[0]);
+               irc::string server;
+               irc::string me;
+
+               // check user exists
+               if (!source)
+               {
+                       return CMD_FAILURE;
+               }
+
+               // check if user is locked
+               if (source->GetExt("nick_locked", dummy))
+               {
+                       user->WriteServ("946 %s %s :This user's nickname is already locked.",user->nick,source->nick);
+                       return CMD_FAILURE;
+               }
+
+               // check nick is valid
+               if (!ServerInstance->IsNick(parameters[1]))
+               {
+                       return CMD_FAILURE;
+               }
+
+               // let others know
+               ServerInstance->WriteOpers(std::string(user->nick)+" used NICKLOCK to change and hold "+parameters[0]+" to "+parameters[1]);
+
+               if (!source->ForceNickChange(parameters[1]))
+               {
+                       // ugh, nickchange failed for some reason -- possibly existing nick?
+                       userrec::QuitUser(ServerInstance, source, "Nickname collision");
+                       return CMD_FAILURE;
+               }
+
+               // give them a lock flag
+               source->Extend("nick_locked", "ON");
+
+               /* route */
+               return CMD_SUCCESS;
+       }
+};
+
+/** Handle /NICKUNLOCK
+ */
+class cmd_nickunlock : public command_t
+{
+ public:
+ cmd_nickunlock (InspIRCd* Instance) : command_t(Instance,"NICKUNLOCK", 'o', 1)
+       {
+               this->source = "m_nickunlock.so";
+               syntax = "<locked-nick>";
+       }
+
+       CmdResult Handle (const char** parameters, int pcnt, userrec *user)
+       {
+               userrec* source = ServerInstance->FindNick(parameters[0]);
+               if (source)
+               {
+                       source->Shrink("nick_locked");
+                       user->WriteServ("945 %s %s :Nickname now unlocked.",user->nick,source->nick);
+                       ServerInstance->WriteOpers(std::string(user->nick)+" used NICKUNLOCK on "+parameters[0]);
+                       return CMD_SUCCESS;
+               }
+
+               return CMD_FAILURE;
+       }
+};
+
+
+class ModuleNickLock : public Module
+{
+       cmd_nicklock*   cmd1;
+       cmd_nickunlock* cmd2;
+       char* n;
+ public:
+       ModuleNickLock(InspIRCd* Me)
+               : Module(Me)
+       {
+               
+               cmd1 = new cmd_nicklock(ServerInstance);
+               cmd2 = new cmd_nickunlock(ServerInstance);
+               ServerInstance->AddCommand(cmd1);
+               ServerInstance->AddCommand(cmd2);
+       }
+       
+       virtual ~ModuleNickLock()
+       {
+       }
+       
+       virtual Version GetVersion()
+       {
+               return Version(1,1,0,1,VF_VENDOR,API_VERSION);
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnUserPreNick] = List[I_OnUserQuit] = List[I_OnCleanup] = 1;
+       }
+
+       virtual int OnUserPreNick(userrec* user, const std::string &newnick)
+       {
+               if (user->GetExt("nick_locked", n))
+               {
+                       user->WriteServ("447 %s :You cannot change your nickname (your nick is locked)",user->nick);
+                       return 1;
+               }
+               return 0;
+       }
+
+       virtual void OnUserQuit(userrec* user, const std::string &reason, const std::string &oper_message)
+       {
+               user->Shrink("nick_locked");
+       }
+
+       virtual void OnCleanup(int target_type, void* item)
+       {
+               if(target_type == TYPE_USER)
+               {
+                       userrec* user = (userrec*)item;
+                       user->Shrink("nick_locked");
+               }
+       }
+};
+
+MODULE_INIT(ModuleNickLock)
index b3445155a9c109fcc1f6becfef3920ba97167fa8..05dbd69cab610daf6eea1115080c99296ec1fc4f 100644 (file)
@@ -1 +1,107 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r\r/* $ModDesc: Provides support for unreal-style channel mode +c */\r\rclass NoCTCP : public ModeHandler\r{\r public:\r      NoCTCP(InspIRCd* Instance) : ModeHandler(Instance, 'C', 0, 0, false, MODETYPE_CHANNEL, false) { }\r\r     ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)\r {\r              if (adding)\r            {\r                      if (!channel->IsModeSet('C'))\r                  {\r                              channel->SetMode('C',true);\r                            return MODEACTION_ALLOW;\r                       }\r              }\r              else\r           {\r                      if (channel->IsModeSet('C'))\r                   {\r                              channel->SetMode('C',false);\r                           return MODEACTION_ALLOW;\r                       }\r              }\r\r             return MODEACTION_DENY;\r        }\r};\r\rclass ModuleNoCTCP : public Module\r{\r     \r       NoCTCP* nc;\r    \r public:\r \r    ModuleNoCTCP(InspIRCd* Me)\r             : Module(Me)\r   {\r              \r               nc = new NoCTCP(ServerInstance);\r               if (!ServerInstance->AddMode(nc, 'C'))\r                 throw ModuleException("Could not add new modes!");\r     }\r\r     void Implements(char* List)\r    {\r              List[I_OnUserPreMessage] = List[I_OnUserPreNotice] = 1;\r        }\r\r     virtual int OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)\r    {\r              return OnUserPreNotice(user,dest,target_type,text,status,exempt_list);\r }\r      \r       virtual int OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)\r     {\r              if ((target_type == TYPE_CHANNEL) && (IS_LOCAL(user)))\r         {\r                      chanrec* c = (chanrec*)dest;\r                   if (c->IsModeSet('C'))\r                 {\r                              if ((text.length()) && (text[0] == '\1'))\r                              {\r                                      if (strncmp(text.c_str(),"\1ACTION ",8))\r                                       {\r                                              user->WriteServ("492 %s %s :Can't send CTCP to channel (+C set)",user->nick, c->name);\r                                         return 1;\r                                      }\r                              }\r                      }\r              }\r              return 0;\r      }\r\r     virtual ~ModuleNoCTCP()\r        {\r              ServerInstance->Modes->DelMode(nc);\r            DELETE(nc);\r    }\r\r     virtual Version GetVersion()\r   {\r              return Version(1,1,0,0,VF_COMMON|VF_VENDOR,API_VERSION);\r       }\r};\r\rMODULE_INIT(ModuleNoCTCP)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+
+/* $ModDesc: Provides support for unreal-style channel mode +c */
+
+class NoCTCP : public ModeHandler
+{
+ public:
+       NoCTCP(InspIRCd* Instance) : ModeHandler(Instance, 'C', 0, 0, false, MODETYPE_CHANNEL, false) { }
+
+       ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)
+       {
+               if (adding)
+               {
+                       if (!channel->IsModeSet('C'))
+                       {
+                               channel->SetMode('C',true);
+                               return MODEACTION_ALLOW;
+                       }
+               }
+               else
+               {
+                       if (channel->IsModeSet('C'))
+                       {
+                               channel->SetMode('C',false);
+                               return MODEACTION_ALLOW;
+                       }
+               }
+
+               return MODEACTION_DENY;
+       }
+};
+
+class ModuleNoCTCP : public Module
+{
+       
+       NoCTCP* nc;
+       
+ public:
+       ModuleNoCTCP(InspIRCd* Me)
+               : Module(Me)
+       {
+               
+               nc = new NoCTCP(ServerInstance);
+               if (!ServerInstance->AddMode(nc, 'C'))
+                       throw ModuleException("Could not add new modes!");
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnUserPreMessage] = List[I_OnUserPreNotice] = 1;
+       }
+
+       virtual int OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
+       {
+               return OnUserPreNotice(user,dest,target_type,text,status,exempt_list);
+       }
+       
+       virtual int OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
+       {
+               if ((target_type == TYPE_CHANNEL) && (IS_LOCAL(user)))
+               {
+                       chanrec* c = (chanrec*)dest;
+                       if (c->IsModeSet('C'))
+                       {
+                               if ((text.length()) && (text[0] == '\1'))
+                               {
+                                       if (strncmp(text.c_str(),"\1ACTION ",8))
+                                       {
+                                               user->WriteServ("492 %s %s :Can't send CTCP to channel (+C set)",user->nick, c->name);
+                                               return 1;
+                                       }
+                               }
+                       }
+               }
+               return 0;
+       }
+
+       virtual ~ModuleNoCTCP()
+       {
+               ServerInstance->Modes->DelMode(nc);
+               DELETE(nc);
+       }
+
+       virtual Version GetVersion()
+       {
+               return Version(1,1,0,0,VF_COMMON|VF_VENDOR,API_VERSION);
+       }
+};
+
+MODULE_INIT(ModuleNoCTCP)
index 76e2616e3ca21487bd52883716f4de9f2c33ae26..26965d319f8b30c2a6d23cd1cba194b36cbac89b 100644 (file)
@@ -1 +1,88 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r\r/* $ModDesc: Provides support for unreal-style channel mode +V */\r\rclass NoInvite : public ModeHandler\r{\r public:\r    NoInvite(InspIRCd* Instance) : ModeHandler(Instance, 'V', 0, 0, false, MODETYPE_CHANNEL, false) { }\r\r   ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)\r {\r              if (adding)\r            {\r                      if (!channel->IsModeSet('V'))\r                  {\r                              channel->SetMode('V',true);\r                            return MODEACTION_ALLOW;\r                       }\r              }\r              else\r           {\r                      if (channel->IsModeSet('V'))\r                   {\r                              channel->SetMode('V',false);\r                           return MODEACTION_ALLOW;\r                       }\r              }\r\r             return MODEACTION_DENY;\r        }\r};\r\rclass ModuleNoInvite : public Module\r{\r   NoInvite *ni;\r public:\r\r        ModuleNoInvite(InspIRCd* Me) : Module(Me)\r      {\r              ni = new NoInvite(ServerInstance);\r             if (!ServerInstance->AddMode(ni, 'V'))\r                 throw ModuleException("Could not add new modes!");\r     }\r\r     void Implements(char* List)\r    {\r              List[I_OnUserPreInvite] = 1;\r   }\r\r     virtual int OnUserPreInvite(userrec* user,userrec* dest,chanrec* channel)\r      {\r              if (channel->IsModeSet('V'))\r           {\r                      user->WriteServ("492 %s %s :Can't invite %s to channel (+V set)",user->nick, channel->name, dest->nick);\r                       return 1;\r              }\r              return 0;\r      }\r\r     virtual ~ModuleNoInvite()\r      {\r              ServerInstance->Modes->DelMode(ni);\r            DELETE(ni);\r    }\r      \r       virtual Version GetVersion()\r   {\r              return Version(1,1,0,0,VF_COMMON|VF_VENDOR,API_VERSION);\r       }\r};\r\rMODULE_INIT(ModuleNoInvite)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+
+/* $ModDesc: Provides support for unreal-style channel mode +V */
+
+class NoInvite : public ModeHandler
+{
+ public:
+       NoInvite(InspIRCd* Instance) : ModeHandler(Instance, 'V', 0, 0, false, MODETYPE_CHANNEL, false) { }
+
+       ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)
+       {
+               if (adding)
+               {
+                       if (!channel->IsModeSet('V'))
+                       {
+                               channel->SetMode('V',true);
+                               return MODEACTION_ALLOW;
+                       }
+               }
+               else
+               {
+                       if (channel->IsModeSet('V'))
+                       {
+                               channel->SetMode('V',false);
+                               return MODEACTION_ALLOW;
+                       }
+               }
+
+               return MODEACTION_DENY;
+       }
+};
+
+class ModuleNoInvite : public Module
+{
+       NoInvite *ni;
+ public:
+
+       ModuleNoInvite(InspIRCd* Me) : Module(Me)
+       {
+               ni = new NoInvite(ServerInstance);
+               if (!ServerInstance->AddMode(ni, 'V'))
+                       throw ModuleException("Could not add new modes!");
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnUserPreInvite] = 1;
+       }
+
+       virtual int OnUserPreInvite(userrec* user,userrec* dest,chanrec* channel)
+       {
+               if (channel->IsModeSet('V'))
+               {
+                       user->WriteServ("492 %s %s :Can't invite %s to channel (+V set)",user->nick, channel->name, dest->nick);
+                       return 1;
+               }
+               return 0;
+       }
+
+       virtual ~ModuleNoInvite()
+       {
+               ServerInstance->Modes->DelMode(ni);
+               DELETE(ni);
+       }
+       
+       virtual Version GetVersion()
+       {
+               return Version(1,1,0,0,VF_COMMON|VF_VENDOR,API_VERSION);
+       }
+};
+
+MODULE_INIT(ModuleNoInvite)
index ac78b4d7a09abe01597ee00b0d78811bea0c83c6..315eb7399428e7acfa3a226c2856135eb7beff76 100644 (file)
@@ -1 +1,105 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r\r/* $ModDesc: Provides support for unreal-style channel mode +Q */\r\rclass NoKicks : public ModeHandler\r{\r public:\r     NoKicks(InspIRCd* Instance) : ModeHandler(Instance, 'Q', 0, 0, false, MODETYPE_CHANNEL, false) { }\r\r    ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)\r {\r              if (adding)\r            {\r                      if (!channel->IsModeSet('Q'))\r                  {\r                              channel->SetMode('Q',true);\r                            return MODEACTION_ALLOW;\r                       }\r              }\r              else\r           {\r                      if (channel->IsModeSet('Q'))\r                   {\r                              channel->SetMode('Q',false);\r                           return MODEACTION_ALLOW;\r                       }\r              }\r\r             return MODEACTION_DENY;\r        }\r};\r\rclass ModuleNoKicks : public Module\r{\r    \r       NoKicks* nk;\r   \r public:\r \r    ModuleNoKicks(InspIRCd* Me)\r            : Module(Me)\r   {\r              \r               nk = new NoKicks(ServerInstance);\r              if (!ServerInstance->AddMode(nk, 'Q'))\r                 throw ModuleException("Could not add new modes!");\r     }\r\r     void Implements(char* List)\r    {\r              List[I_OnAccessCheck] = 1;\r     }\r\r     virtual int OnAccessCheck(userrec* source,userrec* dest,chanrec* channel,int access_type)\r      {\r              if (access_type == AC_KICK)\r            {\r                      if (channel->IsModeSet('Q'))\r                   {\r                              if ((ServerInstance->ULine(source->nick)) || (ServerInstance->ULine(source->server)) || (!*source->server))\r                            {\r                                      // ulines can still kick with +Q in place\r                                      return ACR_ALLOW;\r                              }\r                              else\r                           {\r                                      // nobody else can (not even opers with override, and founders)\r                                        source->WriteServ("484 %s %s :Can't kick user %s from channel (+Q set)",source->nick, channel->name,dest->nick);\r                                       return ACR_DENY;\r                               }\r                      }\r              }\r              return ACR_DEFAULT;\r    }\r\r     virtual ~ModuleNoKicks()\r       {\r              ServerInstance->Modes->DelMode(nk);\r            DELETE(nk);\r    }\r      \r       virtual Version GetVersion()\r   {\r              return Version(1,1,0,0,VF_COMMON|VF_VENDOR,API_VERSION);\r       }\r};\r\r\rMODULE_INIT(ModuleNoKicks)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+
+/* $ModDesc: Provides support for unreal-style channel mode +Q */
+
+class NoKicks : public ModeHandler
+{
+ public:
+       NoKicks(InspIRCd* Instance) : ModeHandler(Instance, 'Q', 0, 0, false, MODETYPE_CHANNEL, false) { }
+
+       ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)
+       {
+               if (adding)
+               {
+                       if (!channel->IsModeSet('Q'))
+                       {
+                               channel->SetMode('Q',true);
+                               return MODEACTION_ALLOW;
+                       }
+               }
+               else
+               {
+                       if (channel->IsModeSet('Q'))
+                       {
+                               channel->SetMode('Q',false);
+                               return MODEACTION_ALLOW;
+                       }
+               }
+
+               return MODEACTION_DENY;
+       }
+};
+
+class ModuleNoKicks : public Module
+{
+       
+       NoKicks* nk;
+       
+ public:
+       ModuleNoKicks(InspIRCd* Me)
+               : Module(Me)
+       {
+               
+               nk = new NoKicks(ServerInstance);
+               if (!ServerInstance->AddMode(nk, 'Q'))
+                       throw ModuleException("Could not add new modes!");
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnAccessCheck] = 1;
+       }
+
+       virtual int OnAccessCheck(userrec* source,userrec* dest,chanrec* channel,int access_type)
+       {
+               if (access_type == AC_KICK)
+               {
+                       if (channel->IsModeSet('Q'))
+                       {
+                               if ((ServerInstance->ULine(source->nick)) || (ServerInstance->ULine(source->server)) || (!*source->server))
+                               {
+                                       // ulines can still kick with +Q in place
+                                       return ACR_ALLOW;
+                               }
+                               else
+                               {
+                                       // nobody else can (not even opers with override, and founders)
+                                       source->WriteServ("484 %s %s :Can't kick user %s from channel (+Q set)",source->nick, channel->name,dest->nick);
+                                       return ACR_DENY;
+                               }
+                       }
+               }
+               return ACR_DEFAULT;
+       }
+
+       virtual ~ModuleNoKicks()
+       {
+               ServerInstance->Modes->DelMode(nk);
+               DELETE(nk);
+       }
+       
+       virtual Version GetVersion()
+       {
+               return Version(1,1,0,0,VF_COMMON|VF_VENDOR,API_VERSION);
+       }
+};
+
+
+MODULE_INIT(ModuleNoKicks)
index d6e6553e9bd0b36b11926f9ff61ec9e018cab716..bb1843a958e20b6eae05c41f65b387ee7e760e8a 100644 (file)
@@ -1 +1,102 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r#include "hashcomp.h"\r#include "configreader.h"\r\r/* $ModDesc: Provides support for channel mode +N which prevents nick changes on channel */\r\rclass NoNicks : public ModeHandler\r{\r public:\r   NoNicks(InspIRCd* Instance) : ModeHandler(Instance, 'N', 0, 0, false, MODETYPE_CHANNEL, false) { }\r\r    ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)\r {\r              if (adding)\r            {\r                      if (!channel->IsModeSet('N'))\r                  {\r                              channel->SetMode('N',true);\r                            return MODEACTION_ALLOW;\r                       }\r              }\r              else\r           {\r                      if (channel->IsModeSet('N'))\r                   {\r                              channel->SetMode('N',false);\r                           return MODEACTION_ALLOW;\r                       }\r              }\r\r             return MODEACTION_DENY;\r        }\r};\r\rclass ModuleNoNickChange : public Module\r{\r       NoNicks* nn;\r public:\r  ModuleNoNickChange(InspIRCd* Me)\r               : Module(Me)\r   {\r              \r               nn = new NoNicks(ServerInstance);\r              ServerInstance->AddMode(nn, 'N');\r      }\r      \r       virtual ~ModuleNoNickChange()\r  {\r              ServerInstance->Modes->DelMode(nn);\r            DELETE(nn);\r    }\r      \r       virtual Version GetVersion()\r   {\r              return Version(1,1,0,1,VF_COMMON|VF_VENDOR,API_VERSION);\r       }\r\r     void Implements(char* List)\r    {\r              List[I_OnUserPreNick] = 1;\r     }\r\r     virtual int OnUserPreNick(userrec* user, const std::string &newnick)\r   {\r              if (IS_LOCAL(user))\r            {\r                      for (UCListIter i = user->chans.begin(); i != user->chans.end(); i++)\r                  {\r                              chanrec* curr = i->first;\r\r                             if (curr->IsModeSet('N'))\r                              {\r                                      if (CHANOPS_EXEMPT(ServerInstance, 'N') && curr->GetStatus(user) == STATUS_OP)\r                                         continue;\r\r                                     user->WriteServ("447 %s :Can't change nickname while on %s (+N is set)", user->nick, curr->name);\r                                      return 1;\r                              }\r                      }\r              }\r\r             return 0;\r      }\r};\r\rMODULE_INIT(ModuleNoNickChange)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+#include "hashcomp.h"
+#include "configreader.h"
+
+/* $ModDesc: Provides support for channel mode +N which prevents nick changes on channel */
+
+class NoNicks : public ModeHandler
+{
+ public:
+       NoNicks(InspIRCd* Instance) : ModeHandler(Instance, 'N', 0, 0, false, MODETYPE_CHANNEL, false) { }
+
+       ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)
+       {
+               if (adding)
+               {
+                       if (!channel->IsModeSet('N'))
+                       {
+                               channel->SetMode('N',true);
+                               return MODEACTION_ALLOW;
+                       }
+               }
+               else
+               {
+                       if (channel->IsModeSet('N'))
+                       {
+                               channel->SetMode('N',false);
+                               return MODEACTION_ALLOW;
+                       }
+               }
+
+               return MODEACTION_DENY;
+       }
+};
+
+class ModuleNoNickChange : public Module
+{
+       NoNicks* nn;
+ public:
+       ModuleNoNickChange(InspIRCd* Me)
+               : Module(Me)
+       {
+               
+               nn = new NoNicks(ServerInstance);
+               ServerInstance->AddMode(nn, 'N');
+       }
+       
+       virtual ~ModuleNoNickChange()
+       {
+               ServerInstance->Modes->DelMode(nn);
+               DELETE(nn);
+       }
+       
+       virtual Version GetVersion()
+       {
+               return Version(1,1,0,1,VF_COMMON|VF_VENDOR,API_VERSION);
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnUserPreNick] = 1;
+       }
+
+       virtual int OnUserPreNick(userrec* user, const std::string &newnick)
+       {
+               if (IS_LOCAL(user))
+               {
+                       for (UCListIter i = user->chans.begin(); i != user->chans.end(); i++)
+                       {
+                               chanrec* curr = i->first;
+
+                               if (curr->IsModeSet('N'))
+                               {
+                                       if (CHANOPS_EXEMPT(ServerInstance, 'N') && curr->GetStatus(user) == STATUS_OP)
+                                               continue;
+
+                                       user->WriteServ("447 %s :Can't change nickname while on %s (+N is set)", user->nick, curr->name);
+                                       return 1;
+                               }
+                       }
+               }
+
+               return 0;
+       }
+};
+
+MODULE_INIT(ModuleNoNickChange)
index fd4c474cb42d7eb35347db6d741baa130952110c..ae926b4bbb5d1ec7b93fe4ef224e98cc8ba4ec48 100644 (file)
@@ -1 +1,103 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r\r/* $ModDesc: Provides support for unreal-style channel mode +T */\r\rclass NoNotice : public ModeHandler\r{\r public:\r    NoNotice(InspIRCd* Instance) : ModeHandler(Instance, 'T', 0, 0, false, MODETYPE_CHANNEL, false) { }\r\r   ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)\r {\r              if (adding)\r            {\r                      if (!channel->IsModeSet('T'))\r                  {\r                              channel->SetMode('T',true);\r                            return MODEACTION_ALLOW;\r                       }\r              }\r              else\r           {\r                      if (channel->IsModeSet('T'))\r                   {\r                              channel->SetMode('T',false);\r                           return MODEACTION_ALLOW;\r                       }\r              }\r\r             return MODEACTION_DENY;\r        }\r};\r\rclass ModuleNoNotice : public Module\r{\r   \r       NoNotice* nt;\r public:\r \r       ModuleNoNotice(InspIRCd* Me)\r           : Module(Me)\r   {\r              \r               nt = new NoNotice(ServerInstance);\r             if (!ServerInstance->AddMode(nt, 'T'))\r                 throw ModuleException("Could not add new modes!");\r     }\r\r     void Implements(char* List)\r    {\r              List[I_OnUserPreNotice] = 1;\r   }\r      \r       virtual int OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)\r     {\r              if ((target_type == TYPE_CHANNEL) && (IS_LOCAL(user)))\r         {\r                      chanrec* c = (chanrec*)dest;\r                   if (c->IsModeSet('T'))\r                 {\r                              if ((ServerInstance->ULine(user->server)) || (c->GetStatus(user) == STATUS_OP) || (c->GetStatus(user) == STATUS_HOP))\r                          {\r                                      // ops and halfops can still /NOTICE the channel\r                                       return 0;\r                              }\r                              else\r                           {\r                                      user->WriteServ("404 %s %s :Can't send NOTICE to channel (+T set)",user->nick, c->name);\r                                       return 1;\r                              }\r                      }\r              }\r              return 0;\r      }\r\r     virtual ~ModuleNoNotice()\r      {\r              ServerInstance->Modes->DelMode(nt);\r            DELETE(nt);\r    }\r      \r       virtual Version GetVersion()\r   {\r              return Version(1,1,0,0,VF_COMMON|VF_VENDOR,API_VERSION);\r       }\r};\r\rMODULE_INIT(ModuleNoNotice)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+
+/* $ModDesc: Provides support for unreal-style channel mode +T */
+
+class NoNotice : public ModeHandler
+{
+ public:
+       NoNotice(InspIRCd* Instance) : ModeHandler(Instance, 'T', 0, 0, false, MODETYPE_CHANNEL, false) { }
+
+       ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)
+       {
+               if (adding)
+               {
+                       if (!channel->IsModeSet('T'))
+                       {
+                               channel->SetMode('T',true);
+                               return MODEACTION_ALLOW;
+                       }
+               }
+               else
+               {
+                       if (channel->IsModeSet('T'))
+                       {
+                               channel->SetMode('T',false);
+                               return MODEACTION_ALLOW;
+                       }
+               }
+
+               return MODEACTION_DENY;
+       }
+};
+
+class ModuleNoNotice : public Module
+{
+       
+       NoNotice* nt;
+ public:
+       ModuleNoNotice(InspIRCd* Me)
+               : Module(Me)
+       {
+               
+               nt = new NoNotice(ServerInstance);
+               if (!ServerInstance->AddMode(nt, 'T'))
+                       throw ModuleException("Could not add new modes!");
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnUserPreNotice] = 1;
+       }
+       
+       virtual int OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
+       {
+               if ((target_type == TYPE_CHANNEL) && (IS_LOCAL(user)))
+               {
+                       chanrec* c = (chanrec*)dest;
+                       if (c->IsModeSet('T'))
+                       {
+                               if ((ServerInstance->ULine(user->server)) || (c->GetStatus(user) == STATUS_OP) || (c->GetStatus(user) == STATUS_HOP))
+                               {
+                                       // ops and halfops can still /NOTICE the channel
+                                       return 0;
+                               }
+                               else
+                               {
+                                       user->WriteServ("404 %s %s :Can't send NOTICE to channel (+T set)",user->nick, c->name);
+                                       return 1;
+                               }
+                       }
+               }
+               return 0;
+       }
+
+       virtual ~ModuleNoNotice()
+       {
+               ServerInstance->Modes->DelMode(nt);
+               DELETE(nt);
+       }
+       
+       virtual Version GetVersion()
+       {
+               return Version(1,1,0,0,VF_COMMON|VF_VENDOR,API_VERSION);
+       }
+};
+
+MODULE_INIT(ModuleNoNotice)
index a3989ad91acf4d4c056c5f35572f07e11c7cbeef..b4661741b52b9ce4e44341c62324be6aa78cae94 100644 (file)
@@ -1 +1,163 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r/* $ModDesc: Allows for hashed oper passwords */\r/* $ModDep: m_hash.h */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r#include "m_hash.h"\r\rtypedef std::map<irc::string, Module*> hashymodules;\r\r/* Handle /MKPASSWD\r */\rclass cmd_mkpasswd : public command_t\r{\r  Module* Sender;\r        hashymodules &hashers;\r std::deque<std::string> &names;\r public:\r       cmd_mkpasswd (InspIRCd* Instance, Module* S, hashymodules &h, std::deque<std::string> &n)\r              : command_t(Instance,"MKPASSWD", 'o', 2), Sender(S), hashers(h), names(n)\r      {\r              this->source = "m_oper_hash.so";\r               syntax = "<hashtype> <any-text>";\r      }\r\r     void MakeHash(userrec* user, const char* algo, const char* stuff)\r      {\r              /* Lets see if they gave us an algorithm which has been implemented */\r         hashymodules::iterator x = hashers.find(algo);\r         if (x != hashers.end())\r                {\r                      /* Yup, reset it first (Always ALWAYS do this) */\r                      HashResetRequest(Sender, x->second).Send();\r                    /* Now attempt to generate a hash */\r                   user->WriteServ("NOTICE %s :%s hashed password for %s is %s",user->nick, algo, stuff, HashSumRequest(Sender, x->second, stuff).Send() );\r               }\r              else\r           {\r                      /* I dont do flying, bob. */\r                   user->WriteServ("NOTICE %s :Unknown hash type, valid hash types are: %s", user->nick, irc::stringjoiner(", ", names, 0, names.size() - 1).GetJoined().c_str() );\r               }\r      }\r\r     CmdResult Handle (const char** parameters, int pcnt, userrec *user)\r    {\r              MakeHash(user, parameters[0], parameters[1]);\r          /* NOTE: Don't propogate this across the network!\r               * We dont want plaintext passes going all over the place...\r            * To make sure it goes nowhere, return CMD_FAILURE!\r            */\r            return CMD_FAILURE;\r    }\r};\r\rclass ModuleOperHash : public Module\r{\r   \r       cmd_mkpasswd* mycommand;\r       ConfigReader* Conf;\r    hashymodules hashers; /* List of modules which implement HashRequest */\r        std::deque<std::string> names; /* Module names which implement HashRequest */\r\r public:\r\r       ModuleOperHash(InspIRCd* Me)\r           : Module(Me)\r   {\r\r             /* Read the config file first */\r               Conf = NULL;\r           OnRehash(NULL,"");\r\r            ServerInstance->UseInterface("HashRequest");\r\r          /* Find all modules which implement the interface 'HashRequest' */\r             modulelist* ml = ServerInstance->FindInterface("HashRequest");\r\r                /* Did we find any modules? */\r         if (ml)\r                {\r                      /* Yes, enumerate them all to find out the hashing algorithm name */\r                   for (modulelist::iterator m = ml->begin(); m != ml->end(); m++)\r                        {\r                              /* Make a request to it for its name, its implementing\r                          * HashRequest so we know its safe to do this\r                           */\r                            std::string name = HashNameRequest(this, *m).Send();\r                           /* Build a map of them */\r                              hashers[name.c_str()] = *m;\r                            names.push_back(name);\r                 }\r              }\r              else\r           {\r                      throw ModuleException("I can't find any modules loaded which implement the HashRequest interface! You probably forgot to load a hashing module such as m_md5.so or m_sha256.so.");\r             }\r\r             mycommand = new cmd_mkpasswd(ServerInstance, this, hashers, names);\r            ServerInstance->AddCommand(mycommand);\r }\r      \r       virtual ~ModuleOperHash()\r      {\r              ServerInstance->DoneWithInterface("HashRequest");\r      }\r\r     void Implements(char* List)\r    {\r              List[I_OnRehash] = List[I_OnOperCompare] = 1;\r  }\r\r     virtual void OnRehash(userrec* user, const std::string &parameter)\r     {\r              /* Re-read configuration file */\r               if (Conf)\r                      delete Conf;\r\r          Conf = new ConfigReader(ServerInstance);\r       }\r\r     virtual int OnOperCompare(const std::string &data, const std::string &input, int tagnumber)\r    {\r              /* First, lets see what hash theyre using on this oper */\r              std::string hashtype = Conf->ReadValue("oper", "hash", tagnumber);\r             hashymodules::iterator x = hashers.find(hashtype.c_str());\r\r            /* Is this a valid hash name? (case insensitive) */\r            if (x != hashers.end())\r                {\r                      /* Reset the hashing module */\r                 HashResetRequest(this, x->second).Send();\r                      /* Compare the hash in the config to the generated hash */\r                     if (!strcasecmp(data.c_str(), HashSumRequest(this, x->second, input.c_str()).Send()))\r                          return 1;\r                      /* No match, and must be hashed, forbid */\r                     else return -1;\r                }\r\r             /* Not a hash, fall through to strcmp in core */\r               return 0;\r      }\r\r     virtual Version GetVersion()\r   {\r              return Version(1,1,0,1,VF_VENDOR,API_VERSION);\r }\r};\r\rMODULE_INIT(ModuleOperHash)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+/* $ModDesc: Allows for hashed oper passwords */
+/* $ModDep: m_hash.h */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+#include "m_hash.h"
+
+typedef std::map<irc::string, Module*> hashymodules;
+
+/* Handle /MKPASSWD
+ */
+class cmd_mkpasswd : public command_t
+{
+       Module* Sender;
+       hashymodules &hashers;
+       std::deque<std::string> &names;
+ public:
+       cmd_mkpasswd (InspIRCd* Instance, Module* S, hashymodules &h, std::deque<std::string> &n)
+               : command_t(Instance,"MKPASSWD", 'o', 2), Sender(S), hashers(h), names(n)
+       {
+               this->source = "m_oper_hash.so";
+               syntax = "<hashtype> <any-text>";
+       }
+
+       void MakeHash(userrec* user, const char* algo, const char* stuff)
+       {
+               /* Lets see if they gave us an algorithm which has been implemented */
+               hashymodules::iterator x = hashers.find(algo);
+               if (x != hashers.end())
+               {
+                       /* Yup, reset it first (Always ALWAYS do this) */
+                       HashResetRequest(Sender, x->second).Send();
+                       /* Now attempt to generate a hash */
+                       user->WriteServ("NOTICE %s :%s hashed password for %s is %s",user->nick, algo, stuff, HashSumRequest(Sender, x->second, stuff).Send() );
+               }
+               else
+               {
+                       /* I dont do flying, bob. */
+                       user->WriteServ("NOTICE %s :Unknown hash type, valid hash types are: %s", user->nick, irc::stringjoiner(", ", names, 0, names.size() - 1).GetJoined().c_str() );
+               }
+       }
+
+       CmdResult Handle (const char** parameters, int pcnt, userrec *user)
+       {
+               MakeHash(user, parameters[0], parameters[1]);
+               /* NOTE: Don't propogate this across the network!
+                * We dont want plaintext passes going all over the place...
+                * To make sure it goes nowhere, return CMD_FAILURE!
+                */
+               return CMD_FAILURE;
+       }
+};
+
+class ModuleOperHash : public Module
+{
+       
+       cmd_mkpasswd* mycommand;
+       ConfigReader* Conf;
+       hashymodules hashers; /* List of modules which implement HashRequest */
+       std::deque<std::string> names; /* Module names which implement HashRequest */
+
+ public:
+
+       ModuleOperHash(InspIRCd* Me)
+               : Module(Me)
+       {
+
+               /* Read the config file first */
+               Conf = NULL;
+               OnRehash(NULL,"");
+
+               ServerInstance->UseInterface("HashRequest");
+
+               /* Find all modules which implement the interface 'HashRequest' */
+               modulelist* ml = ServerInstance->FindInterface("HashRequest");
+
+               /* Did we find any modules? */
+               if (ml)
+               {
+                       /* Yes, enumerate them all to find out the hashing algorithm name */
+                       for (modulelist::iterator m = ml->begin(); m != ml->end(); m++)
+                       {
+                               /* Make a request to it for its name, its implementing
+                                * HashRequest so we know its safe to do this
+                                */
+                               std::string name = HashNameRequest(this, *m).Send();
+                               /* Build a map of them */
+                               hashers[name.c_str()] = *m;
+                               names.push_back(name);
+                       }
+               }
+               else
+               {
+                       throw ModuleException("I can't find any modules loaded which implement the HashRequest interface! You probably forgot to load a hashing module such as m_md5.so or m_sha256.so.");
+               }
+
+               mycommand = new cmd_mkpasswd(ServerInstance, this, hashers, names);
+               ServerInstance->AddCommand(mycommand);
+       }
+       
+       virtual ~ModuleOperHash()
+       {
+               ServerInstance->DoneWithInterface("HashRequest");
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnRehash] = List[I_OnOperCompare] = 1;
+       }
+
+       virtual void OnRehash(userrec* user, const std::string &parameter)
+       {
+               /* Re-read configuration file */
+               if (Conf)
+                       delete Conf;
+
+               Conf = new ConfigReader(ServerInstance);
+       }
+
+       virtual int OnOperCompare(const std::string &data, const std::string &input, int tagnumber)
+       {
+               /* First, lets see what hash theyre using on this oper */
+               std::string hashtype = Conf->ReadValue("oper", "hash", tagnumber);
+               hashymodules::iterator x = hashers.find(hashtype.c_str());
+
+               /* Is this a valid hash name? (case insensitive) */
+               if (x != hashers.end())
+               {
+                       /* Reset the hashing module */
+                       HashResetRequest(this, x->second).Send();
+                       /* Compare the hash in the config to the generated hash */
+                       if (!strcasecmp(data.c_str(), HashSumRequest(this, x->second, input.c_str()).Send()))
+                               return 1;
+                       /* No match, and must be hashed, forbid */
+                       else return -1;
+               }
+
+               /* Not a hash, fall through to strcmp in core */
+               return 0;
+       }
+
+       virtual Version GetVersion()
+       {
+               return Version(1,1,0,1,VF_VENDOR,API_VERSION);
+       }
+};
+
+MODULE_INIT(ModuleOperHash)
index 493904e35292685a7d194f75398d90dec93f3fa3..6fd6c9e981c7e087e86546da2e19a788a0e964c9 100644 (file)
@@ -1 +1,97 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r\r/* $ModDesc: Provides support for oper-only chans via the +O channel mode */\r\rclass OperChans : public ModeHandler\r{\r public:\r        /* This is an oper-only mode */\r        OperChans(InspIRCd* Instance) : ModeHandler(Instance, 'O', 0, 0, false, MODETYPE_CHANNEL, true) { }\r\r   ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)\r {\r              if (adding)\r            {\r                      if (!channel->IsModeSet('O'))\r                  {\r                              channel->SetMode('O',true);\r                            return MODEACTION_ALLOW;\r                       }\r              }\r              else\r           {\r                      if (channel->IsModeSet('O'))\r                   {\r                              channel->SetMode('O',false);\r                           return MODEACTION_ALLOW;\r                       }\r              }\r\r             return MODEACTION_DENY;\r        }\r};\r\rclass ModuleOperChans : public Module\r{\r  \r       OperChans* oc;\r public:\r        ModuleOperChans(InspIRCd* Me)\r          : Module(Me)\r   {\r                              \r               oc = new OperChans(ServerInstance);\r            if (!ServerInstance->AddMode(oc, 'O'))\r                 throw ModuleException("Could not add new modes!");\r     }\r\r     void Implements(char* List)\r    {\r              List[I_OnUserPreJoin] = 1;\r     }\r\r     virtual int OnUserPreJoin(userrec* user, chanrec* chan, const char* cname, std::string &privs)\r {\r              if (!IS_OPER(user))\r            {\r                      if (chan)\r                      {\r                              if (chan->IsModeSet('O'))\r                              {\r                                      user->WriteServ("520 %s %s :Only IRC operators may join the channel %s (+O is set)",user->nick, chan->name,chan->name);\r                                        return 1;\r                              }\r                      }\r              }\r              return 0;\r      }\r      \r       virtual ~ModuleOperChans()\r     {\r              ServerInstance->Modes->DelMode(oc);\r            DELETE(oc);\r    }\r      \r       virtual Version GetVersion()\r   {\r              return Version(1,1,0,0,VF_VENDOR|VF_COMMON,API_VERSION);\r       }\r};\r\rMODULE_INIT(ModuleOperChans)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+
+/* $ModDesc: Provides support for oper-only chans via the +O channel mode */
+
+class OperChans : public ModeHandler
+{
+ public:
+       /* This is an oper-only mode */
+       OperChans(InspIRCd* Instance) : ModeHandler(Instance, 'O', 0, 0, false, MODETYPE_CHANNEL, true) { }
+
+       ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)
+       {
+               if (adding)
+               {
+                       if (!channel->IsModeSet('O'))
+                       {
+                               channel->SetMode('O',true);
+                               return MODEACTION_ALLOW;
+                       }
+               }
+               else
+               {
+                       if (channel->IsModeSet('O'))
+                       {
+                               channel->SetMode('O',false);
+                               return MODEACTION_ALLOW;
+                       }
+               }
+
+               return MODEACTION_DENY;
+       }
+};
+
+class ModuleOperChans : public Module
+{
+       
+       OperChans* oc;
+ public:
+       ModuleOperChans(InspIRCd* Me)
+               : Module(Me)
+       {
+                               
+               oc = new OperChans(ServerInstance);
+               if (!ServerInstance->AddMode(oc, 'O'))
+                       throw ModuleException("Could not add new modes!");
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnUserPreJoin] = 1;
+       }
+
+       virtual int OnUserPreJoin(userrec* user, chanrec* chan, const char* cname, std::string &privs)
+       {
+               if (!IS_OPER(user))
+               {
+                       if (chan)
+                       {
+                               if (chan->IsModeSet('O'))
+                               {
+                                       user->WriteServ("520 %s %s :Only IRC operators may join the channel %s (+O is set)",user->nick, chan->name,chan->name);
+                                       return 1;
+                               }
+                       }
+               }
+               return 0;
+       }
+       
+       virtual ~ModuleOperChans()
+       {
+               ServerInstance->Modes->DelMode(oc);
+               DELETE(oc);
+       }
+       
+       virtual Version GetVersion()
+       {
+               return Version(1,1,0,0,VF_VENDOR|VF_COMMON,API_VERSION);
+       }
+};
+
+MODULE_INIT(ModuleOperChans)
index d69112eba611993748a75109455351edc15c6810..d12bc193225bbade732b1dc028bc40cf77ceb86b 100644 (file)
@@ -1 +1,90 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r\r/* $ModDesc: Forces opers to join the specified channel(s) on oper-up */\r\rclass ModuleOperjoin : public Module\r{\r     private:\r               std::string operChan;\r          std::vector<std::string> operChans;             \r\r              int tokenize(const string &str, std::vector<std::string> &tokens)\r              {\r                      // skip delimiters at beginning.\r                       string::size_type lastPos = str.find_first_not_of(",", 0);\r                     // find first "non-delimiter".\r                 string::size_type pos = str.find_first_of(",", lastPos);\r\r                      while (string::npos != pos || string::npos != lastPos)\r                 {\r                              // found a token, add it to the vector.\r                                tokens.push_back(str.substr(lastPos, pos - lastPos));\r                          // skip delimiters. Note the "not_of"\r                          lastPos = str.find_first_not_of(",", pos);\r                             // find next "non-delimiter"\r                           pos = str.find_first_of(",", lastPos);\r                 }\r                      return tokens.size();\r          }\r\r     public:\r                ModuleOperjoin(InspIRCd* Me) : Module(Me)\r              {\r                      OnRehash(NULL, "");\r            }\r\r             void Implements(char* List)\r            {\r                      List[I_OnPostOper] = List[I_OnRehash] = 1;\r             }\r\r             virtual void OnRehash(userrec* user, const std::string &parameter)\r             {\r                      ConfigReader* conf = new ConfigReader(ServerInstance);\r\r                        operChan = conf->ReadValue("operjoin", "channel", 0);\r                  operChans.clear();\r                     if (!operChan.empty())\r                         tokenize(operChan,operChans);\r\r                 DELETE(conf);\r          }\r\r             virtual ~ModuleOperjoin()\r              {\r              }\r\r             virtual Version GetVersion()\r           {\r                      return Version(1,1,0,1,VF_VENDOR,API_VERSION);\r         }\r\r             virtual void OnPostOper(userrec* user, const std::string &opertype)\r            {\r                      if (!IS_LOCAL(user))\r                           return;\r\r                       for(std::vector<std::string>::iterator it = operChans.begin(); it != operChans.end(); it++)\r                            if (ServerInstance->IsChannel(it->c_str()))\r                                    chanrec::JoinUser(ServerInstance, user, it->c_str(), false, "", ServerInstance->Time(true));\r           }\r\r};\r\rMODULE_INIT(ModuleOperjoin)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+
+/* $ModDesc: Forces opers to join the specified channel(s) on oper-up */
+
+class ModuleOperjoin : public Module
+{
+       private:
+               std::string operChan;
+               std::vector<std::string> operChans;             
+
+               int tokenize(const string &str, std::vector<std::string> &tokens)
+               {
+                       // skip delimiters at beginning.
+                       string::size_type lastPos = str.find_first_not_of(",", 0);
+                       // find first "non-delimiter".
+                       string::size_type pos = str.find_first_of(",", lastPos);
+
+                       while (string::npos != pos || string::npos != lastPos)
+                       {
+                               // found a token, add it to the vector.
+                               tokens.push_back(str.substr(lastPos, pos - lastPos));
+                               // skip delimiters. Note the "not_of"
+                               lastPos = str.find_first_not_of(",", pos);
+                               // find next "non-delimiter"
+                               pos = str.find_first_of(",", lastPos);
+                       }
+                       return tokens.size();
+               }
+
+       public:
+               ModuleOperjoin(InspIRCd* Me) : Module(Me)
+               {
+                       OnRehash(NULL, "");
+               }
+
+               void Implements(char* List)
+               {
+                       List[I_OnPostOper] = List[I_OnRehash] = 1;
+               }
+
+               virtual void OnRehash(userrec* user, const std::string &parameter)
+               {
+                       ConfigReader* conf = new ConfigReader(ServerInstance);
+
+                       operChan = conf->ReadValue("operjoin", "channel", 0);
+                       operChans.clear();
+                       if (!operChan.empty())
+                               tokenize(operChan,operChans);
+
+                       DELETE(conf);
+               }
+
+               virtual ~ModuleOperjoin()
+               {
+               }
+
+               virtual Version GetVersion()
+               {
+                       return Version(1,1,0,1,VF_VENDOR,API_VERSION);
+               }
+
+               virtual void OnPostOper(userrec* user, const std::string &opertype)
+               {
+                       if (!IS_LOCAL(user))
+                               return;
+
+                       for(std::vector<std::string>::iterator it = operChans.begin(); it != operChans.end(); it++)
+                               if (ServerInstance->IsChannel(it->c_str()))
+                                       chanrec::JoinUser(ServerInstance, user, it->c_str(), false, "", ServerInstance->Time(true));
+               }
+
+};
+
+MODULE_INIT(ModuleOperjoin)
index 6d3aa7b14bfcede8ba29fea1b81c17de13566bbf..918d444acc2013497ddd4875cc652cf66ab8b73a 100644 (file)
@@ -1 +1,122 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r\r/* $ModDesc: Gives each oper type a 'level', cannot kill opers 'above' your level. */\r\r\r\rclass ModuleOperLevels : public Module\r{\r\r   private:\r\r              \r               ConfigReader* conf;\r\r   public:\r\r               ModuleOperLevels(InspIRCd* Me)\r                 : Module(Me)\r           {\r\r                     \r                       conf = new ConfigReader(ServerInstance);\r               }\r\r             virtual ~ModuleOperLevels()\r            {\r                      DELETE(conf);\r          }\r\r             void Implements(char* List)\r            {\r                      List[I_OnRehash] = List[I_OnKill] = 1;\r         }\r\r             virtual void OnRehash(userrec* user, const std::string &parameter)\r             {\r                      DELETE(conf);\r                  conf = new ConfigReader(ServerInstance);\r               }\r\r             virtual Version GetVersion()\r           {\r                      return Version(1,1,0,1,VF_VENDOR,API_VERSION);\r         }\r\r             virtual int OnKill(userrec* source, userrec* dest, const std::string &reason)\r          {\r                      long dest_level = 0,source_level = 0;\r\r                 // oper killing an oper?\r                       if (IS_OPER(dest) && IS_OPER(source))\r                  {\r                              for (int j =0; j < conf->Enumerate("type"); j++)\r                               {\r                                      std::string typen = conf->ReadValue("type","name",j);\r                                  if (!strcmp(typen.c_str(),dest->oper))\r                                 {\r                                              dest_level = conf->ReadInteger("type","level",j,true);\r                                         break;\r                                 }\r                              }\r                              for (int k =0; k < conf->Enumerate("type"); k++)\r                               {\r                                      std::string typen = conf->ReadValue("type","name",k);\r                                  if (!strcmp(typen.c_str(),source->oper))\r                                       {\r                                              source_level = conf->ReadInteger("type","level",k,true);\r                                               break;\r                                 }\r                              }\r                              if (dest_level > source_level)\r                         {\r                                      ServerInstance->WriteOpers("Oper %s (level %d) attempted to /kill a higher oper: %s (level %d): Reason: %s",source->nick,source_level,dest->nick,dest_level,reason.c_str());\r                                   dest->WriteServ("NOTICE %s :Oper %s attempted to /kill you!",dest->nick,source->nick);\r                                 source->WriteServ("481 %s :Permission Denied - Oper %s is a higher level than you",source->nick,dest->nick);\r                                   return 1;\r                              }\r                      }\r                      return 0;\r              }\r\r};\r\rclass ModuleOperLevelsFactory : public ModuleFactory\r{\r public:\r ModuleOperLevelsFactory()\r      {\r      }\r\r     ~ModuleOperLevelsFactory()\r     {\r      }\r\r     virtual Module * CreateModule(InspIRCd* Me)\r    {\r              return new ModuleOperLevels(Me);\r       }\r\r};\r\rextern "C" DllExport void * init_module( void )\r{\r       return new ModuleOperLevelsFactory;\r}\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+
+/* $ModDesc: Gives each oper type a 'level', cannot kill opers 'above' your level. */
+
+
+
+class ModuleOperLevels : public Module
+{
+
+       private:
+
+               
+               ConfigReader* conf;
+
+       public:
+
+               ModuleOperLevels(InspIRCd* Me)
+                       : Module(Me)
+               {
+
+                       
+                       conf = new ConfigReader(ServerInstance);
+               }
+
+               virtual ~ModuleOperLevels()
+               {
+                       DELETE(conf);
+               }
+
+               void Implements(char* List)
+               {
+                       List[I_OnRehash] = List[I_OnKill] = 1;
+               }
+
+               virtual void OnRehash(userrec* user, const std::string &parameter)
+               {
+                       DELETE(conf);
+                       conf = new ConfigReader(ServerInstance);
+               }
+
+               virtual Version GetVersion()
+               {
+                       return Version(1,1,0,1,VF_VENDOR,API_VERSION);
+               }
+
+               virtual int OnKill(userrec* source, userrec* dest, const std::string &reason)
+               {
+                       long dest_level = 0,source_level = 0;
+
+                       // oper killing an oper?
+                       if (IS_OPER(dest) && IS_OPER(source))
+                       {
+                               for (int j =0; j < conf->Enumerate("type"); j++)
+                               {
+                                       std::string typen = conf->ReadValue("type","name",j);
+                                       if (!strcmp(typen.c_str(),dest->oper))
+                                       {
+                                               dest_level = conf->ReadInteger("type","level",j,true);
+                                               break;
+                                       }
+                               }
+                               for (int k =0; k < conf->Enumerate("type"); k++)
+                               {
+                                       std::string typen = conf->ReadValue("type","name",k);
+                                       if (!strcmp(typen.c_str(),source->oper))
+                                       {
+                                               source_level = conf->ReadInteger("type","level",k,true);
+                                               break;
+                                       }
+                               }
+                               if (dest_level > source_level)
+                               {
+                                       ServerInstance->WriteOpers("Oper %s (level %d) attempted to /kill a higher oper: %s (level %d): Reason: %s",source->nick,source_level,dest->nick,dest_level,reason.c_str());
+                                       dest->WriteServ("NOTICE %s :Oper %s attempted to /kill you!",dest->nick,source->nick);
+                                       source->WriteServ("481 %s :Permission Denied - Oper %s is a higher level than you",source->nick,dest->nick);
+                                       return 1;
+                               }
+                       }
+                       return 0;
+               }
+
+};
+
+class ModuleOperLevelsFactory : public ModuleFactory
+{
+ public:
+       ModuleOperLevelsFactory()
+       {
+       }
+
+       ~ModuleOperLevelsFactory()
+       {
+       }
+
+       virtual Module * CreateModule(InspIRCd* Me)
+       {
+               return new ModuleOperLevels(Me);
+       }
+
+};
+
+extern "C" DllExport void * init_module( void )
+{
+       return new ModuleOperLevelsFactory;
+}
+
index 1a7d5bd8acb132d756c3da51cc1a6b32c953e9b0..9bbdbef25678b141c9ed3bfa8ed844e49fc5bf32 100644 (file)
@@ -1 +1,75 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h" \r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r\r/* $ModDesc: A module which logs all oper commands to the ircd log at default loglevel. */\r\rclass ModuleOperLog : public Module\r{\r private:\r  \r public:\r     ModuleOperLog(InspIRCd* Me) : Module(Me)\r       {\r              \r       }\r \r    virtual ~ModuleOperLog()\r       {\r      }\r \r    virtual Version GetVersion()\r   {\r              return Version(1,1,0,0,VF_VENDOR,API_VERSION);\r }\r \r    void Implements(char* List)\r    {\r              List[I_OnPreCommand] = List[I_On005Numeric] = 1;\r       }\r\r     virtual int OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line)\r       {\r              /* If the command doesnt appear to be valid, we dont want to mess with it. */\r          if (!validated)\r                        return 0;\r \r            if ((IS_OPER(user)) && (IS_LOCAL(user)) && (user->HasPermission(command)))\r             {\r                      command_t* thiscommand = ServerInstance->Parser->GetHandler(command);\r                  if ((thiscommand) && (thiscommand->flags_needed = 'o'))\r                        {\r                              std::string plist;\r                             for (int j = 0; j < pcnt; j++)\r                                 plist.append(std::string(" ")+std::string(parameters[j]));\r\r                            ServerInstance->Log(DEFAULT,"OPERLOG: [%s!%s@%s] %s%s",user->nick,user->ident,user->host,command.c_str(),plist.c_str());\r                       }\r              }\r\r             return 0;\r      }\r\r     virtual void On005Numeric(std::string &output)\r {\r              output.append(" OPERLOG");\r     }\r\r};\r \r \rMODULE_INIT(ModuleOperLog)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h" 
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+
+/* $ModDesc: A module which logs all oper commands to the ircd log at default loglevel. */
+
+class ModuleOperLog : public Module
+{
+ private:
+        
+ public:
+       ModuleOperLog(InspIRCd* Me) : Module(Me)
+       {
+               
+       }
+       virtual ~ModuleOperLog()
+       {
+       }
+       virtual Version GetVersion()
+       {
+               return Version(1,1,0,0,VF_VENDOR,API_VERSION);
+       }
+       void Implements(char* List)
+       {
+               List[I_OnPreCommand] = List[I_On005Numeric] = 1;
+       }
+
+       virtual int OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line)
+       {
+               /* If the command doesnt appear to be valid, we dont want to mess with it. */
+               if (!validated)
+                       return 0;
+               if ((IS_OPER(user)) && (IS_LOCAL(user)) && (user->HasPermission(command)))
+               {
+                       command_t* thiscommand = ServerInstance->Parser->GetHandler(command);
+                       if ((thiscommand) && (thiscommand->flags_needed = 'o'))
+                       {
+                               std::string plist;
+                               for (int j = 0; j < pcnt; j++)
+                                       plist.append(std::string(" ")+std::string(parameters[j]));
+
+                               ServerInstance->Log(DEFAULT,"OPERLOG: [%s!%s@%s] %s%s",user->nick,user->ident,user->host,command.c_str(),plist.c_str());
+                       }
+               }
+
+               return 0;
+       }
+
+       virtual void On005Numeric(std::string &output)
+       {
+               output.append(" OPERLOG");
+       }
+
+};
+MODULE_INIT(ModuleOperLog)
index 05d7a2b42ba5f7e02dd9bf2a8a53a08dd794413b..598f84e4355c2469fb7087dbb07f2f7224881e3e 100644 (file)
@@ -1 +1,109 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r\r/* $ModDesc: Sets (and unsets) modes on opers when they oper up */\r\rclass ModuleModesOnOper : public Module\r{\r private:\r\r     \r       ConfigReader *Conf;\r\r public:\r  ModuleModesOnOper(InspIRCd* Me)\r                : Module(Me)\r   {\r              \r               Conf = new ConfigReader(ServerInstance);\r       }\r\r     void Implements(char* List)\r    {\r              List[I_OnPostOper] = List[I_OnRehash] = 1;\r     }\r\r     virtual void OnRehash(userrec* user, const std::string &parameter)\r     {\r              DELETE(Conf);\r          Conf = new ConfigReader(ServerInstance);\r       }\r      \r       virtual ~ModuleModesOnOper()\r   {\r              DELETE(Conf);\r  }\r      \r       virtual Version GetVersion()\r   {\r              return Version(1,1,0,1,VF_VENDOR,API_VERSION);\r }\r      \r       virtual void OnPostOper(userrec* user, const std::string &opertype)\r    {\r              // whenever a user opers, go through the oper types, find their <type:modes>,\r          // and if they have one apply their modes. The mode string can contain +modes\r          // to add modes to the user or -modes to take modes from the user.\r             for (int j =0; j < Conf->Enumerate("type"); j++)\r               {\r                      std::string typen = Conf->ReadValue("type","name",j);\r                  if (!strcmp(typen.c_str(),user->oper))\r                 {\r                              std::string ThisOpersModes = Conf->ReadValue("type","modes",j);\r                                if (!ThisOpersModes.empty())\r                           {\r                                      char first = *(ThisOpersModes.c_str());\r                                        if ((first != '+') && (first != '-'))\r                                          ThisOpersModes = "+" + ThisOpersModes;\r\r                                        std::string buf;\r                                       stringstream ss(ThisOpersModes);\r                                       vector<string> tokens;\r\r                                        // split ThisOperModes into modes and mode params\r                                      while (ss >> buf)\r                                              tokens.push_back(buf);\r\r                                        int size = tokens.size() + 1;\r                                  const char** modes = new const char*[size];\r                                    modes[0] = user->nick;\r\r                                        // process mode params\r                                 int i = 1;\r                                     for (unsigned int k = 0; k < tokens.size(); k++)\r                                       {\r                                              modes[i] = tokens[k].c_str();\r                                          i++;\r                                   }\r\r                                     std::deque<std::string> n;\r                                     Event rmode((char *)&n, NULL, "send_mode_explicit");\r                                   for (unsigned int j = 0; j < tokens.size(); j++)\r                                               n.push_back(modes[j]);\r\r                                        rmode.Send(ServerInstance);\r                                    ServerInstance->SendMode(modes, size, user);\r                                   delete [] modes;\r                               }\r                              break;\r                 }\r              }\r      }\r};\r\rMODULE_INIT(ModuleModesOnOper)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+
+/* $ModDesc: Sets (and unsets) modes on opers when they oper up */
+
+class ModuleModesOnOper : public Module
+{
+ private:
+
+       
+       ConfigReader *Conf;
+
+ public:
+       ModuleModesOnOper(InspIRCd* Me)
+               : Module(Me)
+       {
+               
+               Conf = new ConfigReader(ServerInstance);
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnPostOper] = List[I_OnRehash] = 1;
+       }
+
+       virtual void OnRehash(userrec* user, const std::string &parameter)
+       {
+               DELETE(Conf);
+               Conf = new ConfigReader(ServerInstance);
+       }
+       
+       virtual ~ModuleModesOnOper()
+       {
+               DELETE(Conf);
+       }
+       
+       virtual Version GetVersion()
+       {
+               return Version(1,1,0,1,VF_VENDOR,API_VERSION);
+       }
+       
+       virtual void OnPostOper(userrec* user, const std::string &opertype)
+       {
+               // whenever a user opers, go through the oper types, find their <type:modes>,
+               // and if they have one apply their modes. The mode string can contain +modes
+               // to add modes to the user or -modes to take modes from the user.
+               for (int j =0; j < Conf->Enumerate("type"); j++)
+               {
+                       std::string typen = Conf->ReadValue("type","name",j);
+                       if (!strcmp(typen.c_str(),user->oper))
+                       {
+                               std::string ThisOpersModes = Conf->ReadValue("type","modes",j);
+                               if (!ThisOpersModes.empty())
+                               {
+                                       char first = *(ThisOpersModes.c_str());
+                                       if ((first != '+') && (first != '-'))
+                                               ThisOpersModes = "+" + ThisOpersModes;
+
+                                       std::string buf;
+                                       stringstream ss(ThisOpersModes);
+                                       vector<string> tokens;
+
+                                       // split ThisOperModes into modes and mode params
+                                       while (ss >> buf)
+                                               tokens.push_back(buf);
+
+                                       int size = tokens.size() + 1;
+                                       const char** modes = new const char*[size];
+                                       modes[0] = user->nick;
+
+                                       // process mode params
+                                       int i = 1;
+                                       for (unsigned int k = 0; k < tokens.size(); k++)
+                                       {
+                                               modes[i] = tokens[k].c_str();
+                                               i++;
+                                       }
+
+                                       std::deque<std::string> n;
+                                       Event rmode((char *)&n, NULL, "send_mode_explicit");
+                                       for (unsigned int j = 0; j < tokens.size(); j++)
+                                               n.push_back(modes[j]);
+
+                                       rmode.Send(ServerInstance);
+                                       ServerInstance->SendMode(modes, size, user);
+                                       delete [] modes;
+                               }
+                               break;
+                       }
+               }
+       }
+};
+
+MODULE_INIT(ModuleModesOnOper)
index 7e48eefdbb2e792c4fb5d5b219bd3a2788a1f103..55608dcb8ccddfa9891e131350443cca52c4fae3 100644 (file)
@@ -1 +1,116 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r\r/* $ModDesc: Shows a message to opers after oper-up, adds /opermotd */\r\rstatic FileReader* opermotd;\r\rCmdResult ShowOperMOTD(userrec* user)\r{\r        if(!opermotd->FileSize())\r      {\r              user->WriteServ(std::string("425 ") + user->nick + std::string(" :OPERMOTD file is missing"));\r         return CMD_FAILURE;\r    }\r\r     user->WriteServ(std::string("375 ") + user->nick + std::string(" :- IRC Operators Message of the Day"));\r\r      for(int i=0; i != opermotd->FileSize(); i++)\r   {\r              user->WriteServ(std::string("372 ") + user->nick + std::string(" :- ") + opermotd->GetLine(i));\r        }\r\r     user->WriteServ(std::string("376 ") + user->nick + std::string(" :- End of OPERMOTD"));\r\r       /* don't route me */\r   return CMD_LOCALONLY;\r}\r\r/** Handle /OPERMOTD\r */\rclass cmd_opermotd : public command_t\r{\r public:\r     cmd_opermotd (InspIRCd* Instance) : command_t(Instance,"OPERMOTD", 'o', 0)\r     {\r              this->source = "m_opermotd.so";\r                syntax = "[<servername>]";\r     }\r\r     CmdResult Handle (const char** parameters, int pcnt, userrec* user)\r    {\r              return ShowOperMOTD(user);\r     }\r};\r\r\rclass ModuleOpermotd : public Module\r{\r  cmd_opermotd* mycommand;\r public:\r\r     void LoadOperMOTD()\r    {\r              ConfigReader* conf = new ConfigReader(ServerInstance);\r         std::string filename;\r          filename = conf->ReadValue("opermotd","file",0);\r               if (opermotd)\r          {\r                      delete opermotd;\r                       opermotd = NULL;\r               }\r              opermotd = new FileReader(ServerInstance, filename);\r           DELETE(conf);\r  }\r      \r       ModuleOpermotd(InspIRCd* Me)\r           : Module(Me)\r   {\r              opermotd = NULL;\r               mycommand = new cmd_opermotd(ServerInstance);\r          ServerInstance->AddCommand(mycommand);\r         opermotd = new FileReader(ServerInstance);\r             LoadOperMOTD();\r        }\r\r     virtual ~ModuleOpermotd()\r      {\r      }\r\r     virtual Version GetVersion()\r   {\r              return Version(1,1,0,1,VF_VENDOR,API_VERSION);\r }\r\r     void Implements(char* List)\r    {\r              List[I_OnRehash] = List[I_OnOper] = 1;\r }\r\r     virtual void OnOper(userrec* user, const std::string &opertype)\r        {\r              ShowOperMOTD(user);\r    }\r\r     virtual void OnRehash(userrec* user, const std::string &parameter)\r     {\r              LoadOperMOTD();\r        }\r};\r\rMODULE_INIT(ModuleOpermotd)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+
+/* $ModDesc: Shows a message to opers after oper-up, adds /opermotd */
+
+static FileReader* opermotd;
+
+CmdResult ShowOperMOTD(userrec* user)
+{
+       if(!opermotd->FileSize())
+       {
+               user->WriteServ(std::string("425 ") + user->nick + std::string(" :OPERMOTD file is missing"));
+               return CMD_FAILURE;
+       }
+
+       user->WriteServ(std::string("375 ") + user->nick + std::string(" :- IRC Operators Message of the Day"));
+
+       for(int i=0; i != opermotd->FileSize(); i++)
+       {
+               user->WriteServ(std::string("372 ") + user->nick + std::string(" :- ") + opermotd->GetLine(i));
+       }
+
+       user->WriteServ(std::string("376 ") + user->nick + std::string(" :- End of OPERMOTD"));
+
+       /* don't route me */
+       return CMD_LOCALONLY;
+}
+
+/** Handle /OPERMOTD
+ */
+class cmd_opermotd : public command_t
+{
+ public:
+       cmd_opermotd (InspIRCd* Instance) : command_t(Instance,"OPERMOTD", 'o', 0)
+       {
+               this->source = "m_opermotd.so";
+               syntax = "[<servername>]";
+       }
+
+       CmdResult Handle (const char** parameters, int pcnt, userrec* user)
+       {
+               return ShowOperMOTD(user);
+       }
+};
+
+
+class ModuleOpermotd : public Module
+{
+       cmd_opermotd* mycommand;
+ public:
+
+       void LoadOperMOTD()
+       {
+               ConfigReader* conf = new ConfigReader(ServerInstance);
+               std::string filename;
+               filename = conf->ReadValue("opermotd","file",0);
+               if (opermotd)
+               {
+                       delete opermotd;
+                       opermotd = NULL;
+               }
+               opermotd = new FileReader(ServerInstance, filename);
+               DELETE(conf);
+       }
+       
+       ModuleOpermotd(InspIRCd* Me)
+               : Module(Me)
+       {
+               opermotd = NULL;
+               mycommand = new cmd_opermotd(ServerInstance);
+               ServerInstance->AddCommand(mycommand);
+               opermotd = new FileReader(ServerInstance);
+               LoadOperMOTD();
+       }
+
+       virtual ~ModuleOpermotd()
+       {
+       }
+
+       virtual Version GetVersion()
+       {
+               return Version(1,1,0,1,VF_VENDOR,API_VERSION);
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnRehash] = List[I_OnOper] = 1;
+       }
+
+       virtual void OnOper(userrec* user, const std::string &opertype)
+       {
+               ShowOperMOTD(user);
+       }
+
+       virtual void OnRehash(userrec* user, const std::string &parameter)
+       {
+               LoadOperMOTD();
+       }
+};
+
+MODULE_INIT(ModuleOpermotd)
index c5b343552d26e2e3ad97c69b28b90ebbdbbac504..be123d4fd71448ebfeb80332748cdf79594a71bf 100644 (file)
@@ -1 +1,294 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r#include "configreader.h"\r#include "wildcard.h"\r\r/* $ModDesc: Provides support for unreal-style oper-override */\r\rtypedef std::map<std::string,std::string> override_t;\r\rclass ModuleOverride : public Module\r{\r       \r       override_t overrides;\r  bool NoisyOverride;\r    bool OverriddenMode;\r   int OverOps, OverDeops, OverVoices, OverDevoices, OverHalfops, OverDehalfops;\r\r public:\r \r      ModuleOverride(InspIRCd* Me)\r           : Module(Me)\r   {               \r               // read our config options (main config file)\r          OnRehash(NULL,"");\r             ServerInstance->SNO->EnableSnomask('O',"OVERRIDE");\r            OverriddenMode = false;\r                OverOps = OverDeops = OverVoices = OverDevoices = OverHalfops = OverDehalfops = 0;\r     }\r      \r       virtual void OnRehash(userrec* user, const std::string &parameter)\r     {\r              // on a rehash we delete our classes for good measure and create them again.\r           ConfigReader* Conf = new ConfigReader(ServerInstance);\r         \r               // re-read our config options on a rehash\r              NoisyOverride = Conf->ReadFlag("override","noisy",0);\r          overrides.clear();\r             for (int j =0; j < Conf->Enumerate("type"); j++)\r               {\r                      std::string typen = Conf->ReadValue("type","name",j);\r                  std::string tokenlist = Conf->ReadValue("type","override",j);\r                  overrides[typen] = tokenlist;\r          }\r              \r               DELETE(Conf);\r  }\r\r     void Implements(char* List)\r    {\r              List[I_OnRehash] = List[I_OnAccessCheck] = List[I_On005Numeric] = List[I_OnUserPreJoin] = List[I_OnUserPreKick] = List[I_OnPostCommand] = 1;\r   }\r\r     virtual void OnPostCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, CmdResult result, const std::string &original_line)\r   {\r              if ((NoisyOverride) && (OverriddenMode) && (irc::string(command.c_str()) == "MODE") && (result == CMD_SUCCESS))\r                {\r                      int Total = OverOps + OverDeops + OverVoices + OverDevoices + OverHalfops + OverDehalfops;\r\r                    ServerInstance->SNO->WriteToSnoMask('O',std::string(user->nick)+" Overriding modes: "+ServerInstance->Modes->GetLastParse()+" "+(Total ? "[Detail: " : "")+\r                                    (OverOps ? ConvToStr(OverOps)+" op"+(OverOps != 1 ? "s" : "")+" " : "")+\r                                       (OverDeops ? ConvToStr(OverDeops)+" deop"+(OverDeops != 1 ? "s" : "")+" " : "")+\r                                       (OverVoices ? ConvToStr(OverVoices)+" voice"+(OverVoices != 1 ? "s" : "")+" " : "")+\r                                   (OverDevoices ? ConvToStr(OverDevoices)+" devoice"+(OverDevoices != 1 ? "s" : "")+" " : "")+\r                                   (OverHalfops ? ConvToStr(OverHalfops)+" halfop"+(OverHalfops != 1 ? "s" : "")+" " : "")+\r                                       (OverDehalfops ? ConvToStr(OverDehalfops)+" dehalfop"+(OverDehalfops != 1 ? "s" : "") : "")\r                                    +(Total ? "]" : ""));\r\r                 OverriddenMode = false;\r                        OverOps = OverDeops = OverVoices = OverDevoices = OverHalfops = OverDehalfops = 0;\r             }\r      }\r\r     virtual void On005Numeric(std::string &output)\r {\r              output.append(" OVERRIDE");\r    }\r\r     virtual bool CanOverride(userrec* source, char* token)\r {\r              // checks to see if the oper's type has <type:override>\r                override_t::iterator j = overrides.find(source->oper);\r\r                if (j != overrides.end())\r              {\r                      // its defined or * is set, return its value as a boolean for if the token is set\r                      return ((j->second.find(token, 0) != std::string::npos) || (j->second.find("*", 0) != std::string::npos));\r             }\r\r             // its not defined at all, count as false\r              return false;\r  }\r\r     virtual int OnUserPreKick(userrec* source, userrec* user, chanrec* chan, const std::string &reason)\r    {\r              if (IS_OPER(source) && CanOverride(source,"KICK"))\r             {\r                      if (((chan->GetStatus(source) == STATUS_HOP) && (chan->GetStatus(user) == STATUS_OP)) || (chan->GetStatus(source) < STATUS_VOICE))\r                     {\r                              ServerInstance->SNO->WriteToSnoMask('O',std::string(source->nick)+" Override-Kicked "+std::string(user->nick)+" on "+std::string(chan->name)+" ("+reason+")");\r                 }\r                      /* Returning -1 explicitly allows the kick */\r                  return -1;\r             }\r              return 0;\r      }\r      \r       virtual int OnAccessCheck(userrec* source,userrec* dest,chanrec* channel,int access_type)\r      {\r              if (IS_OPER(source))\r           {\r                      if (source && channel)\r                 {\r                              // Fix by brain - allow the change if they arent on channel - rely on boolean short-circuit\r                            // to not check the other items in the statement if they arent on the channel\r                          int mode = channel->GetStatus(source);\r                         switch (access_type)\r                           {\r                                      case AC_DEOP:\r                                          if (CanOverride(source,"MODEDEOP"))\r                                            {\r                                                      if (NoisyOverride)\r                                                     if ((!channel->HasUser(source)) || (mode < STATUS_OP))\r                                                         OverDeops++;\r                                                   return ACR_ALLOW;\r                                              }\r                                              else\r                                           {\r                                                      return ACR_DEFAULT;\r                                            }\r                                      break;\r                                 case AC_OP:\r                                            if (CanOverride(source,"MODEOP"))\r                                              {\r                                                      if (NoisyOverride)\r                                                     if ((!channel->HasUser(source)) || (mode < STATUS_OP))\r                                                         OverOps++;\r                                                     return ACR_ALLOW;\r                                              }\r                                              else\r                                           {\r                                                      return ACR_DEFAULT;\r                                            }\r                                      break;\r                                 case AC_VOICE:\r                                         if (CanOverride(source,"MODEVOICE"))\r                                           {\r                                                      if (NoisyOverride)\r                                                     if ((!channel->HasUser(source)) || (mode < STATUS_HOP))\r                                                                OverVoices++;\r                                                  return ACR_ALLOW;\r                                              }\r                                              else\r                                           {\r                                                      return ACR_DEFAULT;\r                                            }\r                                      break;\r                                 case AC_DEVOICE:\r                                               if (CanOverride(source,"MODEDEVOICE"))\r                                         {\r                                                      if (NoisyOverride)\r                                                     if ((!channel->HasUser(source)) || (mode < STATUS_HOP))\r                                                                OverDevoices++;\r                                                        return ACR_ALLOW;\r                                              }\r                                              else\r                                           {\r                                                      return ACR_DEFAULT;\r                                            }\r                                      break;\r                                 case AC_HALFOP:\r                                                if (CanOverride(source,"MODEHALFOP"))\r                                          {\r                                                      if (NoisyOverride)\r                                                     if ((!channel->HasUser(source)) || (mode < STATUS_OP))\r                                                         OverHalfops++;\r                                                 return ACR_ALLOW;\r                                              }\r                                              else\r                                           {\r                                                      return ACR_DEFAULT;\r                                            }\r                                      break;\r                                 case AC_DEHALFOP:\r                                              if (CanOverride(source,"MODEDEHALFOP"))\r                                                {\r                                                      if (NoisyOverride)\r                                                     if ((!channel->HasUser(source)) || (mode < STATUS_OP))\r                                                         OverDehalfops++;\r                                                       return ACR_ALLOW;\r                                              }\r                                              else\r                                           {\r                                                      return ACR_DEFAULT;\r                                            }\r                                      break;\r                         }\r                      \r                               if (CanOverride(source,"OTHERMODE"))\r                           {\r                                      if (NoisyOverride)\r                                     if ((!channel->HasUser(source)) || (mode < STATUS_OP))\r                                 {\r                                              OverriddenMode = true;\r                                         OverOps = OverDeops = OverVoices = OverDevoices = OverHalfops = OverDehalfops = 0;\r                                     }\r                                      return ACR_ALLOW;\r                              }\r                              else\r                           {\r                                      return ACR_DEFAULT;\r                            }\r                      }\r              }\r\r             return ACR_DEFAULT;\r    }\r      \r       virtual int OnUserPreJoin(userrec* user, chanrec* chan, const char* cname, std::string &privs)\r {\r              if (IS_OPER(user))\r             {\r                      if (chan)\r                      {\r                              if ((chan->modes[CM_INVITEONLY]) && (CanOverride(user,"INVITE")))\r                              {\r                                      irc::string x = chan->name;\r                                    if (!user->IsInvited(x))\r                                       {\r                                              /* XXX - Ugly cast for a parameter that isn't used? :< - Om */\r                                         if (NoisyOverride)\r                                                     chan->WriteChannelWithServ(ServerInstance->Config->ServerName, "NOTICE %s :%s used oper-override to bypass invite-only", cname, user->nick);\r                                           ServerInstance->SNO->WriteToSnoMask('O',std::string(user->nick)+" used operoverride to bypass +i on "+std::string(cname));\r                                     }\r                                      return -1;\r                             }\r                              \r                               if ((*chan->key) && (CanOverride(user,"KEY")))\r                         {\r                                      if (NoisyOverride)\r                                             chan->WriteChannelWithServ(ServerInstance->Config->ServerName, "NOTICE %s :%s used oper-override to bypass the channel key", cname, user->nick);\r                                       ServerInstance->SNO->WriteToSnoMask('O',std::string(user->nick)+" used operoverride to bypass +k on "+std::string(cname));\r                                     return -1;\r                             }\r                                      \r                               if ((chan->limit > 0) && (chan->GetUserCounter() >=  chan->limit) && (CanOverride(user,"LIMIT")))\r                              {\r                                      if (NoisyOverride)\r                                             chan->WriteChannelWithServ(ServerInstance->Config->ServerName, "NOTICE %s :%s used oper-override to bypass the channel limit", cname, user->nick);\r                                     ServerInstance->SNO->WriteToSnoMask('O',std::string(user->nick)+" used operoverride to bypass +l on "+std::string(cname));\r                                     return -1;\r                             }\r\r                             if (CanOverride(user,"BANWALK"))\r                               {\r                                      if (chan->IsBanned(user))\r                                      {\r                                              if (NoisyOverride)\r                                                     chan->WriteChannelWithServ(ServerInstance->Config->ServerName, "NOTICE %s :%s used oper-override to bypass channel ban", cname, user->nick);\r                                           ServerInstance->SNO->WriteToSnoMask('O',"%s used oper-override to bypass channel ban on %s", user->nick, cname);\r                                       }\r                                      return -1;\r                             }\r                      }\r              }\r              return 0;\r      }\r      \r       virtual ~ModuleOverride()\r      {\r              ServerInstance->SNO->DisableSnomask('O');\r      }\r      \r       virtual Version GetVersion()\r   {\r              return Version(1,1,0,1,VF_VENDOR,API_VERSION);\r }\r};\r\rMODULE_INIT(ModuleOverride)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+#include "configreader.h"
+#include "wildcard.h"
+
+/* $ModDesc: Provides support for unreal-style oper-override */
+
+typedef std::map<std::string,std::string> override_t;
+
+class ModuleOverride : public Module
+{
+       
+       override_t overrides;
+       bool NoisyOverride;
+       bool OverriddenMode;
+       int OverOps, OverDeops, OverVoices, OverDevoices, OverHalfops, OverDehalfops;
+
+ public:
+       ModuleOverride(InspIRCd* Me)
+               : Module(Me)
+       {               
+               // read our config options (main config file)
+               OnRehash(NULL,"");
+               ServerInstance->SNO->EnableSnomask('O',"OVERRIDE");
+               OverriddenMode = false;
+               OverOps = OverDeops = OverVoices = OverDevoices = OverHalfops = OverDehalfops = 0;
+       }
+       
+       virtual void OnRehash(userrec* user, const std::string &parameter)
+       {
+               // on a rehash we delete our classes for good measure and create them again.
+               ConfigReader* Conf = new ConfigReader(ServerInstance);
+               
+               // re-read our config options on a rehash
+               NoisyOverride = Conf->ReadFlag("override","noisy",0);
+               overrides.clear();
+               for (int j =0; j < Conf->Enumerate("type"); j++)
+               {
+                       std::string typen = Conf->ReadValue("type","name",j);
+                       std::string tokenlist = Conf->ReadValue("type","override",j);
+                       overrides[typen] = tokenlist;
+               }
+               
+               DELETE(Conf);
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnRehash] = List[I_OnAccessCheck] = List[I_On005Numeric] = List[I_OnUserPreJoin] = List[I_OnUserPreKick] = List[I_OnPostCommand] = 1;
+       }
+
+       virtual void OnPostCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, CmdResult result, const std::string &original_line)
+       {
+               if ((NoisyOverride) && (OverriddenMode) && (irc::string(command.c_str()) == "MODE") && (result == CMD_SUCCESS))
+               {
+                       int Total = OverOps + OverDeops + OverVoices + OverDevoices + OverHalfops + OverDehalfops;
+
+                       ServerInstance->SNO->WriteToSnoMask('O',std::string(user->nick)+" Overriding modes: "+ServerInstance->Modes->GetLastParse()+" "+(Total ? "[Detail: " : "")+
+                                       (OverOps ? ConvToStr(OverOps)+" op"+(OverOps != 1 ? "s" : "")+" " : "")+
+                                       (OverDeops ? ConvToStr(OverDeops)+" deop"+(OverDeops != 1 ? "s" : "")+" " : "")+
+                                       (OverVoices ? ConvToStr(OverVoices)+" voice"+(OverVoices != 1 ? "s" : "")+" " : "")+
+                                       (OverDevoices ? ConvToStr(OverDevoices)+" devoice"+(OverDevoices != 1 ? "s" : "")+" " : "")+
+                                       (OverHalfops ? ConvToStr(OverHalfops)+" halfop"+(OverHalfops != 1 ? "s" : "")+" " : "")+
+                                       (OverDehalfops ? ConvToStr(OverDehalfops)+" dehalfop"+(OverDehalfops != 1 ? "s" : "") : "")
+                                       +(Total ? "]" : ""));
+
+                       OverriddenMode = false;
+                       OverOps = OverDeops = OverVoices = OverDevoices = OverHalfops = OverDehalfops = 0;
+               }
+       }
+
+       virtual void On005Numeric(std::string &output)
+       {
+               output.append(" OVERRIDE");
+       }
+
+       virtual bool CanOverride(userrec* source, char* token)
+       {
+               // checks to see if the oper's type has <type:override>
+               override_t::iterator j = overrides.find(source->oper);
+
+               if (j != overrides.end())
+               {
+                       // its defined or * is set, return its value as a boolean for if the token is set
+                       return ((j->second.find(token, 0) != std::string::npos) || (j->second.find("*", 0) != std::string::npos));
+               }
+
+               // its not defined at all, count as false
+               return false;
+       }
+
+       virtual int OnUserPreKick(userrec* source, userrec* user, chanrec* chan, const std::string &reason)
+       {
+               if (IS_OPER(source) && CanOverride(source,"KICK"))
+               {
+                       if (((chan->GetStatus(source) == STATUS_HOP) && (chan->GetStatus(user) == STATUS_OP)) || (chan->GetStatus(source) < STATUS_VOICE))
+                       {
+                               ServerInstance->SNO->WriteToSnoMask('O',std::string(source->nick)+" Override-Kicked "+std::string(user->nick)+" on "+std::string(chan->name)+" ("+reason+")");
+                       }
+                       /* Returning -1 explicitly allows the kick */
+                       return -1;
+               }
+               return 0;
+       }
+       
+       virtual int OnAccessCheck(userrec* source,userrec* dest,chanrec* channel,int access_type)
+       {
+               if (IS_OPER(source))
+               {
+                       if (source && channel)
+                       {
+                               // Fix by brain - allow the change if they arent on channel - rely on boolean short-circuit
+                               // to not check the other items in the statement if they arent on the channel
+                               int mode = channel->GetStatus(source);
+                               switch (access_type)
+                               {
+                                       case AC_DEOP:
+                                               if (CanOverride(source,"MODEDEOP"))
+                                               {
+                                                       if (NoisyOverride)
+                                                       if ((!channel->HasUser(source)) || (mode < STATUS_OP))
+                                                               OverDeops++;
+                                                       return ACR_ALLOW;
+                                               }
+                                               else
+                                               {
+                                                       return ACR_DEFAULT;
+                                               }
+                                       break;
+                                       case AC_OP:
+                                               if (CanOverride(source,"MODEOP"))
+                                               {
+                                                       if (NoisyOverride)
+                                                       if ((!channel->HasUser(source)) || (mode < STATUS_OP))
+                                                               OverOps++;
+                                                       return ACR_ALLOW;
+                                               }
+                                               else
+                                               {
+                                                       return ACR_DEFAULT;
+                                               }
+                                       break;
+                                       case AC_VOICE:
+                                               if (CanOverride(source,"MODEVOICE"))
+                                               {
+                                                       if (NoisyOverride)
+                                                       if ((!channel->HasUser(source)) || (mode < STATUS_HOP))
+                                                               OverVoices++;
+                                                       return ACR_ALLOW;
+                                               }
+                                               else
+                                               {
+                                                       return ACR_DEFAULT;
+                                               }
+                                       break;
+                                       case AC_DEVOICE:
+                                               if (CanOverride(source,"MODEDEVOICE"))
+                                               {
+                                                       if (NoisyOverride)
+                                                       if ((!channel->HasUser(source)) || (mode < STATUS_HOP))
+                                                               OverDevoices++;
+                                                       return ACR_ALLOW;
+                                               }
+                                               else
+                                               {
+                                                       return ACR_DEFAULT;
+                                               }
+                                       break;
+                                       case AC_HALFOP:
+                                               if (CanOverride(source,"MODEHALFOP"))
+                                               {
+                                                       if (NoisyOverride)
+                                                       if ((!channel->HasUser(source)) || (mode < STATUS_OP))
+                                                               OverHalfops++;
+                                                       return ACR_ALLOW;
+                                               }
+                                               else
+                                               {
+                                                       return ACR_DEFAULT;
+                                               }
+                                       break;
+                                       case AC_DEHALFOP:
+                                               if (CanOverride(source,"MODEDEHALFOP"))
+                                               {
+                                                       if (NoisyOverride)
+                                                       if ((!channel->HasUser(source)) || (mode < STATUS_OP))
+                                                               OverDehalfops++;
+                                                       return ACR_ALLOW;
+                                               }
+                                               else
+                                               {
+                                                       return ACR_DEFAULT;
+                                               }
+                                       break;
+                               }
+                       
+                               if (CanOverride(source,"OTHERMODE"))
+                               {
+                                       if (NoisyOverride)
+                                       if ((!channel->HasUser(source)) || (mode < STATUS_OP))
+                                       {
+                                               OverriddenMode = true;
+                                               OverOps = OverDeops = OverVoices = OverDevoices = OverHalfops = OverDehalfops = 0;
+                                       }
+                                       return ACR_ALLOW;
+                               }
+                               else
+                               {
+                                       return ACR_DEFAULT;
+                               }
+                       }
+               }
+
+               return ACR_DEFAULT;
+       }
+       
+       virtual int OnUserPreJoin(userrec* user, chanrec* chan, const char* cname, std::string &privs)
+       {
+               if (IS_OPER(user))
+               {
+                       if (chan)
+                       {
+                               if ((chan->modes[CM_INVITEONLY]) && (CanOverride(user,"INVITE")))
+                               {
+                                       irc::string x = chan->name;
+                                       if (!user->IsInvited(x))
+                                       {
+                                               /* XXX - Ugly cast for a parameter that isn't used? :< - Om */
+                                               if (NoisyOverride)
+                                                       chan->WriteChannelWithServ(ServerInstance->Config->ServerName, "NOTICE %s :%s used oper-override to bypass invite-only", cname, user->nick);
+                                               ServerInstance->SNO->WriteToSnoMask('O',std::string(user->nick)+" used operoverride to bypass +i on "+std::string(cname));
+                                       }
+                                       return -1;
+                               }
+                               
+                               if ((*chan->key) && (CanOverride(user,"KEY")))
+                               {
+                                       if (NoisyOverride)
+                                               chan->WriteChannelWithServ(ServerInstance->Config->ServerName, "NOTICE %s :%s used oper-override to bypass the channel key", cname, user->nick);
+                                       ServerInstance->SNO->WriteToSnoMask('O',std::string(user->nick)+" used operoverride to bypass +k on "+std::string(cname));
+                                       return -1;
+                               }
+                                       
+                               if ((chan->limit > 0) && (chan->GetUserCounter() >=  chan->limit) && (CanOverride(user,"LIMIT")))
+                               {
+                                       if (NoisyOverride)
+                                               chan->WriteChannelWithServ(ServerInstance->Config->ServerName, "NOTICE %s :%s used oper-override to bypass the channel limit", cname, user->nick);
+                                       ServerInstance->SNO->WriteToSnoMask('O',std::string(user->nick)+" used operoverride to bypass +l on "+std::string(cname));
+                                       return -1;
+                               }
+
+                               if (CanOverride(user,"BANWALK"))
+                               {
+                                       if (chan->IsBanned(user))
+                                       {
+                                               if (NoisyOverride)
+                                                       chan->WriteChannelWithServ(ServerInstance->Config->ServerName, "NOTICE %s :%s used oper-override to bypass channel ban", cname, user->nick);
+                                               ServerInstance->SNO->WriteToSnoMask('O',"%s used oper-override to bypass channel ban on %s", user->nick, cname);
+                                       }
+                                       return -1;
+                               }
+                       }
+               }
+               return 0;
+       }
+       
+       virtual ~ModuleOverride()
+       {
+               ServerInstance->SNO->DisableSnomask('O');
+       }
+       
+       virtual Version GetVersion()
+       {
+               return Version(1,1,0,1,VF_VENDOR,API_VERSION);
+       }
+};
+
+MODULE_INIT(ModuleOverride)
index 8ab9aab4eda4a3f3681477470888bf27b8a01064..2ad7831ce90f0f5aba9e3a1b6d32c9b362b92f39 100644 (file)
@@ -1 +1,138 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r\rstatic FileReader *quotes = NULL;\r\rstd::string q_file;\rstd::string prefix;\rstd::string suffix;\r\r/* $ModDesc: Provides random Quotes on Connect. */\r\r/** Handle /RANDQUOTE\r */\rclass cmd_randquote : public command_t\r{\r public:\r      cmd_randquote (InspIRCd* Instance) : command_t(Instance,"RANDQUOTE", 0, 0)\r     {\r              this->source = "m_randquote.so";\r       }\r\r     CmdResult Handle (const char** parameters, int pcntl, userrec *user)\r   {\r              std::string str;\r               int fsize;\r\r            if (q_file.empty() || quotes->Exists())\r                {\r                      fsize = quotes->FileSize();\r                    str = quotes->GetLine(rand() % fsize);\r                 user->WriteServ("NOTICE %s :%s%s%s",user->nick,prefix.c_str(),str.c_str(),suffix.c_str());\r             }\r              else\r           {\r                      user->WriteServ("NOTICE %s :Your administrator specified an invalid quotes file, please bug them about this.", user->nick);\r                    return CMD_FAILURE;\r            }\r\r             return CMD_LOCALONLY;\r  }\r};\r\r/** Thrown by m_randquote\r */\rclass RandquoteException : public ModuleException\r{\r private:\r      const std::string err;\r public:\r        RandquoteException(const std::string &message) : err(message) { }\r\r     ~RandquoteException() throw () { }\r\r    virtual const char* GetReason()\r        {\r              return err.c_str();\r    }\r};\r\rclass ModuleRandQuote : public Module\r{\r private:\r        cmd_randquote* mycommand;\r      ConfigReader *conf;\r public:\r   ModuleRandQuote(InspIRCd* Me)\r          : Module(Me)\r   {\r              \r               conf = new ConfigReader(ServerInstance);\r               // Sort the Randomizer thingie..\r               srand(time(NULL));\r\r            q_file = conf->ReadValue("randquote","file",0);\r                prefix = conf->ReadValue("randquote","prefix",0);\r              suffix = conf->ReadValue("randquote","suffix",0);\r\r             mycommand = NULL;\r\r             if (q_file.empty())\r            {\r                      RandquoteException e("m_randquote: Quotefile not specified - Please check your config.");\r                      throw(e);\r              }\r\r             quotes = new FileReader(ServerInstance, q_file);\r               if(!quotes->Exists())\r          {\r                      RandquoteException e("m_randquote: QuoteFile not Found!! Please check your config - module will not function.");\r                       throw(e);\r              }\r              else\r           {\r                      /* Hidden Command -- Mode clients assume /quote sends raw data to an IRCd >:D */\r                       mycommand = new cmd_randquote(ServerInstance);\r                 ServerInstance->AddCommand(mycommand);\r         }\r      }\r\r     void Implements(char* List)\r    {\r              List[I_OnUserConnect] = 1;\r     }\r      \r       virtual ~ModuleRandQuote()\r     {\r              DELETE(conf);\r          DELETE(quotes);\r        }\r      \r       virtual Version GetVersion()\r   {\r              return Version(1,1,0,1,VF_VENDOR,API_VERSION);\r }\r      \r       virtual void OnUserConnect(userrec* user)\r      {\r              if (mycommand)\r                 mycommand->Handle(NULL, 0, user);\r      }\r};\r\rMODULE_INIT(ModuleRandQuote)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+
+static FileReader *quotes = NULL;
+
+std::string q_file;
+std::string prefix;
+std::string suffix;
+
+/* $ModDesc: Provides random Quotes on Connect. */
+
+/** Handle /RANDQUOTE
+ */
+class cmd_randquote : public command_t
+{
+ public:
+       cmd_randquote (InspIRCd* Instance) : command_t(Instance,"RANDQUOTE", 0, 0)
+       {
+               this->source = "m_randquote.so";
+       }
+
+       CmdResult Handle (const char** parameters, int pcntl, userrec *user)
+       {
+               std::string str;
+               int fsize;
+
+               if (q_file.empty() || quotes->Exists())
+               {
+                       fsize = quotes->FileSize();
+                       str = quotes->GetLine(rand() % fsize);
+                       user->WriteServ("NOTICE %s :%s%s%s",user->nick,prefix.c_str(),str.c_str(),suffix.c_str());
+               }
+               else
+               {
+                       user->WriteServ("NOTICE %s :Your administrator specified an invalid quotes file, please bug them about this.", user->nick);
+                       return CMD_FAILURE;
+               }
+
+               return CMD_LOCALONLY;
+       }
+};
+
+/** Thrown by m_randquote
+ */
+class RandquoteException : public ModuleException
+{
+ private:
+       const std::string err;
+ public:
+       RandquoteException(const std::string &message) : err(message) { }
+
+       ~RandquoteException() throw () { }
+
+       virtual const char* GetReason()
+       {
+               return err.c_str();
+       }
+};
+
+class ModuleRandQuote : public Module
+{
+ private:
+       cmd_randquote* mycommand;
+       ConfigReader *conf;
+ public:
+       ModuleRandQuote(InspIRCd* Me)
+               : Module(Me)
+       {
+               
+               conf = new ConfigReader(ServerInstance);
+               // Sort the Randomizer thingie..
+               srand(time(NULL));
+
+               q_file = conf->ReadValue("randquote","file",0);
+               prefix = conf->ReadValue("randquote","prefix",0);
+               suffix = conf->ReadValue("randquote","suffix",0);
+
+               mycommand = NULL;
+
+               if (q_file.empty())
+               {
+                       RandquoteException e("m_randquote: Quotefile not specified - Please check your config.");
+                       throw(e);
+               }
+
+               quotes = new FileReader(ServerInstance, q_file);
+               if(!quotes->Exists())
+               {
+                       RandquoteException e("m_randquote: QuoteFile not Found!! Please check your config - module will not function.");
+                       throw(e);
+               }
+               else
+               {
+                       /* Hidden Command -- Mode clients assume /quote sends raw data to an IRCd >:D */
+                       mycommand = new cmd_randquote(ServerInstance);
+                       ServerInstance->AddCommand(mycommand);
+               }
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnUserConnect] = 1;
+       }
+       
+       virtual ~ModuleRandQuote()
+       {
+               DELETE(conf);
+               DELETE(quotes);
+       }
+       
+       virtual Version GetVersion()
+       {
+               return Version(1,1,0,1,VF_VENDOR,API_VERSION);
+       }
+       
+       virtual void OnUserConnect(userrec* user)
+       {
+               if (mycommand)
+                       mycommand->Handle(NULL, 0, user);
+       }
+};
+
+MODULE_INIT(ModuleRandQuote)
index ee2d3f0049c98b4f006dcc24fbf8fb1018813203..a746644c20d5b5d82952cad55865582814faef12 100644 (file)
@@ -1 +1,160 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r\r/* $ModDesc: Provides channel mode +L (limit redirection) */\r\r/** Handle channel mode +L\r */\rclass Redirect : public ModeHandler\r{\r public:\r  Redirect(InspIRCd* Instance) : ModeHandler(Instance, 'L', 1, 0, false, MODETYPE_CHANNEL, false) { }\r\r   ModePair ModeSet(userrec* source, userrec* dest, chanrec* channel, const std::string &parameter)\r       {\r              if (channel->IsModeSet('L'))\r                   return std::make_pair(true, channel->GetModeParameter('L'));\r           else\r                   return std::make_pair(false, parameter);\r       }\r\r     bool CheckTimeStamp(time_t theirs, time_t ours, const std::string &their_param, const std::string &our_param, chanrec* channel)\r        {\r              /* When TS is equal, the alphabetically later one wins */\r              return (their_param < our_param);\r      }\r      \r       ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)\r {\r              if (adding)\r            {\r                      chanrec* c = NULL;\r\r                    if (!ServerInstance->IsChannel(parameter.c_str()))\r                     {\r                              source->WriteServ("403 %s %s :Invalid channel name",source->nick, parameter.c_str());\r                          parameter.clear();\r                             return MODEACTION_DENY;\r                        }\r\r                     c = ServerInstance->FindChan(parameter);\r                       if (c)\r                 {\r                              /* Fix by brain: Dont let a channel be linked to *itself* either */\r                            if (IS_LOCAL(source))\r                          {\r                                      if ((c == channel) || (c->IsModeSet('L')))\r                                     {\r                                              source->WriteServ("690 %s :Circular or chained +L to %s not allowed (Channel already has +L). Pack of wild dogs has been unleashed.",source->nick,parameter.c_str());\r                                          parameter.clear();\r                                             return MODEACTION_DENY;\r                                        }\r                                      else\r                                   {\r                                              for (chan_hash::const_iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++)\r                                               {\r                                                      if ((i->second != channel) && (i->second->IsModeSet('L')) && (irc::string(i->second->GetModeParameter('L').c_str()) == irc::string(channel->name)))\r                                                    {\r                                                              source->WriteServ("690 %s :Circular or chained +L to %s not allowed (Already forwarded here from %s). Angry monkeys dispatched.",source->nick,parameter.c_str(),i->second->name);\r                                                              return MODEACTION_DENY;\r                                                        }\r                                              }\r                                      }\r                              }\r                      }\r\r                     channel->SetMode('L', true);\r                   channel->SetModeParam('L', parameter.c_str(), true);\r                   return MODEACTION_ALLOW;\r               }\r              else\r           {\r                      if (channel->IsModeSet('L'))\r                   {\r                              channel->SetMode('L', false);\r                          return MODEACTION_ALLOW;\r                       }\r              }\r\r             return MODEACTION_DENY;\r                \r       }\r};\r\rclass ModuleRedirect : public Module\r{\r   \r       Redirect* re;\r  \r public:\r \r    ModuleRedirect(InspIRCd* Me)\r           : Module(Me)\r   {\r              \r               re = new Redirect(ServerInstance);\r             if (!ServerInstance->AddMode(re, 'L'))\r                 throw ModuleException("Could not add new modes!");\r     }\r      \r       void Implements(char* List)\r    {\r              List[I_OnUserPreJoin] = 1;\r     }\r\r     virtual int OnUserPreJoin(userrec* user, chanrec* chan, const char* cname, std::string &privs)\r {\r              if (chan)\r              {\r                      if (chan->IsModeSet('L') && chan->limit)\r                       {\r                              if (chan->GetUserCounter() >= chan->limit)\r                             {\r                                      std::string channel = chan->GetModeParameter('L');\r\r                                    /* sometimes broken ulines can make circular or chained +L, avoid this */\r                                      chanrec* destchan = NULL;\r                                      destchan = ServerInstance->FindChan(channel);\r                                  if (destchan && destchan->IsModeSet('L'))\r                                      {\r                                              user->WriteServ("470 %s :%s is full, but has a circular redirect (+L), not following redirection to %s", user->nick, cname, channel.c_str());\r                                          return 1;\r                                      }\r\r                                     user->WriteServ("470 %s :%s has become full, so you are automatically being transferred to the linked channel %s", user->nick, cname, channel.c_str());\r                                        chanrec::JoinUser(ServerInstance, user, channel.c_str(), false, "", ServerInstance->Time(true));\r                                       return 1;\r                              }\r                      }\r              }\r              return 0;\r      }\r\r     virtual ~ModuleRedirect()\r      {\r              ServerInstance->Modes->DelMode(re);\r            DELETE(re);\r    }\r      \r       virtual Version GetVersion()\r   {\r              return Version(1, 1, 0, 0, VF_COMMON | VF_VENDOR, API_VERSION);\r        }\r};\r\rMODULE_INIT(ModuleRedirect)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+
+/* $ModDesc: Provides channel mode +L (limit redirection) */
+
+/** Handle channel mode +L
+ */
+class Redirect : public ModeHandler
+{
+ public:
+       Redirect(InspIRCd* Instance) : ModeHandler(Instance, 'L', 1, 0, false, MODETYPE_CHANNEL, false) { }
+
+       ModePair ModeSet(userrec* source, userrec* dest, chanrec* channel, const std::string &parameter)
+       {
+               if (channel->IsModeSet('L'))
+                       return std::make_pair(true, channel->GetModeParameter('L'));
+               else
+                       return std::make_pair(false, parameter);
+       }
+
+       bool CheckTimeStamp(time_t theirs, time_t ours, const std::string &their_param, const std::string &our_param, chanrec* channel)
+       {
+               /* When TS is equal, the alphabetically later one wins */
+               return (their_param < our_param);
+       }
+       
+       ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)
+       {
+               if (adding)
+               {
+                       chanrec* c = NULL;
+
+                       if (!ServerInstance->IsChannel(parameter.c_str()))
+                       {
+                               source->WriteServ("403 %s %s :Invalid channel name",source->nick, parameter.c_str());
+                               parameter.clear();
+                               return MODEACTION_DENY;
+                       }
+
+                       c = ServerInstance->FindChan(parameter);
+                       if (c)
+                       {
+                               /* Fix by brain: Dont let a channel be linked to *itself* either */
+                               if (IS_LOCAL(source))
+                               {
+                                       if ((c == channel) || (c->IsModeSet('L')))
+                                       {
+                                               source->WriteServ("690 %s :Circular or chained +L to %s not allowed (Channel already has +L). Pack of wild dogs has been unleashed.",source->nick,parameter.c_str());
+                                               parameter.clear();
+                                               return MODEACTION_DENY;
+                                       }
+                                       else
+                                       {
+                                               for (chan_hash::const_iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++)
+                                               {
+                                                       if ((i->second != channel) && (i->second->IsModeSet('L')) && (irc::string(i->second->GetModeParameter('L').c_str()) == irc::string(channel->name)))
+                                                       {
+                                                               source->WriteServ("690 %s :Circular or chained +L to %s not allowed (Already forwarded here from %s). Angry monkeys dispatched.",source->nick,parameter.c_str(),i->second->name);
+                                                               return MODEACTION_DENY;
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+
+                       channel->SetMode('L', true);
+                       channel->SetModeParam('L', parameter.c_str(), true);
+                       return MODEACTION_ALLOW;
+               }
+               else
+               {
+                       if (channel->IsModeSet('L'))
+                       {
+                               channel->SetMode('L', false);
+                               return MODEACTION_ALLOW;
+                       }
+               }
+
+               return MODEACTION_DENY;
+               
+       }
+};
+
+class ModuleRedirect : public Module
+{
+       
+       Redirect* re;
+       
+ public:
+       ModuleRedirect(InspIRCd* Me)
+               : Module(Me)
+       {
+               
+               re = new Redirect(ServerInstance);
+               if (!ServerInstance->AddMode(re, 'L'))
+                       throw ModuleException("Could not add new modes!");
+       }
+       
+       void Implements(char* List)
+       {
+               List[I_OnUserPreJoin] = 1;
+       }
+
+       virtual int OnUserPreJoin(userrec* user, chanrec* chan, const char* cname, std::string &privs)
+       {
+               if (chan)
+               {
+                       if (chan->IsModeSet('L') && chan->limit)
+                       {
+                               if (chan->GetUserCounter() >= chan->limit)
+                               {
+                                       std::string channel = chan->GetModeParameter('L');
+
+                                       /* sometimes broken ulines can make circular or chained +L, avoid this */
+                                       chanrec* destchan = NULL;
+                                       destchan = ServerInstance->FindChan(channel);
+                                       if (destchan && destchan->IsModeSet('L'))
+                                       {
+                                               user->WriteServ("470 %s :%s is full, but has a circular redirect (+L), not following redirection to %s", user->nick, cname, channel.c_str());
+                                               return 1;
+                                       }
+
+                                       user->WriteServ("470 %s :%s has become full, so you are automatically being transferred to the linked channel %s", user->nick, cname, channel.c_str());
+                                       chanrec::JoinUser(ServerInstance, user, channel.c_str(), false, "", ServerInstance->Time(true));
+                                       return 1;
+                               }
+                       }
+               }
+               return 0;
+       }
+
+       virtual ~ModuleRedirect()
+       {
+               ServerInstance->Modes->DelMode(re);
+               DELETE(re);
+       }
+       
+       virtual Version GetVersion()
+       {
+               return Version(1, 1, 0, 0, VF_COMMON | VF_VENDOR, API_VERSION);
+       }
+};
+
+MODULE_INIT(ModuleRedirect)
index 0d911a0bf8729db1f74490eb4137320840ac24ec..2174c860c28a14d4be42b3eb05741ef2e9f44cbf 100644 (file)
@@ -1 +1,61 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r\r/* $ModDesc: Prevents users who's nicks are not registered from creating new channels */\r\rclass ModuleRegOnlyCreate : public Module\r{\r public:\r       ModuleRegOnlyCreate(InspIRCd* Me)\r              : Module(Me)\r   {\r      }\r\r     void Implements(char* List)\r    {\r              List[I_OnUserPreJoin] = 1;\r     }\r\r     virtual int OnUserPreJoin(userrec* user, chanrec* chan, const char* cname, std::string &privs)\r {\r              if (chan)\r                      return 0;\r\r             if (IS_OPER(user))\r                     return 0;\r\r             if ((!user->IsModeSet('r')) && (!user->GetExt("accountname")))\r         {\r                      user->WriteServ("482 %s %s :You must have a registered nickname to create a new channel", user->nick, cname);\r                  return 1;\r              }\r\r             return 0;\r      }\r      \r       virtual ~ModuleRegOnlyCreate()\r {\r      }\r      \r       virtual Version GetVersion()\r   {\r              return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION);\r    }\r};\r\rMODULE_INIT(ModuleRegOnlyCreate)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+
+/* $ModDesc: Prevents users who's nicks are not registered from creating new channels */
+
+class ModuleRegOnlyCreate : public Module
+{
+ public:
+       ModuleRegOnlyCreate(InspIRCd* Me)
+               : Module(Me)
+       {
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnUserPreJoin] = 1;
+       }
+
+       virtual int OnUserPreJoin(userrec* user, chanrec* chan, const char* cname, std::string &privs)
+       {
+               if (chan)
+                       return 0;
+
+               if (IS_OPER(user))
+                       return 0;
+
+               if ((!user->IsModeSet('r')) && (!user->GetExt("accountname")))
+               {
+                       user->WriteServ("482 %s %s :You must have a registered nickname to create a new channel", user->nick, cname);
+                       return 1;
+               }
+
+               return 0;
+       }
+       
+       virtual ~ModuleRegOnlyCreate()
+       {
+       }
+       
+       virtual Version GetVersion()
+       {
+               return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION);
+       }
+};
+
+MODULE_INIT(ModuleRegOnlyCreate)
index 6d9be00adbd464e4cdcfefe6e6aa172fdf4d4a60..d28087ba8d6a0d965163857769ede766b987d3f4 100644 (file)
@@ -1 +1,288 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include <sstream>\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r#include "configreader.h"\r\r/* $ModDesc: Provides a /remove command, this is mostly an alternative to /kick, except makes users appear to have parted the channel */\r\r/*     \r * This module supports the use of the +q and +a usermodes, but should work without them too.\r * Usage of the command is restricted to +hoaq, and you cannot remove a user with a "higher" level than yourself.\r * eg: +h can remove +hv and users with no modes. +a can remove +aohv and users with no modes.\r*/\r\r/** Base class for /FPART and /REMOVE\r */\rclass RemoveBase\r{\r private: \r    bool& supportnokicks;\r  InspIRCd* ServerInstance;\r \r protected:\r        RemoveBase(InspIRCd* Instance, bool& snk) : supportnokicks(snk), ServerInstance(Instance)\r      {\r      }               \r \r     enum ModeLevel { PEON = 0, HALFOP = 1, OP = 2, ADMIN = 3, OWNER = 4, ULINE = 5 };        \r \r    /* This little function just converts a chanmode character (U ~ & @ & +) into an integer (5 4 3 2 1 0) */\r      /* XXX - We should probably use the new mode prefix rank stuff\r  * for this instead now -- Brain */\r    ModeLevel chartolevel(const std::string &privs)\r        {\r              if(privs.empty())\r              {\r                      return PEON;\r           }\r      \r               switch (privs[0])\r              {\r                      case 'U':\r                              /* Ulined */\r                           return ULINE;\r                  case '~':\r                              /* Owner */\r                            return OWNER;\r                  case '&':\r                              /* Admin */\r                            return ADMIN;\r                  case '@':\r                              /* Operator */\r                         return OP;\r                     case '%':\r                              /* Halfop */\r                           return HALFOP;\r                 default:\r                               /* Peon */\r                             return PEON;\r           }\r      }\r      \r       CmdResult Handle (const char** parameters, int pcnt, userrec *user, bool neworder)\r     {\r              const char* channame;\r          const char* username;\r          userrec* target;\r               chanrec* channel;\r              ModeLevel tlevel;\r              ModeLevel ulevel;\r              std::string reason;\r            std::string protectkey;\r                std::string founderkey;\r                bool hasnokicks;\r               \r               /* Set these to the parameters needed, the new version of this module switches it's parameters around\r           * supplying a new command with the new order while keeping the old /remove with the older order.\r               * /remove <nick> <channel> [reason ...]\r                * /fpart <channel> <nick> [reason ...]\r                 */\r            channame = parameters[ neworder ? 0 : 1];\r              username = parameters[ neworder ? 1 : 0];\r              \r               /* Look up the user we're meant to be removing from the channel */\r             target = ServerInstance->FindNick(username);\r           \r               /* And the channel we're meant to be removing them from */\r             channel = ServerInstance->FindChan(channame);\r\r         /* Fix by brain - someone needs to learn to validate their input! */\r           if (!target || !channel)\r               {\r                      user->WriteServ("401 %s %s :No such nick/channel", user->nick, !target ? username : channame);\r                 return CMD_FAILURE;\r            }\r\r             if (!channel->HasUser(target))\r         {\r                      user->WriteServ( "NOTICE %s :*** The user %s is not on channel %s", user->nick, target->nick, channel->name);\r                  return CMD_FAILURE;\r            }       \r               \r               /* This is adding support for the +q and +a channel modes, basically if they are enabled, and the remover has them set.\r                 * Then we change the @|%|+ to & if they are +a, or ~ if they are +q */\r                protectkey = "cm_protect_" + std::string(channel->name);\r               founderkey = "cm_founder_" + std::string(channel->name);\r               \r               if (ServerInstance->ULine(user->server) || ServerInstance->ULine(user->nick))\r          {\r                      ulevel = chartolevel("U");\r             }\r              if (user->GetExt(founderkey))\r          {\r                      ulevel = chartolevel("~");\r             }\r              else if (user->GetExt(protectkey))\r             {\r                      ulevel = chartolevel("&");\r             }\r              else\r           {\r                      ulevel = chartolevel(channel->GetPrefixChar(user));\r            }\r                      \r               /* Now it's the same idea, except for the target. If they're ulined make sure they get a higher level than the sender can */\r           if (ServerInstance->ULine(target->server) || ServerInstance->ULine(target->nick))\r              {\r                      tlevel = chartolevel("U");\r             }\r              else if (target->GetExt(founderkey))\r           {\r                      tlevel = chartolevel("~");\r             }\r              else if (target->GetExt(protectkey))\r           {\r                      tlevel = chartolevel("&");\r             }\r              else\r           {\r                      tlevel = chartolevel(channel->GetPrefixChar(target));\r          }\r              \r               hasnokicks = (ServerInstance->FindModule("m_nokicks.so") && channel->IsModeSet('Q'));\r          \r               /* We support the +Q channel mode via. the m_nokicks module, if the module is loaded and the mode is set then disallow the /remove */\r          if ((!IS_LOCAL(user)) || (!supportnokicks || !hasnokicks || (ulevel == ULINE)))\r                {\r                      /* We'll let everyone remove their level and below, eg:\r                         * ops can remove ops, halfops, voices, and those with no mode (no moders actually are set to 1)\r                        * a ulined target will get a higher level than it's possible for a /remover to get..so they're safe.\r                   * Nobody may remove a founder.\r                         */\r                    if ((!IS_LOCAL(user)) || ((ulevel > PEON) && (ulevel >= tlevel) && (tlevel != OWNER)))\r                 {\r                              // no you can't just go from a std::ostringstream to a std::string, Om. -nenolod\r                               // but you can do this, nenolod -brain\r\r                                std::string reasonparam("No reason given");\r                            \r                               /* If a reason is given, use it */\r                             if(pcnt > 2)\r                           {\r                                      /* Join params 2 ... pcnt - 1 (inclusive) into one */\r                                  irc::stringjoiner reason_join(" ", parameters, 2, pcnt - 1);\r                                   reasonparam = reason_join.GetJoined();\r                         }\r\r                             /* Build up the part reason string. */\r                         reason = std::string("Removed by ") + user->nick + ": " + reasonparam;\r\r                                channel->WriteChannelWithServ(ServerInstance->Config->ServerName, "NOTICE %s :%s removed %s from the channel", channel->name, user->nick, target->nick);\r                               target->WriteServ("NOTICE %s :*** %s removed you from %s with the message: %s", target->nick, user->nick, channel->name, reasonparam.c_str());\r\r                                if (!channel->PartUser(target, reason.c_str()))\r                                        delete channel;\r                        }\r                      else\r                   {\r                              user->WriteServ( "NOTICE %s :*** You do not have access to /remove %s from %s", user->nick, target->nick, channel->name);\r                              return CMD_FAILURE;\r                    }\r              }\r              else\r           {\r                      /* m_nokicks.so was loaded and +Q was set, block! */\r                   user->WriteServ( "484 %s %s :Can't remove user %s from channel (+Q set)", user->nick, channel->name, target->nick);\r                    return CMD_FAILURE;\r            }\r\r             /* route me */\r         return CMD_SUCCESS;\r    }\r};\r\r/** Handle /REMOVE\r */\rclass cmd_remove : public command_t, public RemoveBase\r{\r public:\r cmd_remove(InspIRCd* Instance, bool& snk) : command_t(Instance, "REMOVE", 0, 2), RemoveBase(Instance, snk)\r     {\r              this->source = "m_remove.so";\r          syntax = "<nick> <channel> [<reason>]";\r        }\r      \r       CmdResult Handle (const char** parameters, int pcnt, userrec *user)\r    {\r              return RemoveBase::Handle(parameters, pcnt, user, false);\r      }\r};\r\r/** Handle /FPART\r */\rclass cmd_fpart : public command_t, public RemoveBase\r{\r public:\r   cmd_fpart(InspIRCd* Instance, bool& snk) : command_t(Instance, "FPART", 0, 2), RemoveBase(Instance, snk)\r       {\r              this->source = "m_remove.so";\r          syntax = "<channel> <nick> [<reason>]";\r        }\r\r     CmdResult Handle (const char** parameters, int pcnt, userrec *user)\r    {\r              return RemoveBase::Handle(parameters, pcnt, user, true);\r       }\r};\r\rclass ModuleRemove : public Module\r{\r     cmd_remove* mycommand;\r cmd_fpart* mycommand2;\r bool supportnokicks;\r   \r       \r public:\r      ModuleRemove(InspIRCd* Me)\r     : Module(Me)\r   {\r              mycommand = new cmd_remove(ServerInstance, supportnokicks);\r            mycommand2 = new cmd_fpart(ServerInstance, supportnokicks);\r            ServerInstance->AddCommand(mycommand);\r         ServerInstance->AddCommand(mycommand2);\r                OnRehash(NULL,"");\r     }\r\r     void Implements(char* List)\r    {\r              List[I_On005Numeric] = List[I_OnRehash] = 1;\r   }\r\r     virtual void On005Numeric(std::string &output)\r {\r              output.append(" REMOVE");\r      }\r      \r       virtual void OnRehash(userrec* user, const std::string&)\r       {\r              ConfigReader conf(ServerInstance);\r             supportnokicks = conf.ReadFlag("remove", "supportnokicks", 0);\r }\r      \r       virtual ~ModuleRemove()\r        {\r      }\r      \r       virtual Version GetVersion()\r   {\r              return Version(1,1,1,0,VF_VENDOR,API_VERSION);\r }\r      \r};\r\rMODULE_INIT(ModuleRemove)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include <sstream>
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+#include "configreader.h"
+
+/* $ModDesc: Provides a /remove command, this is mostly an alternative to /kick, except makes users appear to have parted the channel */
+
+/*     
+ * This module supports the use of the +q and +a usermodes, but should work without them too.
+ * Usage of the command is restricted to +hoaq, and you cannot remove a user with a "higher" level than yourself.
+ * eg: +h can remove +hv and users with no modes. +a can remove +aohv and users with no modes.
+*/
+
+/** Base class for /FPART and /REMOVE
+ */
+class RemoveBase
+{
+ private: 
+       bool& supportnokicks;
+       InspIRCd* ServerInstance;
+ protected:
+       RemoveBase(InspIRCd* Instance, bool& snk) : supportnokicks(snk), ServerInstance(Instance)
+       {
+       }               
+       enum ModeLevel { PEON = 0, HALFOP = 1, OP = 2, ADMIN = 3, OWNER = 4, ULINE = 5 };        
+       /* This little function just converts a chanmode character (U ~ & @ & +) into an integer (5 4 3 2 1 0) */
+       /* XXX - We should probably use the new mode prefix rank stuff
+        * for this instead now -- Brain */
+       ModeLevel chartolevel(const std::string &privs)
+       {
+               if(privs.empty())
+               {
+                       return PEON;
+               }
+       
+               switch (privs[0])
+               {
+                       case 'U':
+                               /* Ulined */
+                               return ULINE;
+                       case '~':
+                               /* Owner */
+                               return OWNER;
+                       case '&':
+                               /* Admin */
+                               return ADMIN;
+                       case '@':
+                               /* Operator */
+                               return OP;
+                       case '%':
+                               /* Halfop */
+                               return HALFOP;
+                       default:
+                               /* Peon */
+                               return PEON;
+               }
+       }
+       
+       CmdResult Handle (const char** parameters, int pcnt, userrec *user, bool neworder)
+       {
+               const char* channame;
+               const char* username;
+               userrec* target;
+               chanrec* channel;
+               ModeLevel tlevel;
+               ModeLevel ulevel;
+               std::string reason;
+               std::string protectkey;
+               std::string founderkey;
+               bool hasnokicks;
+               
+               /* Set these to the parameters needed, the new version of this module switches it's parameters around
+                * supplying a new command with the new order while keeping the old /remove with the older order.
+                * /remove <nick> <channel> [reason ...]
+                * /fpart <channel> <nick> [reason ...]
+                */
+               channame = parameters[ neworder ? 0 : 1];
+               username = parameters[ neworder ? 1 : 0];
+               
+               /* Look up the user we're meant to be removing from the channel */
+               target = ServerInstance->FindNick(username);
+               
+               /* And the channel we're meant to be removing them from */
+               channel = ServerInstance->FindChan(channame);
+
+               /* Fix by brain - someone needs to learn to validate their input! */
+               if (!target || !channel)
+               {
+                       user->WriteServ("401 %s %s :No such nick/channel", user->nick, !target ? username : channame);
+                       return CMD_FAILURE;
+               }
+
+               if (!channel->HasUser(target))
+               {
+                       user->WriteServ( "NOTICE %s :*** The user %s is not on channel %s", user->nick, target->nick, channel->name);
+                       return CMD_FAILURE;
+               }       
+               
+               /* This is adding support for the +q and +a channel modes, basically if they are enabled, and the remover has them set.
+                * Then we change the @|%|+ to & if they are +a, or ~ if they are +q */
+               protectkey = "cm_protect_" + std::string(channel->name);
+               founderkey = "cm_founder_" + std::string(channel->name);
+               
+               if (ServerInstance->ULine(user->server) || ServerInstance->ULine(user->nick))
+               {
+                       ulevel = chartolevel("U");
+               }
+               if (user->GetExt(founderkey))
+               {
+                       ulevel = chartolevel("~");
+               }
+               else if (user->GetExt(protectkey))
+               {
+                       ulevel = chartolevel("&");
+               }
+               else
+               {
+                       ulevel = chartolevel(channel->GetPrefixChar(user));
+               }
+                       
+               /* Now it's the same idea, except for the target. If they're ulined make sure they get a higher level than the sender can */
+               if (ServerInstance->ULine(target->server) || ServerInstance->ULine(target->nick))
+               {
+                       tlevel = chartolevel("U");
+               }
+               else if (target->GetExt(founderkey))
+               {
+                       tlevel = chartolevel("~");
+               }
+               else if (target->GetExt(protectkey))
+               {
+                       tlevel = chartolevel("&");
+               }
+               else
+               {
+                       tlevel = chartolevel(channel->GetPrefixChar(target));
+               }
+               
+               hasnokicks = (ServerInstance->FindModule("m_nokicks.so") && channel->IsModeSet('Q'));
+               
+               /* We support the +Q channel mode via. the m_nokicks module, if the module is loaded and the mode is set then disallow the /remove */
+               if ((!IS_LOCAL(user)) || (!supportnokicks || !hasnokicks || (ulevel == ULINE)))
+               {
+                       /* We'll let everyone remove their level and below, eg:
+                        * ops can remove ops, halfops, voices, and those with no mode (no moders actually are set to 1)
+                        * a ulined target will get a higher level than it's possible for a /remover to get..so they're safe.
+                        * Nobody may remove a founder.
+                        */
+                       if ((!IS_LOCAL(user)) || ((ulevel > PEON) && (ulevel >= tlevel) && (tlevel != OWNER)))
+                       {
+                               // no you can't just go from a std::ostringstream to a std::string, Om. -nenolod
+                               // but you can do this, nenolod -brain
+
+                               std::string reasonparam("No reason given");
+                               
+                               /* If a reason is given, use it */
+                               if(pcnt > 2)
+                               {
+                                       /* Join params 2 ... pcnt - 1 (inclusive) into one */
+                                       irc::stringjoiner reason_join(" ", parameters, 2, pcnt - 1);
+                                       reasonparam = reason_join.GetJoined();
+                               }
+
+                               /* Build up the part reason string. */
+                               reason = std::string("Removed by ") + user->nick + ": " + reasonparam;
+
+                               channel->WriteChannelWithServ(ServerInstance->Config->ServerName, "NOTICE %s :%s removed %s from the channel", channel->name, user->nick, target->nick);
+                               target->WriteServ("NOTICE %s :*** %s removed you from %s with the message: %s", target->nick, user->nick, channel->name, reasonparam.c_str());
+
+                               if (!channel->PartUser(target, reason.c_str()))
+                                       delete channel;
+                       }
+                       else
+                       {
+                               user->WriteServ( "NOTICE %s :*** You do not have access to /remove %s from %s", user->nick, target->nick, channel->name);
+                               return CMD_FAILURE;
+                       }
+               }
+               else
+               {
+                       /* m_nokicks.so was loaded and +Q was set, block! */
+                       user->WriteServ( "484 %s %s :Can't remove user %s from channel (+Q set)", user->nick, channel->name, target->nick);
+                       return CMD_FAILURE;
+               }
+
+               /* route me */
+               return CMD_SUCCESS;
+       }
+};
+
+/** Handle /REMOVE
+ */
+class cmd_remove : public command_t, public RemoveBase
+{
+ public:
+       cmd_remove(InspIRCd* Instance, bool& snk) : command_t(Instance, "REMOVE", 0, 2), RemoveBase(Instance, snk)
+       {
+               this->source = "m_remove.so";
+               syntax = "<nick> <channel> [<reason>]";
+       }
+       
+       CmdResult Handle (const char** parameters, int pcnt, userrec *user)
+       {
+               return RemoveBase::Handle(parameters, pcnt, user, false);
+       }
+};
+
+/** Handle /FPART
+ */
+class cmd_fpart : public command_t, public RemoveBase
+{
+ public:
+       cmd_fpart(InspIRCd* Instance, bool& snk) : command_t(Instance, "FPART", 0, 2), RemoveBase(Instance, snk)
+       {
+               this->source = "m_remove.so";
+               syntax = "<channel> <nick> [<reason>]";
+       }
+
+       CmdResult Handle (const char** parameters, int pcnt, userrec *user)
+       {
+               return RemoveBase::Handle(parameters, pcnt, user, true);
+       }
+};
+
+class ModuleRemove : public Module
+{
+       cmd_remove* mycommand;
+       cmd_fpart* mycommand2;
+       bool supportnokicks;
+       
+       
+ public:
+       ModuleRemove(InspIRCd* Me)
+       : Module(Me)
+       {
+               mycommand = new cmd_remove(ServerInstance, supportnokicks);
+               mycommand2 = new cmd_fpart(ServerInstance, supportnokicks);
+               ServerInstance->AddCommand(mycommand);
+               ServerInstance->AddCommand(mycommand2);
+               OnRehash(NULL,"");
+       }
+
+       void Implements(char* List)
+       {
+               List[I_On005Numeric] = List[I_OnRehash] = 1;
+       }
+
+       virtual void On005Numeric(std::string &output)
+       {
+               output.append(" REMOVE");
+       }
+       
+       virtual void OnRehash(userrec* user, const std::string&)
+       {
+               ConfigReader conf(ServerInstance);
+               supportnokicks = conf.ReadFlag("remove", "supportnokicks", 0);
+       }
+       
+       virtual ~ModuleRemove()
+       {
+       }
+       
+       virtual Version GetVersion()
+       {
+               return Version(1,1,1,0,VF_VENDOR,API_VERSION);
+       }
+       
+};
+
+MODULE_INIT(ModuleRemove)
index 5535ca464f6e4abeca102129d6c379e3515205ed..9315385a1aeb416bf0d2ad63a0ec5967b54404ee 100644 (file)
@@ -1 +1,98 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r\r/* $ModDesc: Restricts banned users in a channel. May not speak, etc. */\r\rclass ModuleRestrictBanned : public Module\r{\r private:\r public:\r    ModuleRestrictBanned(InspIRCd* Me) : Module(Me)\r        {\r      }\r      \r       virtual ~ModuleRestrictBanned()\r        {\r      }\r      \r       virtual Version GetVersion()\r   {\r              return Version(1,1,0,1,VF_VENDOR,API_VERSION);\r }\r\r     void Implements(char* List)\r    {\r              List[I_OnLocalTopicChange] = List[I_OnUserPreNick] = List[I_OnUserPreNotice] = List[I_OnUserPreMessage] = 1;\r   }\r\r     int CheckRestricted(userrec *user, chanrec *channel, const std::string &action)\r        {\r              /* aren't local? we don't care. */\r             if (!IS_LOCAL(user))\r                   return 0;\r\r             if (channel->GetStatus(user) < STATUS_VOICE && channel->IsBanned(user))\r                {\r                      /* banned, boned. drop the message. */\r                 user->WriteServ("NOTICE "+std::string(user->nick)+" :*** You may not " + action + ", as you are banned on channel " + channel->name);\r                  return 1;\r              }\r\r             return 0;\r      }\r\r     virtual int OnUserPreNick(userrec *user, const std::string &newnick)\r   {\r              /* if they aren't local, we don't care */\r              if (!IS_LOCAL(user))\r                   return 0;\r\r             /* bit of a special case. */\r           for (UCListIter i = user->chans.begin(); i != user->chans.end(); i++)\r          {\r                      if (CheckRestricted(user, i->first, "change your nickname") == 1)\r                              return 1;\r              }\r\r             return 0;\r      }\r\r     virtual int OnLocalTopicChange(userrec *user, chanrec *channel, const std::string &topic)\r      {\r              return CheckRestricted(user, channel, "change the topic");\r     }\r      \r       virtual int OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)\r    {\r              return OnUserPreNotice(user,dest,target_type,text,status,exempt_list);\r }\r\r     virtual int OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)\r     {\r              if (target_type == TYPE_CHANNEL)\r               {\r                      chanrec *channel = (chanrec *)dest;\r\r                   return CheckRestricted(user, channel, "message the channel");\r          }\r\r             return 0;\r      }\r};\r\rMODULE_INIT(ModuleRestrictBanned)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+
+/* $ModDesc: Restricts banned users in a channel. May not speak, etc. */
+
+class ModuleRestrictBanned : public Module
+{
+ private:
+ public:
+       ModuleRestrictBanned(InspIRCd* Me) : Module(Me)
+       {
+       }
+       
+       virtual ~ModuleRestrictBanned()
+       {
+       }
+       
+       virtual Version GetVersion()
+       {
+               return Version(1,1,0,1,VF_VENDOR,API_VERSION);
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnLocalTopicChange] = List[I_OnUserPreNick] = List[I_OnUserPreNotice] = List[I_OnUserPreMessage] = 1;
+       }
+
+       int CheckRestricted(userrec *user, chanrec *channel, const std::string &action)
+       {
+               /* aren't local? we don't care. */
+               if (!IS_LOCAL(user))
+                       return 0;
+
+               if (channel->GetStatus(user) < STATUS_VOICE && channel->IsBanned(user))
+               {
+                       /* banned, boned. drop the message. */
+                       user->WriteServ("NOTICE "+std::string(user->nick)+" :*** You may not " + action + ", as you are banned on channel " + channel->name);
+                       return 1;
+               }
+
+               return 0;
+       }
+
+       virtual int OnUserPreNick(userrec *user, const std::string &newnick)
+       {
+               /* if they aren't local, we don't care */
+               if (!IS_LOCAL(user))
+                       return 0;
+
+               /* bit of a special case. */
+               for (UCListIter i = user->chans.begin(); i != user->chans.end(); i++)
+               {
+                       if (CheckRestricted(user, i->first, "change your nickname") == 1)
+                               return 1;
+               }
+
+               return 0;
+       }
+
+       virtual int OnLocalTopicChange(userrec *user, chanrec *channel, const std::string &topic)
+       {
+               return CheckRestricted(user, channel, "change the topic");
+       }
+       
+       virtual int OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
+       {
+               return OnUserPreNotice(user,dest,target_type,text,status,exempt_list);
+       }
+
+       virtual int OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
+       {
+               if (target_type == TYPE_CHANNEL)
+               {
+                       chanrec *channel = (chanrec *)dest;
+
+                       return CheckRestricted(user, channel, "message the channel");
+               }
+
+               return 0;
+       }
+};
+
+MODULE_INIT(ModuleRestrictBanned)
index 1fc44f22bc4eb645a12a7667951de6534635ffea..1f2416d4470b32ae82273f07ef686267d1508fcc 100644 (file)
@@ -1 +1,85 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *        the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r\r/* $ModDesc: Only opers may create new channels if this module is loaded */\r\rclass ModuleRestrictChans : public Module\r{\r \r\r      std::map<irc::string,int> allowchans;\r\r void ReadConfig()\r      {\r              ConfigReader* MyConf = new ConfigReader(ServerInstance);\r               allowchans.clear();\r            for (int i = 0; i < MyConf->Enumerate("allowchannel"); i++)\r            {\r                      std::string txt;\r                       txt = MyConf->ReadValue("allowchannel", "name", i);\r                    irc::string channel = txt.c_str();\r                     allowchans[channel] = 1;\r               }\r              DELETE(MyConf);\r        }\r\r public:\r    ModuleRestrictChans(InspIRCd* Me)\r              : Module(Me)\r   {\r              \r               ReadConfig();\r  }\r\r     virtual void OnRehash(userrec* user, const std::string &parameter)\r     {\r              ReadConfig();\r  }\r\r     void Implements(char* List)\r    {\r              List[I_OnUserPreJoin] = List[I_OnRehash] = 1;\r  }\r      \r       virtual int OnUserPreJoin(userrec* user, chanrec* chan, const char* cname, std::string &privs)\r {\r              irc::string x = cname;\r         // user is not an oper and its not in the allow list\r           if ((!IS_OPER(user)) && (allowchans.find(x) == allowchans.end()))\r              {\r                      // channel does not yet exist (record is null, about to be created IF we were to allow it)\r                     if (!chan)\r                     {\r                              user->WriteServ("530 %s %s :Only IRC operators may create new channels",user->nick,cname,cname);\r                               return 1;\r                      }\r              }\r              return 0;\r      }\r      \r       virtual ~ModuleRestrictChans()\r {\r      }\r      \r       virtual Version GetVersion()\r   {\r              return Version(1,1,0,1,VF_VENDOR,API_VERSION);\r }\r};\r\rMODULE_INIT(ModuleRestrictChans)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *         the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+
+/* $ModDesc: Only opers may create new channels if this module is loaded */
+
+class ModuleRestrictChans : public Module
+{
+       
+
+       std::map<irc::string,int> allowchans;
+
+       void ReadConfig()
+       {
+               ConfigReader* MyConf = new ConfigReader(ServerInstance);
+               allowchans.clear();
+               for (int i = 0; i < MyConf->Enumerate("allowchannel"); i++)
+               {
+                       std::string txt;
+                       txt = MyConf->ReadValue("allowchannel", "name", i);
+                       irc::string channel = txt.c_str();
+                       allowchans[channel] = 1;
+               }
+               DELETE(MyConf);
+       }
+
+ public:
+       ModuleRestrictChans(InspIRCd* Me)
+               : Module(Me)
+       {
+               
+               ReadConfig();
+       }
+
+       virtual void OnRehash(userrec* user, const std::string &parameter)
+       {
+               ReadConfig();
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnUserPreJoin] = List[I_OnRehash] = 1;
+       }
+       
+       virtual int OnUserPreJoin(userrec* user, chanrec* chan, const char* cname, std::string &privs)
+       {
+               irc::string x = cname;
+               // user is not an oper and its not in the allow list
+               if ((!IS_OPER(user)) && (allowchans.find(x) == allowchans.end()))
+               {
+                       // channel does not yet exist (record is null, about to be created IF we were to allow it)
+                       if (!chan)
+                       {
+                               user->WriteServ("530 %s %s :Only IRC operators may create new channels",user->nick,cname,cname);
+                               return 1;
+                       }
+               }
+               return 0;
+       }
+       
+       virtual ~ModuleRestrictChans()
+       {
+       }
+       
+       virtual Version GetVersion()
+       {
+               return Version(1,1,0,1,VF_VENDOR,API_VERSION);
+       }
+};
+
+MODULE_INIT(ModuleRestrictChans)
index c05e320fe8b6e1d1b04a2b0ffa3cc6a6b3f1bd88..0e95660b22eedd563bfdf1bf3dcf92ce766daef0 100644 (file)
@@ -1 +1,75 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r\r/* $ModDesc: Forbids users from messaging each other. Users may still message opers and opers may message other opers. */\r\r\rclass ModuleRestrictMsg : public Module\r{\r        \r public:\r \r    ModuleRestrictMsg(InspIRCd* Me)\r                : Module(Me)\r   {\r              \r       }\r\r     void Implements(char* List)\r    {\r              List[I_OnUserPreMessage] = List[I_OnUserPreNotice] = 1;\r        }\r\r     virtual int OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)\r    {\r              if ((target_type == TYPE_USER) && (IS_LOCAL(user)))\r            {\r                      userrec* u = (userrec*)dest;\r\r                  // message allowed if:\r                 // (1) the sender is opered\r                    // (2) the recipient is opered\r                 // anything else, blocked.\r                     if (IS_OPER(u) || IS_OPER(user))\r                       {\r                              return 0;\r                      }\r                      user->WriteServ("531 %s %s :You are not permitted to send private messages to this user",user->nick,u->nick);\r                  return 1;\r              }\r\r             // however, we must allow channel messages...\r          return 0;\r      }\r\r     virtual int OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)\r     {\r              return this->OnUserPreMessage(user,dest,target_type,text,status,exempt_list);\r  }\r\r     virtual ~ModuleRestrictMsg()\r   {\r      }\r      \r       virtual Version GetVersion()\r   {\r              return Version(1,1,0,1,VF_VENDOR,API_VERSION);\r }\r};\r\rMODULE_INIT(ModuleRestrictMsg)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+
+/* $ModDesc: Forbids users from messaging each other. Users may still message opers and opers may message other opers. */
+
+
+class ModuleRestrictMsg : public Module
+{
+       
+ public:
+       ModuleRestrictMsg(InspIRCd* Me)
+               : Module(Me)
+       {
+               
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnUserPreMessage] = List[I_OnUserPreNotice] = 1;
+       }
+
+       virtual int OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
+       {
+               if ((target_type == TYPE_USER) && (IS_LOCAL(user)))
+               {
+                       userrec* u = (userrec*)dest;
+
+                       // message allowed if:
+                       // (1) the sender is opered
+                       // (2) the recipient is opered
+                       // anything else, blocked.
+                       if (IS_OPER(u) || IS_OPER(user))
+                       {
+                               return 0;
+                       }
+                       user->WriteServ("531 %s %s :You are not permitted to send private messages to this user",user->nick,u->nick);
+                       return 1;
+               }
+
+               // however, we must allow channel messages...
+               return 0;
+       }
+
+       virtual int OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
+       {
+               return this->OnUserPreMessage(user,dest,target_type,text,status,exempt_list);
+       }
+
+       virtual ~ModuleRestrictMsg()
+       {
+       }
+       
+       virtual Version GetVersion()
+       {
+               return Version(1,1,0,1,VF_VENDOR,API_VERSION);
+       }
+};
+
+MODULE_INIT(ModuleRestrictMsg)
index abd782c866ce401f5c78fb02a3ebe01105edc253..4adfc001170f44ecb831a007eff038b10084557c 100644 (file)
@@ -1 +1,268 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *        the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h" \r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r#include "wildcard.h"\r\r/** Holds a users m_safelist state\r */\rclass ListData : public classbase\r{\r public:\r       long list_start;\r       long list_position;\r    bool list_ended;\r       const std::string glob;\r        int minusers;\r  int maxusers;\r\r ListData() : list_start(0), list_position(0), list_ended(false) {};\r    ListData(long pos, time_t t, const std::string &pattern, int mi, int ma) : list_start(t), list_position(pos), list_ended(false), glob(pattern), minusers(mi), maxusers(ma) {};\r};\r\r/* $ModDesc: A module overriding /list, and making it safe - stop those sendq problems. */\r\rclass ModuleSafeList : public Module\r{\r  time_t ThrottleSecs;\r   size_t ServerNameSize;\r int global_listing;\r    int LimitList;\r public:\r        ModuleSafeList(InspIRCd* Me) : Module(Me)\r      {\r              OnRehash(NULL, "");\r    }\r \r    virtual ~ModuleSafeList()\r      {\r      }\r\r     virtual void OnRehash(userrec* user, const std::string &parameter)\r     {\r              ConfigReader MyConf(ServerInstance);\r           ThrottleSecs = MyConf.ReadInteger("safelist", "throttle", "60", 0, true);\r              LimitList = MyConf.ReadInteger("safelist", "maxlisters", "50", 0, true);\r               ServerNameSize = strlen(ServerInstance->Config->ServerName) + 4;\r               global_listing = 0;\r    }\r \r    virtual Version GetVersion()\r   {\r              return Version(1,1,0,0,VF_VENDOR,API_VERSION);\r }\r \r    void Implements(char* List)\r    {\r              List[I_OnBufferFlushed] = List[I_OnPreCommand] = List[I_OnCleanup] = List[I_OnUserQuit] = List[I_On005Numeric] = List[I_OnRehash] = 1;\r }\r\r     /*\r      * OnPreCommand()\r       *   Intercept the LIST command.\r        */ \r   virtual int OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line)\r       {\r              /* If the command doesnt appear to be valid, we dont want to mess with it. */\r          if (!validated)\r                        return 0;\r \r            if (command == "LIST")\r         {\r                      return this->HandleList(parameters, pcnt, user);\r               }\r              return 0;\r      }\r      \r       /*\r      * HandleList()\r         *   Handle (override) the LIST command.\r        */\r    int HandleList(const char** parameters, int pcnt, userrec* user)\r       {\r              int minusers = 0, maxusers = 0;\r\r               if (global_listing >= LimitList)\r               {\r                      user->WriteServ("NOTICE %s :*** Server load is currently too heavy. Please try again later.", user->nick);\r                     user->WriteServ("321 %s Channel :Users Name",user->nick);\r                      user->WriteServ("323 %s :End of channel list.",user->nick);\r                    return 1;\r              }\r\r             /* First, let's check if the user is currently /list'ing */\r            ListData *ld;\r          user->GetExt("safelist_cache", ld);\r \r          if (ld)\r                {\r                      /* user is already /list'ing, we don't want to do shit. */\r                     return 1;\r              }\r\r             /* Work around mIRC suckyness. YOU SUCK, KHALED! */\r            if (pcnt == 1)\r         {\r                      if (*parameters[0] == '<')\r                     {\r                              maxusers = atoi(parameters[0]+1);\r                              ServerInstance->Log(DEBUG,"Max users: %d", maxusers);\r                          pcnt = 0;\r                      }\r                      else if (*parameters[0] == '>')\r                        {\r                              minusers = atoi(parameters[0]+1);\r                              ServerInstance->Log(DEBUG,"Min users: %d", minusers);\r                          pcnt = 0;\r                      }\r              }\r\r             time_t* last_list_time;\r                user->GetExt("safelist_last", last_list_time);\r         if (last_list_time)\r            {\r                      if (ServerInstance->Time() < (*last_list_time)+ThrottleSecs)\r                   {\r                              user->WriteServ("NOTICE %s :*** Woah there, slow down a little, you can't /LIST so often!",user->nick);\r                                user->WriteServ("321 %s Channel :Users Name",user->nick);\r                              user->WriteServ("323 %s :End of channel list.",user->nick);\r                            return 1;\r                      }\r\r                     DELETE(last_list_time);\r                        user->Shrink("safelist_last");\r         }\r\r \r           /*\r              * start at channel 0! ;)\r               */\r            ld = new ListData(0,ServerInstance->Time(), pcnt ? parameters[0] : "*", minusers, maxusers);\r           user->Extend("safelist_cache", ld);\r\r           time_t* llt = new time_t;\r              *llt = ServerInstance->Time();\r         user->Extend("safelist_last", llt);\r\r           user->WriteServ("321 %s Channel :Users Name",user->nick);\r\r             global_listing++;\r\r             return 1;\r      }\r\r     virtual void OnBufferFlushed(userrec* user)\r    {\r              char buffer[MAXBUF];\r           ListData* ld;\r          if (user->GetExt("safelist_cache", ld))\r                {\r                      chanrec* chan = NULL;\r                  long amount_sent = 0;\r                  do\r                     {\r                              chan = ServerInstance->GetChannelIndex(ld->list_position);\r                             bool has_user = (chan && chan->HasUser(user));\r                         long users = chan ? chan->GetUserCounter() : 0;\r\r                               bool too_few = (ld->minusers && (users <= ld->minusers));\r                              bool too_many = (ld->maxusers && (users >= ld->maxusers));\r\r                            if (chan && (too_many || too_few))\r                             {\r                                      ld->list_position++;\r                                   continue;\r                              }\r\r                             if ((chan) && (chan->modes[CM_PRIVATE]))\r                               {\r                                      bool display = (match(chan->name, ld->glob.c_str()) || (*chan->topic && match(chan->topic, ld->glob.c_str())));\r                                        if ((users) && (display))\r                                      {\r                                              int counter = snprintf(buffer, MAXBUF, "322 %s *", user->nick);\r                                                amount_sent += counter + ServerNameSize;\r                                               user->WriteServ(std::string(buffer));\r                                  }\r                              }\r                              else if ((chan) && (((!(chan->modes[CM_PRIVATE])) && (!(chan->modes[CM_SECRET]))) || (has_user)))\r                              {\r                                      bool display = (match(chan->name, ld->glob.c_str()) || (*chan->topic && match(chan->topic, ld->glob.c_str())));\r                                        if ((users) && (display))\r                                      {\r                                              int counter = snprintf(buffer, MAXBUF, "322 %s %s %ld :[+%s] %s",user->nick, chan->name, users, chan->ChanModes(has_user), chan->topic);\r                                               amount_sent += counter + ServerNameSize;\r                                               user->WriteServ(std::string(buffer));\r                                  }\r                              }\r                              else\r                           {\r                                      if (!chan)\r                                     {\r                                              if (!ld->list_ended)\r                                           {\r                                                      ld->list_ended = true;\r                                                 user->WriteServ("323 %s :End of channel list.",user->nick);\r                                            }\r                                      }\r                              }\r                              ld->list_position++;\r                   }\r                      while ((chan != NULL) && (amount_sent < (user->sendqmax / 4)));\r                        if (ld->list_ended)\r                    {\r                              user->Shrink("safelist_cache");\r                                DELETE(ld);\r                            global_listing--;\r                      }\r              }\r      }\r\r     virtual void OnCleanup(int target_type, void* item)\r    {\r              if(target_type == TYPE_USER)\r           {\r                      userrec* u = (userrec*)item;\r                   ListData* ld;\r                  u->GetExt("safelist_cache", ld);\r                       if (ld)\r                        {\r                              u->Shrink("safelist_cache");\r                           DELETE(ld);\r                            global_listing--;\r                      }\r                      time_t* last_list_time;\r                        u->GetExt("safelist_last", last_list_time);\r                    if (last_list_time)\r                    {\r                              DELETE(last_list_time);\r                                u->Shrink("safelist_last");\r                    }\r              }\r      }\r\r     virtual void On005Numeric(std::string &output)\r {\r              output.append(" SAFELIST");\r    }\r\r     virtual void OnUserQuit(userrec* user, const std::string &message, const std::string &oper_message)\r    {\r              this->OnCleanup(TYPE_USER,user);\r       }\r\r};\r\rMODULE_INIT(ModuleSafeList)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *         the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h" 
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+#include "wildcard.h"
+
+/** Holds a users m_safelist state
+ */
+class ListData : public classbase
+{
+ public:
+       long list_start;
+       long list_position;
+       bool list_ended;
+       const std::string glob;
+       int minusers;
+       int maxusers;
+
+       ListData() : list_start(0), list_position(0), list_ended(false) {};
+       ListData(long pos, time_t t, const std::string &pattern, int mi, int ma) : list_start(t), list_position(pos), list_ended(false), glob(pattern), minusers(mi), maxusers(ma) {};
+};
+
+/* $ModDesc: A module overriding /list, and making it safe - stop those sendq problems. */
+
+class ModuleSafeList : public Module
+{
+       time_t ThrottleSecs;
+       size_t ServerNameSize;
+       int global_listing;
+       int LimitList;
+ public:
+       ModuleSafeList(InspIRCd* Me) : Module(Me)
+       {
+               OnRehash(NULL, "");
+       }
+       virtual ~ModuleSafeList()
+       {
+       }
+
+       virtual void OnRehash(userrec* user, const std::string &parameter)
+       {
+               ConfigReader MyConf(ServerInstance);
+               ThrottleSecs = MyConf.ReadInteger("safelist", "throttle", "60", 0, true);
+               LimitList = MyConf.ReadInteger("safelist", "maxlisters", "50", 0, true);
+               ServerNameSize = strlen(ServerInstance->Config->ServerName) + 4;
+               global_listing = 0;
+       }
+       virtual Version GetVersion()
+       {
+               return Version(1,1,0,0,VF_VENDOR,API_VERSION);
+       }
+       void Implements(char* List)
+       {
+               List[I_OnBufferFlushed] = List[I_OnPreCommand] = List[I_OnCleanup] = List[I_OnUserQuit] = List[I_On005Numeric] = List[I_OnRehash] = 1;
+       }
+
+       /*
+        * OnPreCommand()
+        *   Intercept the LIST command.
+        */ 
+       virtual int OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line)
+       {
+               /* If the command doesnt appear to be valid, we dont want to mess with it. */
+               if (!validated)
+                       return 0;
+               if (command == "LIST")
+               {
+                       return this->HandleList(parameters, pcnt, user);
+               }
+               return 0;
+       }
+       
+       /*
+        * HandleList()
+        *   Handle (override) the LIST command.
+        */
+       int HandleList(const char** parameters, int pcnt, userrec* user)
+       {
+               int minusers = 0, maxusers = 0;
+
+               if (global_listing >= LimitList)
+               {
+                       user->WriteServ("NOTICE %s :*** Server load is currently too heavy. Please try again later.", user->nick);
+                       user->WriteServ("321 %s Channel :Users Name",user->nick);
+                       user->WriteServ("323 %s :End of channel list.",user->nick);
+                       return 1;
+               }
+
+               /* First, let's check if the user is currently /list'ing */
+               ListData *ld;
+               user->GetExt("safelist_cache", ld);
+               if (ld)
+               {
+                       /* user is already /list'ing, we don't want to do shit. */
+                       return 1;
+               }
+
+               /* Work around mIRC suckyness. YOU SUCK, KHALED! */
+               if (pcnt == 1)
+               {
+                       if (*parameters[0] == '<')
+                       {
+                               maxusers = atoi(parameters[0]+1);
+                               ServerInstance->Log(DEBUG,"Max users: %d", maxusers);
+                               pcnt = 0;
+                       }
+                       else if (*parameters[0] == '>')
+                       {
+                               minusers = atoi(parameters[0]+1);
+                               ServerInstance->Log(DEBUG,"Min users: %d", minusers);
+                               pcnt = 0;
+                       }
+               }
+
+               time_t* last_list_time;
+               user->GetExt("safelist_last", last_list_time);
+               if (last_list_time)
+               {
+                       if (ServerInstance->Time() < (*last_list_time)+ThrottleSecs)
+                       {
+                               user->WriteServ("NOTICE %s :*** Woah there, slow down a little, you can't /LIST so often!",user->nick);
+                               user->WriteServ("321 %s Channel :Users Name",user->nick);
+                               user->WriteServ("323 %s :End of channel list.",user->nick);
+                               return 1;
+                       }
+
+                       DELETE(last_list_time);
+                       user->Shrink("safelist_last");
+               }
+
+               /*
+                * start at channel 0! ;)
+                */
+               ld = new ListData(0,ServerInstance->Time(), pcnt ? parameters[0] : "*", minusers, maxusers);
+               user->Extend("safelist_cache", ld);
+
+               time_t* llt = new time_t;
+               *llt = ServerInstance->Time();
+               user->Extend("safelist_last", llt);
+
+               user->WriteServ("321 %s Channel :Users Name",user->nick);
+
+               global_listing++;
+
+               return 1;
+       }
+
+       virtual void OnBufferFlushed(userrec* user)
+       {
+               char buffer[MAXBUF];
+               ListData* ld;
+               if (user->GetExt("safelist_cache", ld))
+               {
+                       chanrec* chan = NULL;
+                       long amount_sent = 0;
+                       do
+                       {
+                               chan = ServerInstance->GetChannelIndex(ld->list_position);
+                               bool has_user = (chan && chan->HasUser(user));
+                               long users = chan ? chan->GetUserCounter() : 0;
+
+                               bool too_few = (ld->minusers && (users <= ld->minusers));
+                               bool too_many = (ld->maxusers && (users >= ld->maxusers));
+
+                               if (chan && (too_many || too_few))
+                               {
+                                       ld->list_position++;
+                                       continue;
+                               }
+
+                               if ((chan) && (chan->modes[CM_PRIVATE]))
+                               {
+                                       bool display = (match(chan->name, ld->glob.c_str()) || (*chan->topic && match(chan->topic, ld->glob.c_str())));
+                                       if ((users) && (display))
+                                       {
+                                               int counter = snprintf(buffer, MAXBUF, "322 %s *", user->nick);
+                                               amount_sent += counter + ServerNameSize;
+                                               user->WriteServ(std::string(buffer));
+                                       }
+                               }
+                               else if ((chan) && (((!(chan->modes[CM_PRIVATE])) && (!(chan->modes[CM_SECRET]))) || (has_user)))
+                               {
+                                       bool display = (match(chan->name, ld->glob.c_str()) || (*chan->topic && match(chan->topic, ld->glob.c_str())));
+                                       if ((users) && (display))
+                                       {
+                                               int counter = snprintf(buffer, MAXBUF, "322 %s %s %ld :[+%s] %s",user->nick, chan->name, users, chan->ChanModes(has_user), chan->topic);
+                                               amount_sent += counter + ServerNameSize;
+                                               user->WriteServ(std::string(buffer));
+                                       }
+                               }
+                               else
+                               {
+                                       if (!chan)
+                                       {
+                                               if (!ld->list_ended)
+                                               {
+                                                       ld->list_ended = true;
+                                                       user->WriteServ("323 %s :End of channel list.",user->nick);
+                                               }
+                                       }
+                               }
+                               ld->list_position++;
+                       }
+                       while ((chan != NULL) && (amount_sent < (user->sendqmax / 4)));
+                       if (ld->list_ended)
+                       {
+                               user->Shrink("safelist_cache");
+                               DELETE(ld);
+                               global_listing--;
+                       }
+               }
+       }
+
+       virtual void OnCleanup(int target_type, void* item)
+       {
+               if(target_type == TYPE_USER)
+               {
+                       userrec* u = (userrec*)item;
+                       ListData* ld;
+                       u->GetExt("safelist_cache", ld);
+                       if (ld)
+                       {
+                               u->Shrink("safelist_cache");
+                               DELETE(ld);
+                               global_listing--;
+                       }
+                       time_t* last_list_time;
+                       u->GetExt("safelist_last", last_list_time);
+                       if (last_list_time)
+                       {
+                               DELETE(last_list_time);
+                               u->Shrink("safelist_last");
+                       }
+               }
+       }
+
+       virtual void On005Numeric(std::string &output)
+       {
+               output.append(" SAFELIST");
+       }
+
+       virtual void OnUserQuit(userrec* user, const std::string &message, const std::string &oper_message)
+       {
+               this->OnCleanup(TYPE_USER,user);
+       }
+
+};
+
+MODULE_INIT(ModuleSafeList)
index 2b143606f78640c0ea240c20b8a4c82cced6f3eb..0c9822fb92a743c9990315a13791f47f8de25b3a 100644 (file)
@@ -1 +1,114 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r\r/* $ModDesc: Provides support for unreal-style SAJOIN command */\r\r/** Handle /SAJOIN\r */\rclass cmd_sajoin : public command_t\r{\r public:\r cmd_sajoin (InspIRCd* Instance) : command_t(Instance,"SAJOIN", 'o', 2)\r      {\r              this->source = "m_sajoin.so";\r          syntax = "<nick> <channel>";\r   }\r\r     CmdResult Handle (const char** parameters, int pcnt, userrec *user)\r    {\r              userrec* dest = ServerInstance->FindNick(parameters[0]);\r               if (dest)\r              {\r                      if (ServerInstance->ULine(dest->server))\r                       {\r                              user->WriteServ("990 %s :Cannot use an SA command on a u-lined client",user->nick);\r                            return CMD_FAILURE;\r                    }\r                      if (!ServerInstance->IsChannel(parameters[1]))\r                 {\r                              /* we didn't need to check this for each character ;) */\r                               user->WriteServ("NOTICE "+std::string(user->nick)+" :*** Invalid characters in channel name");\r                         return CMD_FAILURE;\r                    }\r\r                     /* For local users, we send the JoinUser which may create a channel and set its TS.\r                     * For non-local users, we just return CMD_SUCCESS, knowing this will propogate it where it needs to be\r                         * and then that server will generate the users JOIN or FJOIN instead.\r                  */\r                    if (IS_LOCAL(dest))\r                    {\r                              chanrec::JoinUser(ServerInstance, dest, parameters[1], true, "", ServerInstance->Time(true));\r                          /* Fix for dotslasher and w00t - if the join didnt succeed, return CMD_FAILURE so that it doesnt propogate */\r                          chanrec* n = ServerInstance->FindChan(parameters[1]);\r                          if (n)\r                         {\r                                      if (n->HasUser(dest))\r                                  {\r                                              ServerInstance->WriteOpers("*** "+std::string(user->nick)+" used SAJOIN to make "+std::string(dest->nick)+" join "+parameters[1]);\r                                             return CMD_SUCCESS;\r                                    }\r                                      else\r                                   {\r                                              user->WriteServ("NOTICE "+std::string(user->nick)+" :*** Could not join "+std::string(dest->nick)+" to "+parameters[1]+" (User is probably banned, or blocking modes)");\r                                               return CMD_FAILURE;\r                                    }\r                              }\r                              else\r                           {\r                                      user->WriteServ("NOTICE "+std::string(user->nick)+" :*** Could not join "+std::string(dest->nick)+" to "+parameters[1]);\r                                       return CMD_FAILURE;\r                            }\r                      }\r                      else\r                   {\r                              ServerInstance->WriteOpers("*** "+std::string(user->nick)+" sent remote SAJOIN to make "+std::string(dest->nick)+" join "+parameters[1]);\r                              return CMD_SUCCESS;\r                    }\r              }\r              else\r           {\r                      user->WriteServ("NOTICE "+std::string(user->nick)+" :*** No such nickname "+parameters[0]);\r                    return CMD_FAILURE;\r            }\r      }\r};\r\rclass ModuleSajoin : public Module\r{\r     cmd_sajoin*     mycommand;\r public:\r    ModuleSajoin(InspIRCd* Me)\r             : Module(Me)\r   {\r              \r               mycommand = new cmd_sajoin(ServerInstance);\r            ServerInstance->AddCommand(mycommand);\r }\r      \r       virtual ~ModuleSajoin()\r        {\r      }\r      \r       virtual Version GetVersion()\r   {\r              return Version(1,1,0,1,VF_VENDOR,API_VERSION);\r }\r      \r};\r\rMODULE_INIT(ModuleSajoin)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+
+/* $ModDesc: Provides support for unreal-style SAJOIN command */
+
+/** Handle /SAJOIN
+ */
+class cmd_sajoin : public command_t
+{
+ public:
+ cmd_sajoin (InspIRCd* Instance) : command_t(Instance,"SAJOIN", 'o', 2)
+       {
+               this->source = "m_sajoin.so";
+               syntax = "<nick> <channel>";
+       }
+
+       CmdResult Handle (const char** parameters, int pcnt, userrec *user)
+       {
+               userrec* dest = ServerInstance->FindNick(parameters[0]);
+               if (dest)
+               {
+                       if (ServerInstance->ULine(dest->server))
+                       {
+                               user->WriteServ("990 %s :Cannot use an SA command on a u-lined client",user->nick);
+                               return CMD_FAILURE;
+                       }
+                       if (!ServerInstance->IsChannel(parameters[1]))
+                       {
+                               /* we didn't need to check this for each character ;) */
+                               user->WriteServ("NOTICE "+std::string(user->nick)+" :*** Invalid characters in channel name");
+                               return CMD_FAILURE;
+                       }
+
+                       /* For local users, we send the JoinUser which may create a channel and set its TS.
+                        * For non-local users, we just return CMD_SUCCESS, knowing this will propogate it where it needs to be
+                        * and then that server will generate the users JOIN or FJOIN instead.
+                        */
+                       if (IS_LOCAL(dest))
+                       {
+                               chanrec::JoinUser(ServerInstance, dest, parameters[1], true, "", ServerInstance->Time(true));
+                               /* Fix for dotslasher and w00t - if the join didnt succeed, return CMD_FAILURE so that it doesnt propogate */
+                               chanrec* n = ServerInstance->FindChan(parameters[1]);
+                               if (n)
+                               {
+                                       if (n->HasUser(dest))
+                                       {
+                                               ServerInstance->WriteOpers("*** "+std::string(user->nick)+" used SAJOIN to make "+std::string(dest->nick)+" join "+parameters[1]);
+                                               return CMD_SUCCESS;
+                                       }
+                                       else
+                                       {
+                                               user->WriteServ("NOTICE "+std::string(user->nick)+" :*** Could not join "+std::string(dest->nick)+" to "+parameters[1]+" (User is probably banned, or blocking modes)");
+                                               return CMD_FAILURE;
+                                       }
+                               }
+                               else
+                               {
+                                       user->WriteServ("NOTICE "+std::string(user->nick)+" :*** Could not join "+std::string(dest->nick)+" to "+parameters[1]);
+                                       return CMD_FAILURE;
+                               }
+                       }
+                       else
+                       {
+                               ServerInstance->WriteOpers("*** "+std::string(user->nick)+" sent remote SAJOIN to make "+std::string(dest->nick)+" join "+parameters[1]);
+                               return CMD_SUCCESS;
+                       }
+               }
+               else
+               {
+                       user->WriteServ("NOTICE "+std::string(user->nick)+" :*** No such nickname "+parameters[0]);
+                       return CMD_FAILURE;
+               }
+       }
+};
+
+class ModuleSajoin : public Module
+{
+       cmd_sajoin*     mycommand;
+ public:
+       ModuleSajoin(InspIRCd* Me)
+               : Module(Me)
+       {
+               
+               mycommand = new cmd_sajoin(ServerInstance);
+               ServerInstance->AddCommand(mycommand);
+       }
+       
+       virtual ~ModuleSajoin()
+       {
+       }
+       
+       virtual Version GetVersion()
+       {
+               return Version(1,1,0,1,VF_VENDOR,API_VERSION);
+       }
+       
+};
+
+MODULE_INIT(ModuleSajoin)
index f48e078b1159ab7c04631afc13bed0d6ff2bb18a..88d0d666e54828ddea2538c9161aa30f03f9050c 100644 (file)
@@ -1 +1,98 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r/* $ModDesc: Provides more advanced UnrealIRCd SAMODE command */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r\r/** Handle /SAMODE\r */\rclass cmd_samode : public command_t\r{\r public:\r      cmd_samode (InspIRCd* Instance) : command_t(Instance,"SAMODE", 'o', 2)\r {\r              this->source = "m_samode.so";\r          syntax = "<target> <modes> {<mode-parameters>}";\r       }\r\r     CmdResult Handle (const char** parameters, int pcnt, userrec *user)\r    {\r              /*\r              * Handles an SAMODE request. Notifies all +s users.\r            */\r\r           userrec* n = new userrec(ServerInstance);\r              n->SetFd(FD_MAGIC_NUMBER);\r             ServerInstance->SendMode(parameters,pcnt,n);\r           delete n;\r\r             if (ServerInstance->Modes->GetLastParse().length())\r            {\r                      ServerInstance->WriteOpers("*** " + std::string(user->nick) + " used SAMODE: " + ServerInstance->Modes->GetLastParse());\r\r                      std::deque<std::string> n;\r                     irc::spacesepstream spaced(ServerInstance->Modes->GetLastParse());\r                     std::string one = "*";\r                 while ((one = spaced.GetToken()) != "")\r                                n.push_back(one);\r\r                     Event rmode((char *)&n, NULL, "send_mode");\r                    rmode.Send(ServerInstance);\r\r                   n.clear();\r                     n.push_back(std::string(user->nick) + " used SAMODE: " + ServerInstance->Modes->GetLastParse());\r                       Event rmode2((char *)&n, NULL, "send_opers");\r                  rmode2.Send(ServerInstance);\r\r                  /* XXX: Yes, this is right. We dont want to propogate the\r                       * actual SAMODE command, just the MODE command generated\r                       * by the send_mode\r                     */\r                    return CMD_LOCALONLY;\r          }\r              else\r           {\r                      user->WriteServ("NOTICE %s :*** Invalid SAMODE sequence.", user->nick);\r                }\r\r             return CMD_FAILURE;\r    }\r};\r\rclass ModuleSaMode : public Module\r{\r     cmd_samode*     mycommand;\r public:\r    ModuleSaMode(InspIRCd* Me)\r             : Module(Me)\r   {\r              \r               mycommand = new cmd_samode(ServerInstance);\r            ServerInstance->AddCommand(mycommand);\r }\r      \r       virtual ~ModuleSaMode()\r        {\r      }\r      \r       virtual Version GetVersion()\r   {\r              return Version(1,1,2,2,VF_VENDOR,API_VERSION);\r }\r};\r\rMODULE_INIT(ModuleSaMode)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+/* $ModDesc: Provides more advanced UnrealIRCd SAMODE command */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+
+/** Handle /SAMODE
+ */
+class cmd_samode : public command_t
+{
+ public:
+       cmd_samode (InspIRCd* Instance) : command_t(Instance,"SAMODE", 'o', 2)
+       {
+               this->source = "m_samode.so";
+               syntax = "<target> <modes> {<mode-parameters>}";
+       }
+
+       CmdResult Handle (const char** parameters, int pcnt, userrec *user)
+       {
+               /*
+                * Handles an SAMODE request. Notifies all +s users.
+                */
+
+               userrec* n = new userrec(ServerInstance);
+               n->SetFd(FD_MAGIC_NUMBER);
+               ServerInstance->SendMode(parameters,pcnt,n);
+               delete n;
+
+               if (ServerInstance->Modes->GetLastParse().length())
+               {
+                       ServerInstance->WriteOpers("*** " + std::string(user->nick) + " used SAMODE: " + ServerInstance->Modes->GetLastParse());
+
+                       std::deque<std::string> n;
+                       irc::spacesepstream spaced(ServerInstance->Modes->GetLastParse());
+                       std::string one = "*";
+                       while ((one = spaced.GetToken()) != "")
+                               n.push_back(one);
+
+                       Event rmode((char *)&n, NULL, "send_mode");
+                       rmode.Send(ServerInstance);
+
+                       n.clear();
+                       n.push_back(std::string(user->nick) + " used SAMODE: " + ServerInstance->Modes->GetLastParse());
+                       Event rmode2((char *)&n, NULL, "send_opers");
+                       rmode2.Send(ServerInstance);
+
+                       /* XXX: Yes, this is right. We dont want to propogate the
+                        * actual SAMODE command, just the MODE command generated
+                        * by the send_mode
+                        */
+                       return CMD_LOCALONLY;
+               }
+               else
+               {
+                       user->WriteServ("NOTICE %s :*** Invalid SAMODE sequence.", user->nick);
+               }
+
+               return CMD_FAILURE;
+       }
+};
+
+class ModuleSaMode : public Module
+{
+       cmd_samode*     mycommand;
+ public:
+       ModuleSaMode(InspIRCd* Me)
+               : Module(Me)
+       {
+               
+               mycommand = new cmd_samode(ServerInstance);
+               ServerInstance->AddCommand(mycommand);
+       }
+       
+       virtual ~ModuleSaMode()
+       {
+       }
+       
+       virtual Version GetVersion()
+       {
+               return Version(1,1,2,2,VF_VENDOR,API_VERSION);
+       }
+};
+
+MODULE_INIT(ModuleSaMode)
index 8810550ae957704f38f47062077be7f9e6402c3c..715d978c3eebeb6b0ae075fe1f1eb1ea37e50964 100644 (file)
@@ -1 +1,97 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r\r/* $ModDesc: Provides support for SANICK command */\r\r/** Handle /SANICK\r */\rclass cmd_sanick : public command_t\r{\r public:\r cmd_sanick (InspIRCd* Instance) : command_t(Instance,"SANICK", 'o', 2)\r   {\r              this->source = "m_sanick.so";\r          syntax = "<nick> <new-nick>";\r  }\r\r     CmdResult Handle (const char** parameters, int pcnt, userrec *user)\r    {\r              userrec* source = ServerInstance->FindNick(parameters[0]);\r             if (source)\r            {\r                      if (ServerInstance->ULine(source->server))\r                     {\r                              user->WriteServ("990 %s :Cannot use an SA command on a u-lined client",user->nick);\r                            return CMD_FAILURE;\r                    }\r                      std::string oldnick = user->nick;\r                      if (ServerInstance->IsNick(parameters[1]))\r                     {\r                              if (source->ForceNickChange(parameters[1]))\r                            {\r                                      ServerInstance->WriteOpers("*** " + oldnick+" used SANICK to change "+std::string(parameters[0])+" to "+parameters[1]);\r                                        return CMD_SUCCESS;\r                            }\r                              else\r                           {\r                                      /* We couldnt change the nick */\r                                       ServerInstance->WriteOpers("*** " + oldnick+" failed SANICK (from "+std::string(parameters[0])+" to "+parameters[1]+")");\r                                      return CMD_FAILURE;\r                            }\r                      }\r                      else\r                   {\r                              user->WriteServ("NOTICE %s :*** Invalid nickname '%s'", user->nick, parameters[1]);\r                    }\r\r                     return CMD_FAILURE;\r            }\r              else\r           {\r                      user->WriteServ("NOTICE %s :*** No such nickname: '%s'", user->nick, parameters[0]);\r           }\r\r             return CMD_FAILURE;\r    }\r};\r\r\rclass ModuleSanick : public Module\r{\r    cmd_sanick*     mycommand;\r public:\r    ModuleSanick(InspIRCd* Me)\r             : Module(Me)\r   {\r              \r               mycommand = new cmd_sanick(ServerInstance);\r            ServerInstance->AddCommand(mycommand);\r }\r      \r       virtual ~ModuleSanick()\r        {\r      }\r      \r       virtual Version GetVersion()\r   {\r              return Version(1,1,0,1,VF_VENDOR,API_VERSION);\r }\r      \r};\r\rMODULE_INIT(ModuleSanick)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+
+/* $ModDesc: Provides support for SANICK command */
+
+/** Handle /SANICK
+ */
+class cmd_sanick : public command_t
+{
+ public:
+ cmd_sanick (InspIRCd* Instance) : command_t(Instance,"SANICK", 'o', 2)
+       {
+               this->source = "m_sanick.so";
+               syntax = "<nick> <new-nick>";
+       }
+
+       CmdResult Handle (const char** parameters, int pcnt, userrec *user)
+       {
+               userrec* source = ServerInstance->FindNick(parameters[0]);
+               if (source)
+               {
+                       if (ServerInstance->ULine(source->server))
+                       {
+                               user->WriteServ("990 %s :Cannot use an SA command on a u-lined client",user->nick);
+                               return CMD_FAILURE;
+                       }
+                       std::string oldnick = user->nick;
+                       if (ServerInstance->IsNick(parameters[1]))
+                       {
+                               if (source->ForceNickChange(parameters[1]))
+                               {
+                                       ServerInstance->WriteOpers("*** " + oldnick+" used SANICK to change "+std::string(parameters[0])+" to "+parameters[1]);
+                                       return CMD_SUCCESS;
+                               }
+                               else
+                               {
+                                       /* We couldnt change the nick */
+                                       ServerInstance->WriteOpers("*** " + oldnick+" failed SANICK (from "+std::string(parameters[0])+" to "+parameters[1]+")");
+                                       return CMD_FAILURE;
+                               }
+                       }
+                       else
+                       {
+                               user->WriteServ("NOTICE %s :*** Invalid nickname '%s'", user->nick, parameters[1]);
+                       }
+
+                       return CMD_FAILURE;
+               }
+               else
+               {
+                       user->WriteServ("NOTICE %s :*** No such nickname: '%s'", user->nick, parameters[0]);
+               }
+
+               return CMD_FAILURE;
+       }
+};
+
+
+class ModuleSanick : public Module
+{
+       cmd_sanick*     mycommand;
+ public:
+       ModuleSanick(InspIRCd* Me)
+               : Module(Me)
+       {
+               
+               mycommand = new cmd_sanick(ServerInstance);
+               ServerInstance->AddCommand(mycommand);
+       }
+       
+       virtual ~ModuleSanick()
+       {
+       }
+       
+       virtual Version GetVersion()
+       {
+               return Version(1,1,0,1,VF_VENDOR,API_VERSION);
+       }
+       
+};
+
+MODULE_INIT(ModuleSanick)
index 4d663e822037032cb79173f343a5a8345c77f69c..829607e5866dd2c87a8f0f5a41d66ffc5ec781e4 100644 (file)
@@ -1 +1,113 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r\r/* $ModDesc: Provides support for unreal-style SAPART command */\r\r/** Handle /SAPART\r */\rclass cmd_sapart : public command_t\r{\r public:\r      cmd_sapart (InspIRCd* Instance) : command_t(Instance,"SAPART", 'o', 2)\r {\r              this->source = "m_sapart.so";\r          syntax = "<nick> <channel>";\r   }\r\r     CmdResult Handle (const char** parameters, int pcnt, userrec *user)\r    {\r              userrec* dest = ServerInstance->FindNick(parameters[0]);\r               chanrec* channel = ServerInstance->FindChan(parameters[1]);\r            if (dest && channel)\r           {\r                      if (ServerInstance->ULine(dest->server))\r                       {\r                              user->WriteServ("990 %s :Cannot use an SA command on a u-lined client",user->nick);\r                            return CMD_FAILURE;\r                    }\r\r                     /* For local clients, directly part them generating a PART message. For remote clients,\r                         * just return CMD_SUCCESS knowing the protocol module will route the SAPART to the users\r                       * local server and that will generate the PART instead\r                         */\r                    if (IS_LOCAL(dest))\r                    {\r                              if (!channel->PartUser(dest, dest->nick))\r                                      delete channel;\r                                chanrec* n = ServerInstance->FindChan(parameters[1]);\r                          if (!n)\r                                {\r                                      ServerInstance->WriteOpers("*** "+std::string(user->nick)+" used SAPART to make "+dest->nick+" part "+parameters[1]);\r                                  return CMD_SUCCESS;\r                            }\r                              else\r                           {\r                                      if (!n->HasUser(dest))\r                                 {\r                                              ServerInstance->WriteOpers("*** "+std::string(user->nick)+" used SAPART to make "+dest->nick+" part "+parameters[1]);\r                                          return CMD_SUCCESS;\r                                    }\r                                      else\r                                   {\r                                              user->WriteServ("NOTICE %s :*** Unable to make %s part %s",user->nick, dest->nick, parameters[1]);\r                                             return CMD_FAILURE;\r                                    }\r                              }\r                      }\r                      else\r                   {\r                              ServerInstance->WriteOpers("*** "+std::string(user->nick)+" sent remote SAPART to make "+dest->nick+" part "+parameters[1]);\r                   }\r\r                     return CMD_SUCCESS;\r            }\r              else\r           {\r                      user->WriteServ("NOTICE %s :*** Invalid nickname or channel", user->nick);\r             }\r\r             return CMD_FAILURE;\r    }\r};\r\r\rclass ModuleSapart : public Module\r{\r    cmd_sapart*     mycommand;\r public:\r    ModuleSapart(InspIRCd* Me)\r             : Module(Me)\r   {\r              \r               mycommand = new cmd_sapart(ServerInstance);\r            ServerInstance->AddCommand(mycommand);\r }\r      \r       virtual ~ModuleSapart()\r        {\r      }\r      \r       virtual Version GetVersion()\r   {\r              return Version(1,1,0,1,VF_VENDOR,API_VERSION);\r }\r      \r};\r\rMODULE_INIT(ModuleSapart)\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+
+/* $ModDesc: Provides support for unreal-style SAPART command */
+
+/** Handle /SAPART
+ */
+class cmd_sapart : public command_t
+{
+ public:
+       cmd_sapart (InspIRCd* Instance) : command_t(Instance,"SAPART", 'o', 2)
+       {
+               this->source = "m_sapart.so";
+               syntax = "<nick> <channel>";
+       }
+
+       CmdResult Handle (const char** parameters, int pcnt, userrec *user)
+       {
+               userrec* dest = ServerInstance->FindNick(parameters[0]);
+               chanrec* channel = ServerInstance->FindChan(parameters[1]);
+               if (dest && channel)
+               {
+                       if (ServerInstance->ULine(dest->server))
+                       {
+                               user->WriteServ("990 %s :Cannot use an SA command on a u-lined client",user->nick);
+                               return CMD_FAILURE;
+                       }
+
+                       /* For local clients, directly part them generating a PART message. For remote clients,
+                        * just return CMD_SUCCESS knowing the protocol module will route the SAPART to the users
+                        * local server and that will generate the PART instead
+                        */
+                       if (IS_LOCAL(dest))
+                       {
+                               if (!channel->PartUser(dest, dest->nick))
+                                       delete channel;
+                               chanrec* n = ServerInstance->FindChan(parameters[1]);
+                               if (!n)
+                               {
+                                       ServerInstance->WriteOpers("*** "+std::string(user->nick)+" used SAPART to make "+dest->nick+" part "+parameters[1]);
+                                       return CMD_SUCCESS;
+                               }
+                               else
+                               {
+                                       if (!n->HasUser(dest))
+                                       {
+                                               ServerInstance->WriteOpers("*** "+std::string(user->nick)+" used SAPART to make "+dest->nick+" part "+parameters[1]);
+                                               return CMD_SUCCESS;
+                                       }
+                                       else
+                                       {
+                                               user->WriteServ("NOTICE %s :*** Unable to make %s part %s",user->nick, dest->nick, parameters[1]);
+                                               return CMD_FAILURE;
+                                       }
+                               }
+                       }
+                       else
+                       {
+                               ServerInstance->WriteOpers("*** "+std::string(user->nick)+" sent remote SAPART to make "+dest->nick+" part "+parameters[1]);
+                       }
+
+                       return CMD_SUCCESS;
+               }
+               else
+               {
+                       user->WriteServ("NOTICE %s :*** Invalid nickname or channel", user->nick);
+               }
+
+               return CMD_FAILURE;
+       }
+};
+
+
+class ModuleSapart : public Module
+{
+       cmd_sapart*     mycommand;
+ public:
+       ModuleSapart(InspIRCd* Me)
+               : Module(Me)
+       {
+               
+               mycommand = new cmd_sapart(ServerInstance);
+               ServerInstance->AddCommand(mycommand);
+       }
+       
+       virtual ~ModuleSapart()
+       {
+       }
+       
+       virtual Version GetVersion()
+       {
+               return Version(1,1,0,1,VF_VENDOR,API_VERSION);
+       }
+       
+};
+
+MODULE_INIT(ModuleSapart)
+
index 36d511af903f3748718f9cfc92d50072d72c60b9..d2fa8e89b086010c0eb2402ed0ca48e2af5860b3 100644 (file)
@@ -1 +1,82 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r\r/* $ModDesc: Provides support for an SAQUIT command, exits user with a reason */\r\r/** Handle /SAQUIT\r */\rclass cmd_saquit : public command_t\r{\r public:\r cmd_saquit (InspIRCd* Instance) : command_t(Instance,"SAQUIT",'o',2)\r        {\r              this->source = "m_saquit.so";\r          syntax = "<nick> <reason>";\r    }\r\r     CmdResult Handle (const char** parameters, int pcnt, userrec *user)\r    {\r              userrec* dest = ServerInstance->FindNick(parameters[0]);\r               if (dest)\r              {\r                      if (ServerInstance->ULine(dest->server))\r                       {\r                              user->WriteServ("990 %s :Cannot use an SA command on a u-lined client",user->nick);\r                            return CMD_FAILURE;\r                    }\r                      irc::stringjoiner reason_join(" ", parameters, 1, pcnt - 1);\r                   std::string line = reason_join.GetJoined();\r\r                   ServerInstance->WriteOpers("*** "+std::string(user->nick)+" used SAQUIT to make "+std::string(dest->nick)+" quit with a reason of "+line);\r                     userrec::QuitUser(ServerInstance, dest, line);\r\r                        return CMD_SUCCESS;\r            }\r              else\r           {\r                      user->WriteServ("NOTICE %s :*** Invalid nickname '%s'", user->nick, parameters[0]);\r            }\r\r             return CMD_FAILURE;\r    }\r};\r\rclass ModuleSaquit : public Module\r{\r     cmd_saquit*     mycommand;\r public:\r    ModuleSaquit(InspIRCd* Me)\r             : Module(Me)\r   {\r              \r               mycommand = new cmd_saquit(ServerInstance);\r            ServerInstance->AddCommand(mycommand);\r }\r      \r       virtual ~ModuleSaquit()\r        {\r      }\r      \r       virtual Version GetVersion()\r   {\r              return Version(1,1,0,1,VF_VENDOR,API_VERSION);\r }\r      \r};\r\rMODULE_INIT(ModuleSaquit)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+
+/* $ModDesc: Provides support for an SAQUIT command, exits user with a reason */
+
+/** Handle /SAQUIT
+ */
+class cmd_saquit : public command_t
+{
+ public:
+ cmd_saquit (InspIRCd* Instance) : command_t(Instance,"SAQUIT",'o',2)
+       {
+               this->source = "m_saquit.so";
+               syntax = "<nick> <reason>";
+       }
+
+       CmdResult Handle (const char** parameters, int pcnt, userrec *user)
+       {
+               userrec* dest = ServerInstance->FindNick(parameters[0]);
+               if (dest)
+               {
+                       if (ServerInstance->ULine(dest->server))
+                       {
+                               user->WriteServ("990 %s :Cannot use an SA command on a u-lined client",user->nick);
+                               return CMD_FAILURE;
+                       }
+                       irc::stringjoiner reason_join(" ", parameters, 1, pcnt - 1);
+                       std::string line = reason_join.GetJoined();
+
+                       ServerInstance->WriteOpers("*** "+std::string(user->nick)+" used SAQUIT to make "+std::string(dest->nick)+" quit with a reason of "+line);
+                       userrec::QuitUser(ServerInstance, dest, line);
+
+                       return CMD_SUCCESS;
+               }
+               else
+               {
+                       user->WriteServ("NOTICE %s :*** Invalid nickname '%s'", user->nick, parameters[0]);
+               }
+
+               return CMD_FAILURE;
+       }
+};
+
+class ModuleSaquit : public Module
+{
+       cmd_saquit*     mycommand;
+ public:
+       ModuleSaquit(InspIRCd* Me)
+               : Module(Me)
+       {
+               
+               mycommand = new cmd_saquit(ServerInstance);
+               ServerInstance->AddCommand(mycommand);
+       }
+       
+       virtual ~ModuleSaquit()
+       {
+       }
+       
+       virtual Version GetVersion()
+       {
+               return Version(1,1,0,1,VF_VENDOR,API_VERSION);
+       }
+       
+};
+
+MODULE_INIT(ModuleSaquit)
index 264090311581240366c0f855382a42a3a5be72cd..8761716c02dafd2bfd88727a1c7bce8882a22b1c 100644 (file)
@@ -1 +1,97 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h" \r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r\r/* $ModDesc: A module overriding /list, and making it safe - stop those sendq problems. */\r\rclass ModuleSecureList : public Module\r{\r private:\r      std::vector<std::string> allowlist;\r    time_t WaitTime;\r public:\r      ModuleSecureList(InspIRCd* Me) : Module(Me)\r    {\r              OnRehash(NULL,"");\r     }\r \r    virtual ~ModuleSecureList()\r    {\r      }\r \r    virtual Version GetVersion()\r   {\r              return Version(1,1,0,0,VF_VENDOR,API_VERSION);\r }\r\r     void OnRehash(userrec* user, const std::string &parameter)\r     {\r              ConfigReader* MyConf = new ConfigReader(ServerInstance);\r               allowlist.clear();\r             for (int i = 0; i < MyConf->Enumerate("securehost"); i++)\r                      allowlist.push_back(MyConf->ReadValue("securehost", "exception", i));\r          WaitTime = MyConf->ReadInteger("securelist", "waittime", "60", 0, true);\r               DELETE(MyConf);\r        }\r \r    void Implements(char* List)\r    {\r              List[I_OnRehash] = List[I_OnPreCommand] = List[I_On005Numeric] = 1;\r    }\r\r     /*\r      * OnPreCommand()\r       *   Intercept the LIST command.\r        */ \r   virtual int OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line)\r       {\r              /* If the command doesnt appear to be valid, we dont want to mess with it. */\r          if (!validated)\r                        return 0;\r \r            if ((command == "LIST") && (ServerInstance->Time() < (user->signon+WaitTime)) && (!IS_OPER(user)))\r             {\r                      /* Normally wouldnt be allowed here, are they exempt? */\r                       for (std::vector<std::string>::iterator x = allowlist.begin(); x != allowlist.end(); x++)\r                              if (ServerInstance->MatchText(user->MakeHost(), *x))\r                                   return 0;\r\r                     /* Not exempt, BOOK EM DANNO! */\r                       user->WriteServ("NOTICE %s :*** You cannot list within the first %d seconds of connecting. Please try again later.",user->nick, WaitTime);\r                     /* Some crap clients (read: mIRC, various java chat applets) muck up if they don't\r                      * receive these numerics whenever they send LIST, so give them an empty LIST to mull over.\r                     */\r                    user->WriteServ("321 %s Channel :Users Name",user->nick);\r                      user->WriteServ("323 %s :End of channel list.",user->nick);\r                    return 1;\r              }\r              return 0;\r      }\r\r     virtual void On005Numeric(std::string &output)\r {\r              output.append(" SECURELIST");\r  }\r\r     virtual Priority Prioritize()\r  {\r              return (Priority)ServerInstance->PriorityBefore("m_safelist.so");\r      }\r\r};\r \rMODULE_INIT(ModuleSecureList)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h" 
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+
+/* $ModDesc: A module overriding /list, and making it safe - stop those sendq problems. */
+
+class ModuleSecureList : public Module
+{
+ private:
+       std::vector<std::string> allowlist;
+       time_t WaitTime;
+ public:
+       ModuleSecureList(InspIRCd* Me) : Module(Me)
+       {
+               OnRehash(NULL,"");
+       }
+       virtual ~ModuleSecureList()
+       {
+       }
+       virtual Version GetVersion()
+       {
+               return Version(1,1,0,0,VF_VENDOR,API_VERSION);
+       }
+
+       void OnRehash(userrec* user, const std::string &parameter)
+       {
+               ConfigReader* MyConf = new ConfigReader(ServerInstance);
+               allowlist.clear();
+               for (int i = 0; i < MyConf->Enumerate("securehost"); i++)
+                       allowlist.push_back(MyConf->ReadValue("securehost", "exception", i));
+               WaitTime = MyConf->ReadInteger("securelist", "waittime", "60", 0, true);
+               DELETE(MyConf);
+       }
+       void Implements(char* List)
+       {
+               List[I_OnRehash] = List[I_OnPreCommand] = List[I_On005Numeric] = 1;
+       }
+
+       /*
+        * OnPreCommand()
+        *   Intercept the LIST command.
+        */ 
+       virtual int OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line)
+       {
+               /* If the command doesnt appear to be valid, we dont want to mess with it. */
+               if (!validated)
+                       return 0;
+               if ((command == "LIST") && (ServerInstance->Time() < (user->signon+WaitTime)) && (!IS_OPER(user)))
+               {
+                       /* Normally wouldnt be allowed here, are they exempt? */
+                       for (std::vector<std::string>::iterator x = allowlist.begin(); x != allowlist.end(); x++)
+                               if (ServerInstance->MatchText(user->MakeHost(), *x))
+                                       return 0;
+
+                       /* Not exempt, BOOK EM DANNO! */
+                       user->WriteServ("NOTICE %s :*** You cannot list within the first %d seconds of connecting. Please try again later.",user->nick, WaitTime);
+                       /* Some crap clients (read: mIRC, various java chat applets) muck up if they don't
+                        * receive these numerics whenever they send LIST, so give them an empty LIST to mull over.
+                        */
+                       user->WriteServ("321 %s Channel :Users Name",user->nick);
+                       user->WriteServ("323 %s :End of channel list.",user->nick);
+                       return 1;
+               }
+               return 0;
+       }
+
+       virtual void On005Numeric(std::string &output)
+       {
+               output.append(" SECURELIST");
+       }
+
+       virtual Priority Prioritize()
+       {
+               return (Priority)ServerInstance->PriorityBefore("m_safelist.so");
+       }
+
+};
+MODULE_INIT(ModuleSecureList)
index 2e775581072624bb03673f7411a022621d9ea4ee..215cd34b062b3e4929fb18ba39d0aa1d06d10d92 100644 (file)
@@ -1 +1,55 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r#include "hashcomp.h"\r#include "configreader.h"\r\r/* $ModDesc: Provides support for seeing local and remote nickchanges via snomasks */\r\rclass ModuleSeeNicks : public Module\r{\r public:\r       ModuleSeeNicks(InspIRCd* Me)\r           : Module(Me)\r   {\r              ServerInstance->SNO->EnableSnomask('n',"NICK");\r                ServerInstance->SNO->EnableSnomask('N',"REMOTENICK");\r  }\r\r     virtual ~ModuleSeeNicks()\r      {\r              ServerInstance->SNO->DisableSnomask('n');\r              ServerInstance->SNO->DisableSnomask('N');\r      }\r\r     virtual Version GetVersion()\r   {\r              return Version(1,1,0,1, VF_VENDOR, API_VERSION);\r       }\r\r     void Implements(char* List)\r    {\r              List[I_OnUserPostNick] = 1;\r    }\r\r     virtual void OnUserPostNick(userrec* user, const std::string &oldnick)\r {\r              ServerInstance->SNO->WriteToSnoMask(IS_LOCAL(user) ? 'n' : 'N',"User %s changed their nickname to %s", oldnick.c_str(), user->nick);\r   }\r};\r\rMODULE_INIT(ModuleSeeNicks)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+#include "hashcomp.h"
+#include "configreader.h"
+
+/* $ModDesc: Provides support for seeing local and remote nickchanges via snomasks */
+
+class ModuleSeeNicks : public Module
+{
+ public:
+       ModuleSeeNicks(InspIRCd* Me)
+               : Module(Me)
+       {
+               ServerInstance->SNO->EnableSnomask('n',"NICK");
+               ServerInstance->SNO->EnableSnomask('N',"REMOTENICK");
+       }
+
+       virtual ~ModuleSeeNicks()
+       {
+               ServerInstance->SNO->DisableSnomask('n');
+               ServerInstance->SNO->DisableSnomask('N');
+       }
+
+       virtual Version GetVersion()
+       {
+               return Version(1,1,0,1, VF_VENDOR, API_VERSION);
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnUserPostNick] = 1;
+       }
+
+       virtual void OnUserPostNick(userrec* user, const std::string &oldnick)
+       {
+               ServerInstance->SNO->WriteToSnoMask(IS_LOCAL(user) ? 'n' : 'N',"User %s changed their nickname to %s", oldnick.c_str(), user->nick);
+       }
+};
+
+MODULE_INIT(ModuleSeeNicks)
index d429b2860764129b6aa6c88f5a646b2a889bb012..22b5dfcb5fdb27ca7cbebdfd182a0df39f42ba32 100644 (file)
@@ -1 +1,310 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r\rstatic bool kludgeme = false;\r\r/* $ModDesc: Povides support for services +r user/chan modes and more */\r\r/** Channel mode +r - mark a channel as identified\r */\rclass Channel_r : public ModeHandler\r{\r       \r public:\r      Channel_r(InspIRCd* Instance) : ModeHandler(Instance, 'r', 0, 0, false, MODETYPE_CHANNEL, false) { }\r\r  ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)\r {\r              // only a u-lined server may add or remove the +r mode.\r                if ((ServerInstance->ULine(source->nick)) || (ServerInstance->ULine(source->server)) || (!*source->server || (strchr(source->nick,'.'))))\r              {\r                      channel->SetMode('r',adding);\r                  return MODEACTION_ALLOW;\r               }\r              else\r           {\r                      source->WriteServ("500 %s :Only a server may modify the +r channel mode", source->nick);\r                       return MODEACTION_DENY;\r                }\r      }\r};\r\r/** User mode +r - mark a user as identified\r */\rclass User_r : public ModeHandler\r{\r     \r public:\r      User_r(InspIRCd* Instance) : ModeHandler(Instance, 'r', 0, 0, false, MODETYPE_USER, false) { }\r\r        ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)\r {\r              if ((kludgeme) || (ServerInstance->ULine(source->nick)) || (ServerInstance->ULine(source->server)) || (!*source->server || (strchr(source->nick,'.'))))\r                {\r                      if ((adding && !dest->IsModeSet('r')) || (!adding && dest->IsModeSet('r')))\r                    {\r                              dest->SetMode('r',adding);\r                             return MODEACTION_ALLOW;\r                       }\r                      return MODEACTION_DENY;\r                }\r              else\r           {\r                      source->WriteServ("500 %s :Only a server may modify the +r user mode", source->nick);\r                  return MODEACTION_DENY;\r                }\r      }\r};\r\r/** Channel mode +R - registered users only\r */\rclass Channel_R : public ModeHandler\r{\r public:\r  Channel_R(InspIRCd* Instance) : ModeHandler(Instance, 'R', 0, 0, false, MODETYPE_CHANNEL, false) { }\r\r  ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)\r {\r              if (adding)\r            {\r                      if (!channel->IsModeSet('R'))\r                  {\r                              channel->SetMode('R',true);\r                            return MODEACTION_ALLOW;\r                       }\r              }\r              else\r           {\r                      if (channel->IsModeSet('R'))\r                   {\r                              channel->SetMode('R',false);\r                           return MODEACTION_ALLOW;\r                       }\r              }\r\r             return MODEACTION_DENY;\r        }\r};\r\r/** User mode +R - only allow PRIVMSG and NOTICE from registered users\r */\rclass User_R : public ModeHandler\r{\r public:\r  User_R(InspIRCd* Instance) : ModeHandler(Instance, 'R', 0, 0, false, MODETYPE_USER, false) { }\r\r        ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)\r {\r              if (adding)\r            {\r                      if (!dest->IsModeSet('R'))\r                     {\r                              dest->SetMode('R',true);\r                               return MODEACTION_ALLOW;\r                       }\r              }\r              else\r           {\r                      if (dest->IsModeSet('R'))\r                      {\r                              dest->SetMode('R',false);\r                              return MODEACTION_ALLOW;\r                       }\r              }\r\r             return MODEACTION_DENY;\r        }\r};\r\r/** Channel mode +M - only allow privmsg and notice to channel from registered users\r */\rclass Channel_M : public ModeHandler\r{\r public:\r Channel_M(InspIRCd* Instance) : ModeHandler(Instance, 'M', 0, 0, false, MODETYPE_CHANNEL, false) { }\r\r  ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)\r {\r              if (adding)\r            {\r                      if (!channel->IsModeSet('M'))\r                  {\r                              channel->SetMode('M',true);\r                            return MODEACTION_ALLOW;\r                       }\r              }\r              else\r           {\r                      if (channel->IsModeSet('M'))\r                   {\r                              channel->SetMode('M',false);\r                           return MODEACTION_ALLOW;\r                       }\r              }\r\r             return MODEACTION_DENY;\r        }\r};\r\r/** Dreamnforge-like services support\r */\rclass ModuleServices : public Module\r{\r \r       Channel_r* m1;\r Channel_R* m2;\r Channel_M* m3;\r User_r* m4;\r    User_R* m5;\r public:\r   ModuleServices(InspIRCd* Me)\r           : Module(Me)\r   {\r              \r               m1 = new Channel_r(ServerInstance);\r            m2 = new Channel_R(ServerInstance);\r            m3 = new Channel_M(ServerInstance);\r            m4 = new User_r(ServerInstance);\r               m5 = new User_R(ServerInstance);\r\r              if (!ServerInstance->AddMode(m1, 'r') || !ServerInstance->AddMode(m2, 'R') || !ServerInstance->AddMode(m3, 'M')\r                        || !ServerInstance->AddMode(m4, 'r') || !ServerInstance->AddMode(m5, 'R'))\r             {\r                      throw ModuleException("Could not add user and channel modes!");\r                }\r      \r               kludgeme = false;\r      }\r\r     /* <- :stitch.chatspike.net 307 w00t w00t :is a registered nick */\r     virtual void OnWhois(userrec* source, userrec* dest)\r   {\r              if (dest->IsModeSet('r'))\r              {\r                      /* user is registered */\r                       ServerInstance->SendWhoisLine(source, dest, 307, "%s %s :is a registered nick", source->nick, dest->nick);\r             }\r      }\r\r     void Implements(char* List)\r    {\r              List[I_OnWhois] = List[I_OnUserPostNick] = List[I_OnUserPreMessage] = List[I_OnUserPreNotice] = List[I_OnUserPreJoin] = 1;\r     }\r\r     virtual void OnUserPostNick(userrec* user, const std::string &oldnick)\r {\r              /* On nickchange, if they have +r, remove it */\r                if (user->IsModeSet('r'))\r              {\r                      const char* modechange[2];\r                     modechange[0] = user->nick;\r                    modechange[1] = "-r";\r                  kludgeme = true;\r                       ServerInstance->SendMode(modechange,2,user);\r                   kludgeme = false;\r              }\r      }\r      \r       virtual int OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)\r    {\r              if (!IS_LOCAL(user))\r                   return 0;\r\r             if (target_type == TYPE_CHANNEL)\r               {\r                      chanrec* c = (chanrec*)dest;\r                   if ((c->IsModeSet('M')) && (!user->IsModeSet('r')))\r                    {\r                              if ((ServerInstance->ULine(user->nick)) || (ServerInstance->ULine(user->server)))\r                              {\r                                      // user is ulined, can speak regardless\r                                        return 0;\r                              }\r                              // user messaging a +M channel and is not registered\r                           user->WriteServ("477 %s %s :You need a registered nickname to speak on this channel", user->nick, c->name);\r                            return 1;\r                      }\r              }\r              if (target_type == TYPE_USER)\r          {\r                      userrec* u = (userrec*)dest;\r                   if ((u->IsModeSet('R')) && (!user->IsModeSet('r')))\r                    {\r                              if ((ServerInstance->ULine(user->nick)) || (ServerInstance->ULine(user->server)))\r                              {\r                                      // user is ulined, can speak regardless\r                                        return 0;\r                              }\r                              // user messaging a +R user and is not registered\r                              user->WriteServ("477 %s %s :You need a registered nickname to message this user", user->nick, u->nick);\r                                return 1;\r                      }\r              }\r              return 0;\r      }\r      \r       virtual int OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)\r     {\r              return OnUserPreMessage(user,dest,target_type,text,status, exempt_list);\r       }\r      \r       virtual int OnUserPreJoin(userrec* user, chanrec* chan, const char* cname, std::string &privs)\r {\r              if (chan)\r              {\r                      if (chan->IsModeSet('R'))\r                      {\r                              if (!user->IsModeSet('r'))\r                             {\r                                      if ((ServerInstance->ULine(user->nick)) || (ServerInstance->ULine(user->server)))\r                                      {\r                                              // user is ulined, won't be stopped from joining\r                                               return 0;\r                                      }\r                                      // joining a +R channel and not identified\r                                     user->WriteServ("477 %s %s :You need a registered nickname to join this channel", user->nick, chan->name);\r                                     return 1;\r                              }\r                      }\r              }\r              return 0;\r      }\r\r     virtual ~ModuleServices()\r      {\r              kludgeme = true;\r               ServerInstance->Modes->DelMode(m1);\r            ServerInstance->Modes->DelMode(m2);\r            ServerInstance->Modes->DelMode(m3);\r            ServerInstance->Modes->DelMode(m4);\r            ServerInstance->Modes->DelMode(m5);\r            DELETE(m1);\r            DELETE(m2);\r            DELETE(m3);\r            DELETE(m4);\r            DELETE(m5);\r    }\r      \r       virtual Version GetVersion()\r   {\r              return Version(1,1,0,0,VF_COMMON|VF_VENDOR,API_VERSION);\r       }\r};\r\r\rMODULE_INIT(ModuleServices)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+
+static bool kludgeme = false;
+
+/* $ModDesc: Povides support for services +r user/chan modes and more */
+
+/** Channel mode +r - mark a channel as identified
+ */
+class Channel_r : public ModeHandler
+{
+       
+ public:
+       Channel_r(InspIRCd* Instance) : ModeHandler(Instance, 'r', 0, 0, false, MODETYPE_CHANNEL, false) { }
+
+       ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)
+       {
+               // only a u-lined server may add or remove the +r mode.
+               if ((ServerInstance->ULine(source->nick)) || (ServerInstance->ULine(source->server)) || (!*source->server || (strchr(source->nick,'.'))))
+               {
+                       channel->SetMode('r',adding);
+                       return MODEACTION_ALLOW;
+               }
+               else
+               {
+                       source->WriteServ("500 %s :Only a server may modify the +r channel mode", source->nick);
+                       return MODEACTION_DENY;
+               }
+       }
+};
+
+/** User mode +r - mark a user as identified
+ */
+class User_r : public ModeHandler
+{
+       
+ public:
+       User_r(InspIRCd* Instance) : ModeHandler(Instance, 'r', 0, 0, false, MODETYPE_USER, false) { }
+
+       ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)
+       {
+               if ((kludgeme) || (ServerInstance->ULine(source->nick)) || (ServerInstance->ULine(source->server)) || (!*source->server || (strchr(source->nick,'.'))))
+               {
+                       if ((adding && !dest->IsModeSet('r')) || (!adding && dest->IsModeSet('r')))
+                       {
+                               dest->SetMode('r',adding);
+                               return MODEACTION_ALLOW;
+                       }
+                       return MODEACTION_DENY;
+               }
+               else
+               {
+                       source->WriteServ("500 %s :Only a server may modify the +r user mode", source->nick);
+                       return MODEACTION_DENY;
+               }
+       }
+};
+
+/** Channel mode +R - registered users only
+ */
+class Channel_R : public ModeHandler
+{
+ public:
+       Channel_R(InspIRCd* Instance) : ModeHandler(Instance, 'R', 0, 0, false, MODETYPE_CHANNEL, false) { }
+
+       ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)
+       {
+               if (adding)
+               {
+                       if (!channel->IsModeSet('R'))
+                       {
+                               channel->SetMode('R',true);
+                               return MODEACTION_ALLOW;
+                       }
+               }
+               else
+               {
+                       if (channel->IsModeSet('R'))
+                       {
+                               channel->SetMode('R',false);
+                               return MODEACTION_ALLOW;
+                       }
+               }
+
+               return MODEACTION_DENY;
+       }
+};
+
+/** User mode +R - only allow PRIVMSG and NOTICE from registered users
+ */
+class User_R : public ModeHandler
+{
+ public:
+       User_R(InspIRCd* Instance) : ModeHandler(Instance, 'R', 0, 0, false, MODETYPE_USER, false) { }
+
+       ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)
+       {
+               if (adding)
+               {
+                       if (!dest->IsModeSet('R'))
+                       {
+                               dest->SetMode('R',true);
+                               return MODEACTION_ALLOW;
+                       }
+               }
+               else
+               {
+                       if (dest->IsModeSet('R'))
+                       {
+                               dest->SetMode('R',false);
+                               return MODEACTION_ALLOW;
+                       }
+               }
+
+               return MODEACTION_DENY;
+       }
+};
+
+/** Channel mode +M - only allow privmsg and notice to channel from registered users
+ */
+class Channel_M : public ModeHandler
+{
+ public:
+       Channel_M(InspIRCd* Instance) : ModeHandler(Instance, 'M', 0, 0, false, MODETYPE_CHANNEL, false) { }
+
+       ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)
+       {
+               if (adding)
+               {
+                       if (!channel->IsModeSet('M'))
+                       {
+                               channel->SetMode('M',true);
+                               return MODEACTION_ALLOW;
+                       }
+               }
+               else
+               {
+                       if (channel->IsModeSet('M'))
+                       {
+                               channel->SetMode('M',false);
+                               return MODEACTION_ALLOW;
+                       }
+               }
+
+               return MODEACTION_DENY;
+       }
+};
+
+/** Dreamnforge-like services support
+ */
+class ModuleServices : public Module
+{
+       
+       Channel_r* m1;
+       Channel_R* m2;
+       Channel_M* m3;
+       User_r* m4;
+       User_R* m5;
+ public:
+       ModuleServices(InspIRCd* Me)
+               : Module(Me)
+       {
+               
+               m1 = new Channel_r(ServerInstance);
+               m2 = new Channel_R(ServerInstance);
+               m3 = new Channel_M(ServerInstance);
+               m4 = new User_r(ServerInstance);
+               m5 = new User_R(ServerInstance);
+
+               if (!ServerInstance->AddMode(m1, 'r') || !ServerInstance->AddMode(m2, 'R') || !ServerInstance->AddMode(m3, 'M')
+                       || !ServerInstance->AddMode(m4, 'r') || !ServerInstance->AddMode(m5, 'R'))
+               {
+                       throw ModuleException("Could not add user and channel modes!");
+               }
+       
+               kludgeme = false;
+       }
+
+       /* <- :stitch.chatspike.net 307 w00t w00t :is a registered nick */
+       virtual void OnWhois(userrec* source, userrec* dest)
+       {
+               if (dest->IsModeSet('r'))
+               {
+                       /* user is registered */
+                       ServerInstance->SendWhoisLine(source, dest, 307, "%s %s :is a registered nick", source->nick, dest->nick);
+               }
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnWhois] = List[I_OnUserPostNick] = List[I_OnUserPreMessage] = List[I_OnUserPreNotice] = List[I_OnUserPreJoin] = 1;
+       }
+
+       virtual void OnUserPostNick(userrec* user, const std::string &oldnick)
+       {
+               /* On nickchange, if they have +r, remove it */
+               if (user->IsModeSet('r'))
+               {
+                       const char* modechange[2];
+                       modechange[0] = user->nick;
+                       modechange[1] = "-r";
+                       kludgeme = true;
+                       ServerInstance->SendMode(modechange,2,user);
+                       kludgeme = false;
+               }
+       }
+       
+       virtual int OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
+       {
+               if (!IS_LOCAL(user))
+                       return 0;
+
+               if (target_type == TYPE_CHANNEL)
+               {
+                       chanrec* c = (chanrec*)dest;
+                       if ((c->IsModeSet('M')) && (!user->IsModeSet('r')))
+                       {
+                               if ((ServerInstance->ULine(user->nick)) || (ServerInstance->ULine(user->server)))
+                               {
+                                       // user is ulined, can speak regardless
+                                       return 0;
+                               }
+                               // user messaging a +M channel and is not registered
+                               user->WriteServ("477 %s %s :You need a registered nickname to speak on this channel", user->nick, c->name);
+                               return 1;
+                       }
+               }
+               if (target_type == TYPE_USER)
+               {
+                       userrec* u = (userrec*)dest;
+                       if ((u->IsModeSet('R')) && (!user->IsModeSet('r')))
+                       {
+                               if ((ServerInstance->ULine(user->nick)) || (ServerInstance->ULine(user->server)))
+                               {
+                                       // user is ulined, can speak regardless
+                                       return 0;
+                               }
+                               // user messaging a +R user and is not registered
+                               user->WriteServ("477 %s %s :You need a registered nickname to message this user", user->nick, u->nick);
+                               return 1;
+                       }
+               }
+               return 0;
+       }
+       
+       virtual int OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
+       {
+               return OnUserPreMessage(user,dest,target_type,text,status, exempt_list);
+       }
+       
+       virtual int OnUserPreJoin(userrec* user, chanrec* chan, const char* cname, std::string &privs)
+       {
+               if (chan)
+               {
+                       if (chan->IsModeSet('R'))
+                       {
+                               if (!user->IsModeSet('r'))
+                               {
+                                       if ((ServerInstance->ULine(user->nick)) || (ServerInstance->ULine(user->server)))
+                                       {
+                                               // user is ulined, won't be stopped from joining
+                                               return 0;
+                                       }
+                                       // joining a +R channel and not identified
+                                       user->WriteServ("477 %s %s :You need a registered nickname to join this channel", user->nick, chan->name);
+                                       return 1;
+                               }
+                       }
+               }
+               return 0;
+       }
+
+       virtual ~ModuleServices()
+       {
+               kludgeme = true;
+               ServerInstance->Modes->DelMode(m1);
+               ServerInstance->Modes->DelMode(m2);
+               ServerInstance->Modes->DelMode(m3);
+               ServerInstance->Modes->DelMode(m4);
+               ServerInstance->Modes->DelMode(m5);
+               DELETE(m1);
+               DELETE(m2);
+               DELETE(m3);
+               DELETE(m4);
+               DELETE(m5);
+       }
+       
+       virtual Version GetVersion()
+       {
+               return Version(1,1,0,0,VF_COMMON|VF_VENDOR,API_VERSION);
+       }
+};
+
+
+MODULE_INIT(ModuleServices)
index 3d32e315673f037b52dade59f77a2aeebafdfe7b..cff0d7698f236165e4f5543cd3566cdc0c39136f 100644 (file)
@@ -1 +1,332 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r#include "hashcomp.h"\r\r/* $ModDesc: Povides support for ircu-style services accounts, including chmode +R, etc. */\r\r/** Channel mode +R - unidentified users cannot join\r */\rclass AChannel_R : public ModeHandler\r{\r public:\r AChannel_R(InspIRCd* Instance) : ModeHandler(Instance, 'R', 0, 0, false, MODETYPE_CHANNEL, false) { }\r\r ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)\r {\r              if (adding)\r            {\r                      if (!channel->IsModeSet('R'))\r                  {\r                              channel->SetMode('R',true);\r                            return MODEACTION_ALLOW;\r                       }\r              }\r              else\r           {\r                      if (channel->IsModeSet('R'))\r                   {\r                              channel->SetMode('R',false);\r                           return MODEACTION_ALLOW;\r                       }\r              }\r\r             return MODEACTION_DENY;\r        }\r};\r\r/** User mode +R - unidentified users cannot message\r */\rclass AUser_R : public ModeHandler\r{\r public:\r   AUser_R(InspIRCd* Instance) : ModeHandler(Instance, 'R', 0, 0, false, MODETYPE_USER, false) { }\r\r       ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)\r {\r              if (adding)\r            {\r                      if (!dest->IsModeSet('R'))\r                     {\r                              dest->SetMode('R',true);\r                               return MODEACTION_ALLOW;\r                       }\r              }\r              else\r           {\r                      if (dest->IsModeSet('R'))\r                      {\r                              dest->SetMode('R',false);\r                              return MODEACTION_ALLOW;\r                       }\r              }\r\r             return MODEACTION_DENY;\r        }\r};\r\r/** Channel mode +M - unidentified users cannot message channel\r */\rclass AChannel_M : public ModeHandler\r{\r public:\r     AChannel_M(InspIRCd* Instance) : ModeHandler(Instance, 'M', 0, 0, false, MODETYPE_CHANNEL, false) { }\r\r ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)\r {\r              if (adding)\r            {\r                      if (!channel->IsModeSet('M'))\r                  {\r                              channel->SetMode('M',true);\r                            return MODEACTION_ALLOW;\r                       }\r              }\r              else\r           {\r                      if (channel->IsModeSet('M'))\r                   {\r                              channel->SetMode('M',false);\r                           return MODEACTION_ALLOW;\r                       }\r              }\r\r             return MODEACTION_DENY;\r        }\r};\r\rclass ModuleServicesAccount : public Module\r{\r     \r      AChannel_R* m1;\r        AChannel_M* m2;\r        AUser_R* m3;\r public:\r  ModuleServicesAccount(InspIRCd* Me) : Module(Me)\r       {\r              \r               m1 = new AChannel_R(ServerInstance);\r           m2 = new AChannel_M(ServerInstance);\r           m3 = new AUser_R(ServerInstance);\r              if (!ServerInstance->AddMode(m1, 'R') || !ServerInstance->AddMode(m2, 'M') || !ServerInstance->AddMode(m3, 'R'))\r                       throw ModuleException("Could not add new modes!");\r     }\r\r     /* <- :twisted.oscnet.org 330 w00t2 w00t2 w00t :is logged in as */\r     virtual void OnWhois(userrec* source, userrec* dest)\r   {\r              std::string *account;\r          dest->GetExt("accountname", account);\r\r         if (account)\r           {\r                      ServerInstance->SendWhoisLine(source, dest, 330, "%s %s %s :is logged in as", source->nick, dest->nick, account->c_str());\r             }\r      }\r\r     void Implements(char* List)\r    {\r              List[I_OnWhois] = List[I_OnUserPreMessage] = List[I_OnUserPreNotice] = List[I_OnUserPreJoin] = 1;\r              List[I_OnSyncUserMetaData] = List[I_OnUserQuit] = List[I_OnCleanup] = List[I_OnDecodeMetaData] = 1;\r    }\r\r     virtual int OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)\r    {\r              std::string *account;\r\r         if (!IS_LOCAL(user))\r                   return 0;\r\r             user->GetExt("accountname", account);\r          \r               if (target_type == TYPE_CHANNEL)\r               {\r                      chanrec* c = (chanrec*)dest;\r                   \r                       if ((c->IsModeSet('M')) && (!account))\r                 {\r                              if ((ServerInstance->ULine(user->nick)) || (ServerInstance->ULine(user->server)))\r                              {\r                                      // user is ulined, can speak regardless\r                                        return 0;\r                              }\r\r                             // user messaging a +M channel and is not registered\r                           user->WriteServ("477 "+std::string(user->nick)+" "+std::string(c->name)+" :You need to be identified to a registered account to message this channel");\r                                return 1;\r                      }\r              }\r              if (target_type == TYPE_USER)\r          {\r                      userrec* u = (userrec*)dest;\r                   \r                       if ((u->modes['R'-65]) && (!account))\r                  {\r                              if ((ServerInstance->ULine(user->nick)) || (ServerInstance->ULine(user->server)))\r                              {\r                                      // user is ulined, can speak regardless\r                                        return 0;\r                              }\r\r                             // user messaging a +R user and is not registered\r                              user->WriteServ("477 "+std::string(user->nick)+" "+std::string(u->nick)+" :You need to be identified to a registered account to message this user");\r                           return 1;\r                      }\r              }\r              return 0;\r      }\r       \r      virtual int OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)\r     {\r              return OnUserPreMessage(user, dest, target_type, text, status, exempt_list);\r   }\r       \r      virtual int OnUserPreJoin(userrec* user, chanrec* chan, const char* cname, std::string &privs)\r {\r              std::string *account;\r          user->GetExt("accountname", account);\r          \r               if (chan)\r              {\r                      if (chan->IsModeSet('R'))\r                      {\r                              if (!account)\r                          {\r                                      if ((ServerInstance->ULine(user->nick)) || (ServerInstance->ULine(user->server)))\r                                      {\r                                              // user is ulined, won't be stopped from joining\r                                               return 0;\r                                      }\r                                      // joining a +R channel and not identified\r                                     user->WriteServ("477 "+std::string(user->nick)+" "+std::string(chan->name)+" :You need to be identified to a registered account to join this channel");\r                                        return 1;\r                              }\r                      }\r              }\r              return 0;\r      }\r      \r       // Whenever the linking module wants to send out data, but doesnt know what the data\r   // represents (e.g. it is metadata, added to a userrec or chanrec by a module) then\r    // this method is called. We should use the ProtoSendMetaData function after we've\r     // corrected decided how the data should look, to send the metadata on its way if\r      // it is ours.\r virtual void OnSyncUserMetaData(userrec* user, Module* proto, void* opaque, const std::string &extname, bool displayable)\r      {\r              // check if the linking module wants to know about OUR metadata\r                if (extname == "accountname")\r          {\r                      // check if this user has an swhois field to send\r                      std::string* account;\r                  user->GetExt("accountname", account);\r                  if (account)\r                   {\r                              // remove any accidental leading/trailing spaces\r                               trim(*account);\r\r                               // call this function in the linking module, let it format the data how it\r                             // sees fit, and send it on its way. We dont need or want to know how.\r                         proto->ProtoSendMetaData(opaque,TYPE_USER,user,extname,*account);\r                      }\r              }\r      }\r\r     // when a user quits, tidy up their metadata\r   virtual void OnUserQuit(userrec* user, const std::string &message, const std::string &oper_message)\r    {\r              std::string* account;\r          user->GetExt("accountname", account);\r          if (account)\r           {\r                      user->Shrink("accountname");\r                   delete account;\r                }\r      }\r\r     // if the module is unloaded, tidy up all our dangling metadata\r        virtual void OnCleanup(int target_type, void* item)\r    {\r              if (target_type == TYPE_USER)\r          {\r                      userrec* user = (userrec*)item;\r                        std::string* account;\r                  user->GetExt("accountname", account);\r                  if (account)\r                   {\r                              user->Shrink("accountname");\r                           delete account;\r                        }\r              }\r      }\r\r     // Whenever the linking module receives metadata from another server and doesnt know what\r      // to do with it (of course, hence the 'meta') it calls this method, and it is up to each\r      // module in turn to figure out if this metadata key belongs to them, and what they want\r       // to do with it.\r      // In our case we're only sending a single string around, so we just construct a std::string.\r  // Some modules will probably get much more complex and format more detailed structs and classes\r       // in a textual way for sending over the link.\r virtual void OnDecodeMetaData(int target_type, void* target, const std::string &extname, const std::string &extdata)\r   {\r              // check if its our metadata key, and its associated with a user\r               if ((target_type == TYPE_USER) && (extname == "accountname"))\r          {       \r                       userrec* dest = (userrec*)target;\r                      \r                       /* logging them out? */\r                        if (extdata.empty())\r                   {\r                              std::string* account;\r                          dest->GetExt("accountname", account);\r                          if (account)\r                           {\r                                      dest->Shrink("accountname");\r                                   delete account;\r                                }\r                      }\r                      else\r                   {\r                              // if they dont already have an accountname field, accept the remote server's\r                          std::string* text;\r                             if (!dest->GetExt("accountname", text))\r                                {\r                                      text = new std::string(extdata);\r                                       // remove any accidental leading/trailing spaces\r                                       trim(*text);\r                                   dest->Extend("accountname", text);\r                             }\r                      }\r              }\r      }\r\r     virtual ~ModuleServicesAccount()\r       {\r              ServerInstance->Modes->DelMode(m1);\r            ServerInstance->Modes->DelMode(m2);\r            ServerInstance->Modes->DelMode(m3);\r            DELETE(m1);\r            DELETE(m2);\r            DELETE(m3);\r    }\r      \r       virtual Version GetVersion()\r   {\r              return Version(1,1,0,0,VF_COMMON|VF_VENDOR,API_VERSION);\r       }\r};\r\rMODULE_INIT(ModuleServicesAccount)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+#include "hashcomp.h"
+
+/* $ModDesc: Povides support for ircu-style services accounts, including chmode +R, etc. */
+
+/** Channel mode +R - unidentified users cannot join
+ */
+class AChannel_R : public ModeHandler
+{
+ public:
+       AChannel_R(InspIRCd* Instance) : ModeHandler(Instance, 'R', 0, 0, false, MODETYPE_CHANNEL, false) { }
+
+       ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)
+       {
+               if (adding)
+               {
+                       if (!channel->IsModeSet('R'))
+                       {
+                               channel->SetMode('R',true);
+                               return MODEACTION_ALLOW;
+                       }
+               }
+               else
+               {
+                       if (channel->IsModeSet('R'))
+                       {
+                               channel->SetMode('R',false);
+                               return MODEACTION_ALLOW;
+                       }
+               }
+
+               return MODEACTION_DENY;
+       }
+};
+
+/** User mode +R - unidentified users cannot message
+ */
+class AUser_R : public ModeHandler
+{
+ public:
+       AUser_R(InspIRCd* Instance) : ModeHandler(Instance, 'R', 0, 0, false, MODETYPE_USER, false) { }
+
+       ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)
+       {
+               if (adding)
+               {
+                       if (!dest->IsModeSet('R'))
+                       {
+                               dest->SetMode('R',true);
+                               return MODEACTION_ALLOW;
+                       }
+               }
+               else
+               {
+                       if (dest->IsModeSet('R'))
+                       {
+                               dest->SetMode('R',false);
+                               return MODEACTION_ALLOW;
+                       }
+               }
+
+               return MODEACTION_DENY;
+       }
+};
+
+/** Channel mode +M - unidentified users cannot message channel
+ */
+class AChannel_M : public ModeHandler
+{
+ public:
+       AChannel_M(InspIRCd* Instance) : ModeHandler(Instance, 'M', 0, 0, false, MODETYPE_CHANNEL, false) { }
+
+       ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)
+       {
+               if (adding)
+               {
+                       if (!channel->IsModeSet('M'))
+                       {
+                               channel->SetMode('M',true);
+                               return MODEACTION_ALLOW;
+                       }
+               }
+               else
+               {
+                       if (channel->IsModeSet('M'))
+                       {
+                               channel->SetMode('M',false);
+                               return MODEACTION_ALLOW;
+                       }
+               }
+
+               return MODEACTION_DENY;
+       }
+};
+
+class ModuleServicesAccount : public Module
+{
+        
+       AChannel_R* m1;
+       AChannel_M* m2;
+       AUser_R* m3;
+ public:
+       ModuleServicesAccount(InspIRCd* Me) : Module(Me)
+       {
+               
+               m1 = new AChannel_R(ServerInstance);
+               m2 = new AChannel_M(ServerInstance);
+               m3 = new AUser_R(ServerInstance);
+               if (!ServerInstance->AddMode(m1, 'R') || !ServerInstance->AddMode(m2, 'M') || !ServerInstance->AddMode(m3, 'R'))
+                       throw ModuleException("Could not add new modes!");
+       }
+
+       /* <- :twisted.oscnet.org 330 w00t2 w00t2 w00t :is logged in as */
+       virtual void OnWhois(userrec* source, userrec* dest)
+       {
+               std::string *account;
+               dest->GetExt("accountname", account);
+
+               if (account)
+               {
+                       ServerInstance->SendWhoisLine(source, dest, 330, "%s %s %s :is logged in as", source->nick, dest->nick, account->c_str());
+               }
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnWhois] = List[I_OnUserPreMessage] = List[I_OnUserPreNotice] = List[I_OnUserPreJoin] = 1;
+               List[I_OnSyncUserMetaData] = List[I_OnUserQuit] = List[I_OnCleanup] = List[I_OnDecodeMetaData] = 1;
+       }
+
+       virtual int OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
+       {
+               std::string *account;
+
+               if (!IS_LOCAL(user))
+                       return 0;
+
+               user->GetExt("accountname", account);
+               
+               if (target_type == TYPE_CHANNEL)
+               {
+                       chanrec* c = (chanrec*)dest;
+                       
+                       if ((c->IsModeSet('M')) && (!account))
+                       {
+                               if ((ServerInstance->ULine(user->nick)) || (ServerInstance->ULine(user->server)))
+                               {
+                                       // user is ulined, can speak regardless
+                                       return 0;
+                               }
+
+                               // user messaging a +M channel and is not registered
+                               user->WriteServ("477 "+std::string(user->nick)+" "+std::string(c->name)+" :You need to be identified to a registered account to message this channel");
+                               return 1;
+                       }
+               }
+               if (target_type == TYPE_USER)
+               {
+                       userrec* u = (userrec*)dest;
+                       
+                       if ((u->modes['R'-65]) && (!account))
+                       {
+                               if ((ServerInstance->ULine(user->nick)) || (ServerInstance->ULine(user->server)))
+                               {
+                                       // user is ulined, can speak regardless
+                                       return 0;
+                               }
+
+                               // user messaging a +R user and is not registered
+                               user->WriteServ("477 "+std::string(user->nick)+" "+std::string(u->nick)+" :You need to be identified to a registered account to message this user");
+                               return 1;
+                       }
+               }
+               return 0;
+       }
+        
+       virtual int OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
+       {
+               return OnUserPreMessage(user, dest, target_type, text, status, exempt_list);
+       }
+        
+       virtual int OnUserPreJoin(userrec* user, chanrec* chan, const char* cname, std::string &privs)
+       {
+               std::string *account;
+               user->GetExt("accountname", account);
+               
+               if (chan)
+               {
+                       if (chan->IsModeSet('R'))
+                       {
+                               if (!account)
+                               {
+                                       if ((ServerInstance->ULine(user->nick)) || (ServerInstance->ULine(user->server)))
+                                       {
+                                               // user is ulined, won't be stopped from joining
+                                               return 0;
+                                       }
+                                       // joining a +R channel and not identified
+                                       user->WriteServ("477 "+std::string(user->nick)+" "+std::string(chan->name)+" :You need to be identified to a registered account to join this channel");
+                                       return 1;
+                               }
+                       }
+               }
+               return 0;
+       }
+       
+       // Whenever the linking module wants to send out data, but doesnt know what the data
+       // represents (e.g. it is metadata, added to a userrec or chanrec by a module) then
+       // this method is called. We should use the ProtoSendMetaData function after we've
+       // corrected decided how the data should look, to send the metadata on its way if
+       // it is ours.
+       virtual void OnSyncUserMetaData(userrec* user, Module* proto, void* opaque, const std::string &extname, bool displayable)
+       {
+               // check if the linking module wants to know about OUR metadata
+               if (extname == "accountname")
+               {
+                       // check if this user has an swhois field to send
+                       std::string* account;
+                       user->GetExt("accountname", account);
+                       if (account)
+                       {
+                               // remove any accidental leading/trailing spaces
+                               trim(*account);
+
+                               // call this function in the linking module, let it format the data how it
+                               // sees fit, and send it on its way. We dont need or want to know how.
+                               proto->ProtoSendMetaData(opaque,TYPE_USER,user,extname,*account);
+                       }
+               }
+       }
+
+       // when a user quits, tidy up their metadata
+       virtual void OnUserQuit(userrec* user, const std::string &message, const std::string &oper_message)
+       {
+               std::string* account;
+               user->GetExt("accountname", account);
+               if (account)
+               {
+                       user->Shrink("accountname");
+                       delete account;
+               }
+       }
+
+       // if the module is unloaded, tidy up all our dangling metadata
+       virtual void OnCleanup(int target_type, void* item)
+       {
+               if (target_type == TYPE_USER)
+               {
+                       userrec* user = (userrec*)item;
+                       std::string* account;
+                       user->GetExt("accountname", account);
+                       if (account)
+                       {
+                               user->Shrink("accountname");
+                               delete account;
+                       }
+               }
+       }
+
+       // Whenever the linking module receives metadata from another server and doesnt know what
+       // to do with it (of course, hence the 'meta') it calls this method, and it is up to each
+       // module in turn to figure out if this metadata key belongs to them, and what they want
+       // to do with it.
+       // In our case we're only sending a single string around, so we just construct a std::string.
+       // Some modules will probably get much more complex and format more detailed structs and classes
+       // in a textual way for sending over the link.
+       virtual void OnDecodeMetaData(int target_type, void* target, const std::string &extname, const std::string &extdata)
+       {
+               // check if its our metadata key, and its associated with a user
+               if ((target_type == TYPE_USER) && (extname == "accountname"))
+               {       
+                       userrec* dest = (userrec*)target;
+                       
+                       /* logging them out? */
+                       if (extdata.empty())
+                       {
+                               std::string* account;
+                               dest->GetExt("accountname", account);
+                               if (account)
+                               {
+                                       dest->Shrink("accountname");
+                                       delete account;
+                               }
+                       }
+                       else
+                       {
+                               // if they dont already have an accountname field, accept the remote server's
+                               std::string* text;
+                               if (!dest->GetExt("accountname", text))
+                               {
+                                       text = new std::string(extdata);
+                                       // remove any accidental leading/trailing spaces
+                                       trim(*text);
+                                       dest->Extend("accountname", text);
+                               }
+                       }
+               }
+       }
+
+       virtual ~ModuleServicesAccount()
+       {
+               ServerInstance->Modes->DelMode(m1);
+               ServerInstance->Modes->DelMode(m2);
+               ServerInstance->Modes->DelMode(m3);
+               DELETE(m1);
+               DELETE(m2);
+               DELETE(m3);
+       }
+       
+       virtual Version GetVersion()
+       {
+               return Version(1,1,0,0,VF_COMMON|VF_VENDOR,API_VERSION);
+       }
+};
+
+MODULE_INIT(ModuleServicesAccount)
index 833f8e684d6ca523159ea6f1458d7c050836ca2b..e69a944e745dc3b279da4622f17739ae0f7d084b 100644 (file)
@@ -1 +1,108 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r\r/* $ModDesc: Provides support for the SETHOST command */\r\r/** Handle /SETHOST\r */\rclass cmd_sethost : public command_t\r{\r private:\r   char* hostmap;\r public:\r        cmd_sethost (InspIRCd* Instance, char* hmap) : command_t(Instance,"SETHOST",'o',1), hostmap(hmap)\r      {\r              this->source = "m_sethost.so";\r         syntax = "<new-hostname>";\r     }\r\r     CmdResult Handle (const char** parameters, int pcnt, userrec *user)\r    {\r              size_t len = 0;\r                for (const char* x = parameters[0]; *x; x++, len++)\r            {\r                      if (!hostmap[(unsigned char)*x])\r                       {\r                              user->WriteServ("NOTICE "+std::string(user->nick)+" :*** SETHOST: Invalid characters in hostname");\r                            return CMD_FAILURE;\r                    }\r              }\r              if (len == 0)\r          {\r                      user->WriteServ("NOTICE %s :*** SETHOST: Host must be specified", user->nick);\r                 return CMD_FAILURE;\r            }\r              if (len > 64)\r          {\r                      user->WriteServ("NOTICE %s :*** SETHOST: Host too long",user->nick);\r                   return CMD_FAILURE;\r            }\r              if (user->ChangeDisplayedHost(parameters[0]))\r          {\r                      ServerInstance->WriteOpers(std::string(user->nick)+" used SETHOST to change their displayed host to "+user->dhost);\r                    return CMD_SUCCESS;\r            }\r\r             return CMD_FAILURE;\r    }\r};\r\r\rclass ModuleSetHost : public Module\r{\r   cmd_sethost* mycommand;\r        char hostmap[256];\r public:\r    ModuleSetHost(InspIRCd* Me)\r            : Module(Me)\r   {       \r               OnRehash(NULL,"");\r             mycommand = new cmd_sethost(ServerInstance, hostmap);\r          ServerInstance->AddCommand(mycommand);\r }\r\r     void Implements(char* List)\r    {\r              List[I_OnRehash] = 1;\r  }\r\r     void OnRehash(userrec* user, const std::string &parameter)\r     {\r              ConfigReader Conf(ServerInstance);\r             std::string hmap = Conf.ReadValue("hostname", "charmap", 0);\r\r          if (hmap.empty())\r                      hmap = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.-_/0123456789";\r\r          memset(&hostmap, 0, 255);\r              for (std::string::iterator n = hmap.begin(); n != hmap.end(); n++)\r                     hostmap[(unsigned char)*n] = 1;\r        }\r\r     virtual ~ModuleSetHost()\r       {\r      }\r      \r       virtual Version GetVersion()\r   {\r              return Version(1,1,0,1,VF_VENDOR,API_VERSION);\r }\r      \r};\r\rMODULE_INIT(ModuleSetHost)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+
+/* $ModDesc: Provides support for the SETHOST command */
+
+/** Handle /SETHOST
+ */
+class cmd_sethost : public command_t
+{
+ private:
+       char* hostmap;
+ public:
+       cmd_sethost (InspIRCd* Instance, char* hmap) : command_t(Instance,"SETHOST",'o',1), hostmap(hmap)
+       {
+               this->source = "m_sethost.so";
+               syntax = "<new-hostname>";
+       }
+
+       CmdResult Handle (const char** parameters, int pcnt, userrec *user)
+       {
+               size_t len = 0;
+               for (const char* x = parameters[0]; *x; x++, len++)
+               {
+                       if (!hostmap[(unsigned char)*x])
+                       {
+                               user->WriteServ("NOTICE "+std::string(user->nick)+" :*** SETHOST: Invalid characters in hostname");
+                               return CMD_FAILURE;
+                       }
+               }
+               if (len == 0)
+               {
+                       user->WriteServ("NOTICE %s :*** SETHOST: Host must be specified", user->nick);
+                       return CMD_FAILURE;
+               }
+               if (len > 64)
+               {
+                       user->WriteServ("NOTICE %s :*** SETHOST: Host too long",user->nick);
+                       return CMD_FAILURE;
+               }
+               if (user->ChangeDisplayedHost(parameters[0]))
+               {
+                       ServerInstance->WriteOpers(std::string(user->nick)+" used SETHOST to change their displayed host to "+user->dhost);
+                       return CMD_SUCCESS;
+               }
+
+               return CMD_FAILURE;
+       }
+};
+
+
+class ModuleSetHost : public Module
+{
+       cmd_sethost* mycommand;
+       char hostmap[256];
+ public:
+       ModuleSetHost(InspIRCd* Me)
+               : Module(Me)
+       {       
+               OnRehash(NULL,"");
+               mycommand = new cmd_sethost(ServerInstance, hostmap);
+               ServerInstance->AddCommand(mycommand);
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnRehash] = 1;
+       }
+
+       void OnRehash(userrec* user, const std::string &parameter)
+       {
+               ConfigReader Conf(ServerInstance);
+               std::string hmap = Conf.ReadValue("hostname", "charmap", 0);
+
+               if (hmap.empty())
+                       hmap = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.-_/0123456789";
+
+               memset(&hostmap, 0, 255);
+               for (std::string::iterator n = hmap.begin(); n != hmap.end(); n++)
+                       hostmap[(unsigned char)*n] = 1;
+       }
+
+       virtual ~ModuleSetHost()
+       {
+       }
+       
+       virtual Version GetVersion()
+       {
+               return Version(1,1,0,1,VF_VENDOR,API_VERSION);
+       }
+       
+};
+
+MODULE_INIT(ModuleSetHost)
index f512a1f599d602102e3c39bf4be98e97c4472887..3f33061cdd6c4ebc1f5d97ccb2fb392b4ff86b8a 100644 (file)
@@ -1 +1,83 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "modules.h"\r\r/* $ModDesc: Provides support for the SETIDENT command */\r\r/** Handle /SETIDENT\r */\rclass cmd_setident : public command_t\r{\r public:\r cmd_setident (InspIRCd* Instance) : command_t(Instance,"SETIDENT", 'o', 1)\r   {\r              this->source = "m_setident.so";\r                syntax = "<new-ident>";\r        }\r\r     CmdResult Handle(const char** parameters, int pcnt, userrec *user)\r     {\r              if (!*parameters[0])\r           {\r                      user->WriteServ("NOTICE %s :*** SETIDENT: Ident must be specified", user->nick);\r                       return CMD_FAILURE;\r            }\r              \r               if (strlen(parameters[0]) > IDENTMAX)\r          {\r                      user->WriteServ("NOTICE %s :*** SETIDENT: Ident is too long", user->nick);\r                     return CMD_FAILURE;\r            }\r              \r               if (!ServerInstance->IsIdent(parameters[0]))\r           {\r                      user->WriteServ("NOTICE %s :*** SETIDENT: Invalid characters in ident", user->nick);\r                   return CMD_FAILURE;\r            }\r              \r               user->ChangeIdent(parameters[0]);\r              ServerInstance->WriteOpers("%s used SETIDENT to change their ident to '%s'", user->nick, user->ident);\r\r                return CMD_SUCCESS;\r    }\r};\r\r\rclass ModuleSetIdent : public Module\r{\r  cmd_setident*   mycommand;\r     \r public:\r      ModuleSetIdent(InspIRCd* Me) : Module(Me)\r      {\r              \r               mycommand = new cmd_setident(ServerInstance);\r          ServerInstance->AddCommand(mycommand);\r }\r      \r       virtual ~ModuleSetIdent()\r      {\r      }\r      \r       virtual Version GetVersion()\r   {\r              return Version(1,1,0,0,VF_VENDOR,API_VERSION);\r }\r      \r};\r\r\rMODULE_INIT(ModuleSetIdent)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "modules.h"
+
+/* $ModDesc: Provides support for the SETIDENT command */
+
+/** Handle /SETIDENT
+ */
+class cmd_setident : public command_t
+{
+ public:
+ cmd_setident (InspIRCd* Instance) : command_t(Instance,"SETIDENT", 'o', 1)
+       {
+               this->source = "m_setident.so";
+               syntax = "<new-ident>";
+       }
+
+       CmdResult Handle(const char** parameters, int pcnt, userrec *user)
+       {
+               if (!*parameters[0])
+               {
+                       user->WriteServ("NOTICE %s :*** SETIDENT: Ident must be specified", user->nick);
+                       return CMD_FAILURE;
+               }
+               
+               if (strlen(parameters[0]) > IDENTMAX)
+               {
+                       user->WriteServ("NOTICE %s :*** SETIDENT: Ident is too long", user->nick);
+                       return CMD_FAILURE;
+               }
+               
+               if (!ServerInstance->IsIdent(parameters[0]))
+               {
+                       user->WriteServ("NOTICE %s :*** SETIDENT: Invalid characters in ident", user->nick);
+                       return CMD_FAILURE;
+               }
+               
+               user->ChangeIdent(parameters[0]);
+               ServerInstance->WriteOpers("%s used SETIDENT to change their ident to '%s'", user->nick, user->ident);
+
+               return CMD_SUCCESS;
+       }
+};
+
+
+class ModuleSetIdent : public Module
+{
+       cmd_setident*   mycommand;
+       
+ public:
+       ModuleSetIdent(InspIRCd* Me) : Module(Me)
+       {
+               
+               mycommand = new cmd_setident(ServerInstance);
+               ServerInstance->AddCommand(mycommand);
+       }
+       
+       virtual ~ModuleSetIdent()
+       {
+       }
+       
+       virtual Version GetVersion()
+       {
+               return Version(1,1,0,0,VF_VENDOR,API_VERSION);
+       }
+       
+};
+
+
+MODULE_INIT(ModuleSetIdent)
index 917368d7b3603333c5e151a9fde07115bc61d41d..e16369aa4b30e60afe4f17a4160dffcf9eb875f1 100644 (file)
@@ -1 +1,74 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r\r/* $ModDesc: Allows opers to set their idle time */\r\r/** Handle /SETIDLE\r */\rclass cmd_setidle : public command_t\r{\r public:\r cmd_setidle (InspIRCd* Instance) : command_t(Instance,"SETIDLE", 'o', 1)\r       {\r              this->source = "m_setidle.so";\r         syntax = "<duration>";\r }\r\r     CmdResult Handle (const char** parameters, int pcnt, userrec *user)\r    {\r              time_t idle = ServerInstance->Duration(parameters[0]);\r         if (idle < 1)\r          {\r                      user->WriteServ("948 %s :Invalid idle time.",user->nick);\r                      return CMD_FAILURE;\r            }\r              user->idle_lastmsg = (ServerInstance->Time() - idle);\r          // minor tweak - we cant have signon time shorter than our idle time!\r          if (user->signon > user->idle_lastmsg)\r                 user->signon = user->idle_lastmsg;\r             ServerInstance->WriteOpers(std::string(user->nick)+" used SETIDLE to set their idle time to "+ConvToStr(idle)+" seconds");\r             user->WriteServ("944 %s :Idle time set.",user->nick);\r\r         return CMD_LOCALONLY;\r  }\r};\r\r\rclass ModuleSetIdle : public Module\r{\r   cmd_setidle*    mycommand;\r public:\r    ModuleSetIdle(InspIRCd* Me)\r            : Module(Me)\r   {\r              \r               mycommand = new cmd_setidle(ServerInstance);\r           ServerInstance->AddCommand(mycommand);\r }\r      \r       virtual ~ModuleSetIdle()\r       {\r      }\r      \r       virtual Version GetVersion()\r   {\r              return Version(1,1,0,1,VF_VENDOR,API_VERSION);\r }\r};\r\rMODULE_INIT(ModuleSetIdle)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+
+/* $ModDesc: Allows opers to set their idle time */
+
+/** Handle /SETIDLE
+ */
+class cmd_setidle : public command_t
+{
+ public:
+       cmd_setidle (InspIRCd* Instance) : command_t(Instance,"SETIDLE", 'o', 1)
+       {
+               this->source = "m_setidle.so";
+               syntax = "<duration>";
+       }
+
+       CmdResult Handle (const char** parameters, int pcnt, userrec *user)
+       {
+               time_t idle = ServerInstance->Duration(parameters[0]);
+               if (idle < 1)
+               {
+                       user->WriteServ("948 %s :Invalid idle time.",user->nick);
+                       return CMD_FAILURE;
+               }
+               user->idle_lastmsg = (ServerInstance->Time() - idle);
+               // minor tweak - we cant have signon time shorter than our idle time!
+               if (user->signon > user->idle_lastmsg)
+                       user->signon = user->idle_lastmsg;
+               ServerInstance->WriteOpers(std::string(user->nick)+" used SETIDLE to set their idle time to "+ConvToStr(idle)+" seconds");
+               user->WriteServ("944 %s :Idle time set.",user->nick);
+
+               return CMD_LOCALONLY;
+       }
+};
+
+
+class ModuleSetIdle : public Module
+{
+       cmd_setidle*    mycommand;
+ public:
+       ModuleSetIdle(InspIRCd* Me)
+               : Module(Me)
+       {
+               
+               mycommand = new cmd_setidle(ServerInstance);
+               ServerInstance->AddCommand(mycommand);
+       }
+       
+       virtual ~ModuleSetIdle()
+       {
+       }
+       
+       virtual Version GetVersion()
+       {
+               return Version(1,1,0,1,VF_VENDOR,API_VERSION);
+       }
+};
+
+MODULE_INIT(ModuleSetIdle)
index 3f525622f15aa21b87bfc9e6cdc0fc4de54cec83..586c6f84e7b7d6da58d76a3d266bf2adb73b50a7 100644 (file)
@@ -1 +1,80 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r\r/* $ModDesc: Provides support for the SETNAME command */\r\r\r\rclass cmd_setname : public command_t\r{\r public:\r  cmd_setname (InspIRCd* Instance) : command_t(Instance,"SETNAME", 0, 1)\r {\r              this->source = "m_setname.so";\r         syntax = "<new-gecos>";\r        }\r\r     CmdResult Handle (const char** parameters, int pcnt, userrec *user)\r    {\r              if (!*parameters[0])\r           {\r                      user->WriteServ("NOTICE %s :*** SETNAME: GECOS must be specified", user->nick);\r                        return CMD_FAILURE;\r            }\r              \r               if (strlen(parameters[0]) > MAXGECOS)\r          {\r                      user->WriteServ("NOTICE %s :*** SETNAME: GECOS too long", user->nick);\r                 return CMD_FAILURE;\r            }\r              \r               if (user->ChangeName(parameters[0]))\r           {\r                      ServerInstance->WriteOpers("%s used SETNAME to change their GECOS to %s", user->nick, parameters[0]);\r                  return CMD_SUCCESS;\r            }\r\r             return CMD_SUCCESS;\r    }\r};\r\r\rclass ModuleSetName : public Module\r{\r   cmd_setname*    mycommand;\r public:\r    ModuleSetName(InspIRCd* Me)\r            : Module(Me)\r   {\r              \r               mycommand = new cmd_setname(ServerInstance);\r           ServerInstance->AddCommand(mycommand);\r }\r      \r       virtual ~ModuleSetName()\r       {\r      }\r      \r       virtual Version GetVersion()\r   {\r              return Version(1,1,0,1,VF_VENDOR,API_VERSION);\r }\r      \r};\r\rMODULE_INIT(ModuleSetName)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+
+/* $ModDesc: Provides support for the SETNAME command */
+
+
+
+class cmd_setname : public command_t
+{
+ public:
+       cmd_setname (InspIRCd* Instance) : command_t(Instance,"SETNAME", 0, 1)
+       {
+               this->source = "m_setname.so";
+               syntax = "<new-gecos>";
+       }
+
+       CmdResult Handle (const char** parameters, int pcnt, userrec *user)
+       {
+               if (!*parameters[0])
+               {
+                       user->WriteServ("NOTICE %s :*** SETNAME: GECOS must be specified", user->nick);
+                       return CMD_FAILURE;
+               }
+               
+               if (strlen(parameters[0]) > MAXGECOS)
+               {
+                       user->WriteServ("NOTICE %s :*** SETNAME: GECOS too long", user->nick);
+                       return CMD_FAILURE;
+               }
+               
+               if (user->ChangeName(parameters[0]))
+               {
+                       ServerInstance->WriteOpers("%s used SETNAME to change their GECOS to %s", user->nick, parameters[0]);
+                       return CMD_SUCCESS;
+               }
+
+               return CMD_SUCCESS;
+       }
+};
+
+
+class ModuleSetName : public Module
+{
+       cmd_setname*    mycommand;
+ public:
+       ModuleSetName(InspIRCd* Me)
+               : Module(Me)
+       {
+               
+               mycommand = new cmd_setname(ServerInstance);
+               ServerInstance->AddCommand(mycommand);
+       }
+       
+       virtual ~ModuleSetName()
+       {
+       }
+       
+       virtual Version GetVersion()
+       {
+               return Version(1,1,0,1,VF_VENDOR,API_VERSION);
+       }
+       
+};
+
+MODULE_INIT(ModuleSetName)
index 0dfef40b9706bf383169c638c97e68d575196989..547e7655cd24359a57b8e8879f48750c7fa24622 100644 (file)
@@ -1 +1,296 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r/* m_sha256 - Based on m_opersha256 written by Special <john@yarbbles.com>\r * Modified and improved by Craig Edwards, December 2006.\r *\r *\r * FIPS 180-2 SHA-224/256/384/512 implementation\r * Last update: 05/23/2005\r * Issue date:  04/30/2005\r *\r * Copyright (C) 2005 Olivier Gay <olivier.gay@a3.epfl.ch>\r * All rights reserved.\r *\r * Redistribution and use in source and binary forms, with or without\r * modification, are permitted provided that the following conditions\r * are met:\r * 1. Redistributions of source code must retain the above copyright\r *    notice, this list of conditions and the following disclaimer.\r * 2. Redistributions in binary form must reproduce the above copyright\r *    notice, this list of conditions and the following disclaimer in the\r *    documentation and/or other materials provided with the distribution.\r * 3. Neither the name of the project nor the names of its contributors\r *    may be used to endorse or promote products derived from this software\r *    without specific prior written permission.\r *\r * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND\r * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE\r * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\r * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\r * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\r * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\r * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\r * SUCH DAMAGE.\r */\r\r/* $ModDesc: Allows for SHA-256 encrypted oper passwords */\r/* $ModDep: m_hash.h */\r\r#include "inspircd.h"\r#ifdef HAS_STDINT\r#include <stdint.h>\r#endif\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r#include "m_hash.h"\r\r#ifndef HAS_STDINT\rtypedef unsigned int uint32_t;\r#endif\r\r/** An sha 256 context, used by m_opersha256\r */\rclass SHA256Context : public classbase\r{\r public:\r        unsigned int tot_len;\r  unsigned int len;\r      unsigned char block[2 * SHA256_BLOCK_SIZE];\r    uint32_t h[8];\r};\r\r#define SHFR(x, n)    (x >> n)\r#define ROTR(x, n)   ((x >> n) | (x << ((sizeof(x) << 3) - n)))\r#define ROTL(x, n)   ((x << n) | (x >> ((sizeof(x) << 3) - n)))\r#define CH(x, y, z)  ((x & y) ^ (~x & z))\r#define MAJ(x, y, z) ((x & y) ^ (x & z) ^ (y & z))\r\r#define SHA256_F1(x) (ROTR(x,  2) ^ ROTR(x, 13) ^ ROTR(x, 22))\r#define SHA256_F2(x) (ROTR(x,  6) ^ ROTR(x, 11) ^ ROTR(x, 25))\r#define SHA256_F3(x) (ROTR(x,  7) ^ ROTR(x, 18) ^ SHFR(x,  3))\r#define SHA256_F4(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHFR(x, 10))\r\r#define UNPACK32(x, str)                  \\r{                                            \\r        *((str) + 3) = (uint8_t) ((x)      );      \\r   *((str) + 2) = (uint8_t) ((x) >>  8);      \\r   *((str) + 1) = (uint8_t) ((x) >> 16);      \\r   *((str) + 0) = (uint8_t) ((x) >> 24);      \\r}\r\r#define PACK32(str, x)                   \\r{                                          \\r        *(x) = ((uint32_t) *((str) + 3)      )     \\r   | ((uint32_t) *((str) + 2) <<  8)     \\r        | ((uint32_t) *((str) + 1) << 16)     \\r        | ((uint32_t) *((str) + 0) << 24);    \\r}\r\r/* Macros used for loops unrolling */\r\r#define SHA256_SCR(i)                   \\r{                                         \\r        w[i] =  SHA256_F4(w[i - 2]) + w[i - 7]     \\r   + SHA256_F3(w[i - 15]) + w[i - 16];  \\r}\r\rconst unsigned int sha256_h0[8] =\r{\r  0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,\r        0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19\r};\r\ruint32_t sha256_k[64] =\r{\r   0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,\r        0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,\r        0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,\r        0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,\r        0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,\r        0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,\r        0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,\r        0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,\r        0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,\r        0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,\r        0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,\r        0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,\r        0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,\r        0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,\r        0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,\r        0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2\r};\r\rclass ModuleSHA256 : public Module\r{\r        void SHA256Init(SHA256Context *ctx, const unsigned int* key)\r   {\r              if (key)\r               {\r                      for (int i = 0; i < 8; i++)\r                            ctx->h[i] = key[i];\r            }\r              else\r           {\r                      for (int i = 0; i < 8; i++)\r                            ctx->h[i] = sha256_h0[i];\r              }\r              ctx->len = 0;\r          ctx->tot_len = 0;\r      }\r\r     void SHA256Transform(SHA256Context *ctx, unsigned char *message, unsigned int block_nb)\r        {\r              uint32_t w[64];\r                uint32_t wv[8];\r                unsigned char *sub_block;\r              for (unsigned int i = 1; i <= block_nb; i++)\r           {\r                      int j;\r                 sub_block = message + ((i - 1) << 6);\r  \r                       for (j = 0; j < 16; j++)\r                               PACK32(&sub_block[j << 2], &w[j]);\r                     for (j = 16; j < 64; j++)\r                              SHA256_SCR(j);\r                 for (j = 0; j < 8; j++)\r                                wv[j] = ctx->h[j];\r                     for (j = 0; j < 64; j++)\r                       {\r                              uint32_t t1 = wv[7] + SHA256_F2(wv[4]) + CH(wv[4], wv[5], wv[6]) + sha256_k[j] + w[j];\r                         uint32_t t2 = SHA256_F1(wv[0]) + MAJ(wv[0], wv[1], wv[2]);\r                             wv[7] = wv[6];\r                         wv[6] = wv[5];\r                         wv[5] = wv[4];\r                         wv[4] = wv[3] + t1;\r                            wv[3] = wv[2];\r                         wv[2] = wv[1];\r                         wv[1] = wv[0];\r                         wv[0] = t1 + t2;\r                       }\r                      for (j = 0; j < 8; j++)\r                                ctx->h[j] += wv[j];\r            }\r      }\r      \r       void SHA256Update(SHA256Context *ctx, unsigned char *message, unsigned int len)\r        {\r              unsigned int rem_len = SHA256_BLOCK_SIZE - ctx->len;\r           memcpy(&ctx->block[ctx->len], message, rem_len);\r               if (ctx->len + len < SHA256_BLOCK_SIZE)\r                {\r                      ctx->len += len;\r                       return;\r                }\r              unsigned int new_len = len - rem_len;\r          unsigned int block_nb = new_len / SHA256_BLOCK_SIZE;\r           unsigned char *shifted_message = message + rem_len;\r            SHA256Transform(ctx, ctx->block, 1);\r           SHA256Transform(ctx, shifted_message, block_nb);\r               rem_len = new_len % SHA256_BLOCK_SIZE;\r         memcpy(ctx->block, &shifted_message[block_nb << 6],rem_len);\r           ctx->len = rem_len;\r            ctx->tot_len += (block_nb + 1) << 6;\r   }\r      \r       void SHA256Final(SHA256Context *ctx, unsigned char *digest)\r    {\r              unsigned int block_nb = (1 + ((SHA256_BLOCK_SIZE - 9) < (ctx->len % SHA256_BLOCK_SIZE)));\r              unsigned int len_b = (ctx->tot_len + ctx->len) << 3;\r           unsigned int pm_len = block_nb << 6;\r           memset(ctx->block + ctx->len, 0, pm_len - ctx->len);\r           ctx->block[ctx->len] = 0x80;\r           UNPACK32(len_b, ctx->block + pm_len - 4);\r              SHA256Transform(ctx, ctx->block, block_nb);\r            for (int i = 0 ; i < 8; i++)\r                   UNPACK32(ctx->h[i], &digest[i << 2]);\r  }\r      \r       void SHA256(const char *src, char *dest, int len, const char* hxc, const unsigned int* key = NULL)\r     {\r              // Generate the hash\r           unsigned char bytehash[SHA256_DIGEST_SIZE];\r            SHA256Context ctx;\r             SHA256Init(&ctx, key);\r         SHA256Update(&ctx, (unsigned char *)src, (unsigned int)len);\r           SHA256Final(&ctx, bytehash);\r           // Convert it to hex\r           for (int i = 0, j = 0; i < SHA256_DIGEST_SIZE; i++)\r            {\r                      dest[j++] = hxc[bytehash[i] / 16];\r                     dest[j++] = hxc[bytehash[i] % 16];\r                     dest[j] = '\0';\r                }\r      }\r\r     unsigned int* key;\r     char* chars;\r\r public:\r\r        ModuleSHA256(InspIRCd* Me) : Module(Me), key(NULL), chars(NULL)\r        {\r              ServerInstance->PublishInterface("HashRequest", this);\r }\r\r     virtual ~ModuleSHA256()\r        {\r              ServerInstance->UnpublishInterface("HashRequest", this);\r       }\r\r     void Implements(char *List)\r    {\r              List[I_OnRequest] = 1;\r }\r\r     virtual char* OnRequest(Request* request)\r      {\r              HashRequest* SHA = (HashRequest*)request;\r              if (strcmp("KEY", request->GetId()) == 0)\r              {\r                      this->key = (unsigned int*)SHA->GetKeyData();\r          }\r              else if (strcmp("HEX", request->GetId()) == 0)\r         {\r                      this->chars = (char*)SHA->GetOutputs();\r                }\r              else if (strcmp("SUM", request->GetId()) == 0)\r         {\r                      static char data[MAXBUF];\r                      SHA256((const char*)SHA->GetHashData(), data, strlen(SHA->GetHashData()), chars ? chars : "0123456789abcdef", key);\r                    return data;\r           }\r              else if (strcmp("NAME", request->GetId()) == 0)\r                {\r                      return "sha256";\r               }\r              else if (strcmp("RESET", request->GetId()) == 0)\r               {\r                      this->chars = NULL;\r                    this->key = NULL;\r              }\r              return NULL;\r   }\r\r     virtual Version GetVersion()\r   {\r              return Version(1, 1, 0, 1, VF_VENDOR|VF_SERVICEPROVIDER, API_VERSION);\r }\r};\r\rMODULE_INIT(ModuleSHA256)\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+/* m_sha256 - Based on m_opersha256 written by Special <john@yarbbles.com>
+ * Modified and improved by Craig Edwards, December 2006.
+ *
+ *
+ * FIPS 180-2 SHA-224/256/384/512 implementation
+ * Last update: 05/23/2005
+ * Issue date:  04/30/2005
+ *
+ * Copyright (C) 2005 Olivier Gay <olivier.gay@a3.epfl.ch>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* $ModDesc: Allows for SHA-256 encrypted oper passwords */
+/* $ModDep: m_hash.h */
+
+#include "inspircd.h"
+#ifdef HAS_STDINT
+#include <stdint.h>
+#endif
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+#include "m_hash.h"
+
+#ifndef HAS_STDINT
+typedef unsigned int uint32_t;
+#endif
+
+/** An sha 256 context, used by m_opersha256
+ */
+class SHA256Context : public classbase
+{
+ public:
+       unsigned int tot_len;
+       unsigned int len;
+       unsigned char block[2 * SHA256_BLOCK_SIZE];
+       uint32_t h[8];
+};
+
+#define SHFR(x, n)    (x >> n)
+#define ROTR(x, n)   ((x >> n) | (x << ((sizeof(x) << 3) - n)))
+#define ROTL(x, n)   ((x << n) | (x >> ((sizeof(x) << 3) - n)))
+#define CH(x, y, z)  ((x & y) ^ (~x & z))
+#define MAJ(x, y, z) ((x & y) ^ (x & z) ^ (y & z))
+
+#define SHA256_F1(x) (ROTR(x,  2) ^ ROTR(x, 13) ^ ROTR(x, 22))
+#define SHA256_F2(x) (ROTR(x,  6) ^ ROTR(x, 11) ^ ROTR(x, 25))
+#define SHA256_F3(x) (ROTR(x,  7) ^ ROTR(x, 18) ^ SHFR(x,  3))
+#define SHA256_F4(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHFR(x, 10))
+
+#define UNPACK32(x, str)                      \
+{                                            \
+       *((str) + 3) = (uint8_t) ((x)      );      \
+       *((str) + 2) = (uint8_t) ((x) >>  8);      \
+       *((str) + 1) = (uint8_t) ((x) >> 16);      \
+       *((str) + 0) = (uint8_t) ((x) >> 24);      \
+}
+
+#define PACK32(str, x)                  \
+{                                            \
+       *(x) = ((uint32_t) *((str) + 3)      )     \
+       | ((uint32_t) *((str) + 2) <<  8)     \
+       | ((uint32_t) *((str) + 1) << 16)     \
+       | ((uint32_t) *((str) + 0) << 24);    \
+}
+
+/* Macros used for loops unrolling */
+
+#define SHA256_SCR(i)                    \
+{                                            \
+       w[i] =  SHA256_F4(w[i - 2]) + w[i - 7]     \
+       + SHA256_F3(w[i - 15]) + w[i - 16];  \
+}
+
+const unsigned int sha256_h0[8] =
+{
+       0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
+       0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
+};
+
+uint32_t sha256_k[64] =
+{
+       0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
+       0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
+       0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
+       0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
+       0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
+       0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
+       0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
+       0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
+       0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
+       0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
+       0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
+       0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
+       0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
+       0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
+       0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
+       0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
+};
+
+class ModuleSHA256 : public Module
+{
+       void SHA256Init(SHA256Context *ctx, const unsigned int* key)
+       {
+               if (key)
+               {
+                       for (int i = 0; i < 8; i++)
+                               ctx->h[i] = key[i];
+               }
+               else
+               {
+                       for (int i = 0; i < 8; i++)
+                               ctx->h[i] = sha256_h0[i];
+               }
+               ctx->len = 0;
+               ctx->tot_len = 0;
+       }
+
+       void SHA256Transform(SHA256Context *ctx, unsigned char *message, unsigned int block_nb)
+       {
+               uint32_t w[64];
+               uint32_t wv[8];
+               unsigned char *sub_block;
+               for (unsigned int i = 1; i <= block_nb; i++)
+               {
+                       int j;
+                       sub_block = message + ((i - 1) << 6);
+       
+                       for (j = 0; j < 16; j++)
+                               PACK32(&sub_block[j << 2], &w[j]);
+                       for (j = 16; j < 64; j++)
+                               SHA256_SCR(j);
+                       for (j = 0; j < 8; j++)
+                               wv[j] = ctx->h[j];
+                       for (j = 0; j < 64; j++)
+                       {
+                               uint32_t t1 = wv[7] + SHA256_F2(wv[4]) + CH(wv[4], wv[5], wv[6]) + sha256_k[j] + w[j];
+                               uint32_t t2 = SHA256_F1(wv[0]) + MAJ(wv[0], wv[1], wv[2]);
+                               wv[7] = wv[6];
+                               wv[6] = wv[5];
+                               wv[5] = wv[4];
+                               wv[4] = wv[3] + t1;
+                               wv[3] = wv[2];
+                               wv[2] = wv[1];
+                               wv[1] = wv[0];
+                               wv[0] = t1 + t2;
+                       }
+                       for (j = 0; j < 8; j++)
+                               ctx->h[j] += wv[j];
+               }
+       }
+       
+       void SHA256Update(SHA256Context *ctx, unsigned char *message, unsigned int len)
+       {
+               unsigned int rem_len = SHA256_BLOCK_SIZE - ctx->len;
+               memcpy(&ctx->block[ctx->len], message, rem_len);
+               if (ctx->len + len < SHA256_BLOCK_SIZE)
+               {
+                       ctx->len += len;
+                       return;
+               }
+               unsigned int new_len = len - rem_len;
+               unsigned int block_nb = new_len / SHA256_BLOCK_SIZE;
+               unsigned char *shifted_message = message + rem_len;
+               SHA256Transform(ctx, ctx->block, 1);
+               SHA256Transform(ctx, shifted_message, block_nb);
+               rem_len = new_len % SHA256_BLOCK_SIZE;
+               memcpy(ctx->block, &shifted_message[block_nb << 6],rem_len);
+               ctx->len = rem_len;
+               ctx->tot_len += (block_nb + 1) << 6;
+       }
+       
+       void SHA256Final(SHA256Context *ctx, unsigned char *digest)
+       {
+               unsigned int block_nb = (1 + ((SHA256_BLOCK_SIZE - 9) < (ctx->len % SHA256_BLOCK_SIZE)));
+               unsigned int len_b = (ctx->tot_len + ctx->len) << 3;
+               unsigned int pm_len = block_nb << 6;
+               memset(ctx->block + ctx->len, 0, pm_len - ctx->len);
+               ctx->block[ctx->len] = 0x80;
+               UNPACK32(len_b, ctx->block + pm_len - 4);
+               SHA256Transform(ctx, ctx->block, block_nb);
+               for (int i = 0 ; i < 8; i++)
+                       UNPACK32(ctx->h[i], &digest[i << 2]);
+       }
+       
+       void SHA256(const char *src, char *dest, int len, const char* hxc, const unsigned int* key = NULL)
+       {
+               // Generate the hash
+               unsigned char bytehash[SHA256_DIGEST_SIZE];
+               SHA256Context ctx;
+               SHA256Init(&ctx, key);
+               SHA256Update(&ctx, (unsigned char *)src, (unsigned int)len);
+               SHA256Final(&ctx, bytehash);
+               // Convert it to hex
+               for (int i = 0, j = 0; i < SHA256_DIGEST_SIZE; i++)
+               {
+                       dest[j++] = hxc[bytehash[i] / 16];
+                       dest[j++] = hxc[bytehash[i] % 16];
+                       dest[j] = '\0';
+               }
+       }
+
+       unsigned int* key;
+       char* chars;
+
+ public:
+
+       ModuleSHA256(InspIRCd* Me) : Module(Me), key(NULL), chars(NULL)
+       {
+               ServerInstance->PublishInterface("HashRequest", this);
+       }
+
+       virtual ~ModuleSHA256()
+       {
+               ServerInstance->UnpublishInterface("HashRequest", this);
+       }
+
+       void Implements(char *List)
+       {
+               List[I_OnRequest] = 1;
+       }
+
+       virtual char* OnRequest(Request* request)
+       {
+               HashRequest* SHA = (HashRequest*)request;
+               if (strcmp("KEY", request->GetId()) == 0)
+               {
+                       this->key = (unsigned int*)SHA->GetKeyData();
+               }
+               else if (strcmp("HEX", request->GetId()) == 0)
+               {
+                       this->chars = (char*)SHA->GetOutputs();
+               }
+               else if (strcmp("SUM", request->GetId()) == 0)
+               {
+                       static char data[MAXBUF];
+                       SHA256((const char*)SHA->GetHashData(), data, strlen(SHA->GetHashData()), chars ? chars : "0123456789abcdef", key);
+                       return data;
+               }
+               else if (strcmp("NAME", request->GetId()) == 0)
+               {
+                       return "sha256";
+               }
+               else if (strcmp("RESET", request->GetId()) == 0)
+               {
+                       this->chars = NULL;
+                       this->key = NULL;
+               }
+               return NULL;
+       }
+
+       virtual Version GetVersion()
+       {
+               return Version(1, 1, 0, 1, VF_VENDOR|VF_SERVICEPROVIDER, API_VERSION);
+       }
+};
+
+MODULE_INIT(ModuleSHA256)
+
index 67696281894371be4efc72d51f5add13e86ed14a..cb6a0ffb028ec26733f49c655c562f1aa5635e8d 100644 (file)
@@ -1 +1,109 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r\r/* $ModDesc: Allows opers to set +W to see when a user uses WHOIS on them */\r\r/** Handle user mode +W\r */\rclass SeeWhois : public ModeHandler\r{\r public:\r     SeeWhois(InspIRCd* Instance) : ModeHandler(Instance, 'W', 0, 0, false, MODETYPE_USER, true) { }\r\r       ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)\r {\r              /* Only opers can change other users modes */\r          if (source != dest)\r                    return MODEACTION_DENY;\r\r               if (adding)\r            {\r                      if (!dest->IsModeSet('W'))\r                     {\r                              dest->SetMode('W',true);\r                               return MODEACTION_ALLOW;\r                       }\r              }\r              else\r           {\r                      if (dest->IsModeSet('W'))\r                      {\r                              dest->SetMode('W',false);\r                              return MODEACTION_ALLOW;\r                       }\r              }\r\r             return MODEACTION_DENY;\r        }\r};\r\rclass ModuleShowwhois : public Module\r{\r  \r       SeeWhois* sw;\r\r public:\r\r       ModuleShowwhois(InspIRCd* Me) : Module(Me)\r     {\r              \r               sw = new SeeWhois(ServerInstance);\r             if (!ServerInstance->AddMode(sw, 'W'))\r                 throw ModuleException("Could not add new modes!");\r     }\r\r     ~ModuleShowwhois()\r     {\r              ServerInstance->Modes->DelMode(sw);\r            DELETE(sw);\r    }\r\r     void Implements(char* List)\r    {\r              List[I_OnWhois] = 1;\r   }\r\r     virtual Version GetVersion()\r   {\r              return Version(1,1,0,3,VF_COMMON|VF_VENDOR,API_VERSION);\r       }\r\r     virtual void OnWhois(userrec* source, userrec* dest)\r   {\r              if ((dest->IsModeSet('W')) && (source != dest))\r                {\r                      if (IS_LOCAL(dest))\r                    {\r                              dest->WriteServ("NOTICE %s :*** %s (%s@%s) did a /whois on you.",dest->nick,source->nick,source->ident,source->host);\r                  }\r                      else\r                   {\r                              std::deque<std::string> params;\r                                params.push_back(dest->nick);\r                          std::string msg = ":";\r                         msg = msg + dest->server + " NOTICE " + dest->nick + " :*** " + source->nick + " (" + source->ident + "@" + source->host + ") did a /whois on you.";\r                           params.push_back(msg);\r                         Event ev((char *) &params, NULL, "send_push");\r                         ev.Send(ServerInstance);\r                       }\r              }\r      }\r\r};\r\rMODULE_INIT(ModuleShowwhois)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+
+/* $ModDesc: Allows opers to set +W to see when a user uses WHOIS on them */
+
+/** Handle user mode +W
+ */
+class SeeWhois : public ModeHandler
+{
+ public:
+       SeeWhois(InspIRCd* Instance) : ModeHandler(Instance, 'W', 0, 0, false, MODETYPE_USER, true) { }
+
+       ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)
+       {
+               /* Only opers can change other users modes */
+               if (source != dest)
+                       return MODEACTION_DENY;
+
+               if (adding)
+               {
+                       if (!dest->IsModeSet('W'))
+                       {
+                               dest->SetMode('W',true);
+                               return MODEACTION_ALLOW;
+                       }
+               }
+               else
+               {
+                       if (dest->IsModeSet('W'))
+                       {
+                               dest->SetMode('W',false);
+                               return MODEACTION_ALLOW;
+                       }
+               }
+
+               return MODEACTION_DENY;
+       }
+};
+
+class ModuleShowwhois : public Module
+{
+       
+       SeeWhois* sw;
+
+ public:
+
+       ModuleShowwhois(InspIRCd* Me) : Module(Me)
+       {
+               
+               sw = new SeeWhois(ServerInstance);
+               if (!ServerInstance->AddMode(sw, 'W'))
+                       throw ModuleException("Could not add new modes!");
+       }
+
+       ~ModuleShowwhois()
+       {
+               ServerInstance->Modes->DelMode(sw);
+               DELETE(sw);
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnWhois] = 1;
+       }
+
+       virtual Version GetVersion()
+       {
+               return Version(1,1,0,3,VF_COMMON|VF_VENDOR,API_VERSION);
+       }
+
+       virtual void OnWhois(userrec* source, userrec* dest)
+       {
+               if ((dest->IsModeSet('W')) && (source != dest))
+               {
+                       if (IS_LOCAL(dest))
+                       {
+                               dest->WriteServ("NOTICE %s :*** %s (%s@%s) did a /whois on you.",dest->nick,source->nick,source->ident,source->host);
+                       }
+                       else
+                       {
+                               std::deque<std::string> params;
+                               params.push_back(dest->nick);
+                               std::string msg = ":";
+                               msg = msg + dest->server + " NOTICE " + dest->nick + " :*** " + source->nick + " (" + source->ident + "@" + source->host + ") did a /whois on you.";
+                               params.push_back(msg);
+                               Event ev((char *) &params, NULL, "send_push");
+                               ev.Send(ServerInstance);
+                       }
+               }
+       }
+
+};
+
+MODULE_INIT(ModuleShowwhois)
index 3becb06f2276a50a5efb9f9d1624c9aae51bbc1f..b0568905676a0e337a9b704c844f1455c34c7ac4 100644 (file)
@@ -1 +1,215 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r#include "hashcomp.h"\r#include "wildcard.h"\r\r/* $ModDesc: Provides support for the /SILENCE command */\r\r// This typedef holds a silence list. Each user may or may not have a\r// silencelist, if a silence list is empty for a user, he/she does not\r// have one of these structures associated with their user record.\rtypedef std::map<irc::string, time_t> silencelist;\r\rclass cmd_silence : public command_t\r{\r    unsigned int& maxsilence;\r public:\r     cmd_silence (InspIRCd* Instance, unsigned int &max) : command_t(Instance,"SILENCE", 0, 0), maxsilence(max)\r     {\r              this->source = "m_silence.so";\r         syntax = "{[+|-]<mask>}";\r      }\r\r     CmdResult Handle (const char** parameters, int pcnt, userrec *user)\r    {\r              if (!pcnt)\r             {\r                      // no parameters, show the current silence list.\r                       // Use Extensible::GetExt to fetch the silence list\r                    silencelist* sl;\r                       user->GetExt("silence_list", sl);\r                      // if the user has a silence list associated with their user record, show it\r                   if (sl)\r                        {\r                              for (silencelist::const_iterator c = sl->begin(); c != sl->end(); c++)\r                         {\r                                      user->WriteServ("271 %s %s %s :%lu",user->nick, user->nick, c->first.c_str(), (unsigned long)c->second);\r                               }\r                      }\r                      user->WriteServ("272 %s :End of Silence List",user->nick);\r\r                    return CMD_SUCCESS;\r            }\r              else if (pcnt > 0)\r             {\r                      // one or more parameters, add or delete entry from the list (only the first parameter is used)\r                        std::string mask = parameters[0] + 1;\r                  char action = *parameters[0];\r                  \r                       if (!mask.length())\r                    {\r                              // 'SILENCE +' or 'SILENCE -', assume *!*@*\r                            mask = "*!*@*";\r                        }\r                      \r                       ModeParser::CleanMask(mask);\r\r                  if (action == '-')\r                     {\r                              // fetch their silence list\r                            silencelist* sl;\r                               user->GetExt("silence_list", sl);\r                              // does it contain any entries and does it exist?\r                              if (sl)\r                                {\r                                      silencelist::iterator i = sl->find(mask.c_str());\r                                      if (i != sl->end())\r                                    {\r                                              sl->erase(i);\r                                          user->WriteServ("950 %s %s :Removed %s from silence list",user->nick, user->nick, mask.c_str());\r                                               if (!sl->size())\r                                               {\r                                                      // tidy up -- if a user's list is empty, theres no use having it\r                                                       // hanging around in the user record.\r                                                  DELETE(sl);\r                                                    user->Shrink("silence_list");\r                                          }\r                                      }\r                                      else\r                                           user->WriteServ("952 %s %s :%s does not exist on your silence list",user->nick, user->nick, mask.c_str());\r                             }\r                      }\r                      else if (action == '+')\r                        {\r                              // fetch the user's current silence list\r                               silencelist* sl;\r                               user->GetExt("silence_list", sl);\r                              // what, they dont have one??? WE'RE ALL GONNA DIE! ...no, we just create an empty one.\r                                if (!sl)\r                               {\r                                      sl = new silencelist;\r                                  user->Extend("silence_list", sl);\r                              }\r                              silencelist::iterator n = sl->find(mask.c_str());\r                              if (n != sl->end())\r                            {\r                                      user->WriteServ("952 %s %s :%s is already on your silence list",user->nick, user->nick, mask.c_str());\r                                 return CMD_FAILURE;\r                            }\r                              if (sl->size() >= maxsilence)\r                          {\r                                      user->WriteServ("952 %s %s :Your silence list is full",user->nick, user->nick, mask.c_str());\r                                  return CMD_FAILURE;\r                            }\r                              sl->insert(std::make_pair<irc::string, time_t>(mask.c_str(), ServerInstance->Time()));\r                         user->WriteServ("951 %s %s :Added %s to silence list",user->nick, user->nick, mask.c_str());\r                           return CMD_SUCCESS;\r                    }\r              }\r              return CMD_SUCCESS;\r    }\r};\r\rclass ModuleSilence : public Module\r{\r    \r       cmd_silence* mycommand;\r        unsigned int maxsilence;\r public:\r \r    ModuleSilence(InspIRCd* Me)\r            : Module(Me), maxsilence(32)\r   {\r              OnRehash(NULL, "");\r            mycommand = new cmd_silence(ServerInstance, maxsilence);\r               ServerInstance->AddCommand(mycommand);\r }\r\r     void Implements(char* List)\r    {\r              List[I_OnRehash] = List[I_OnUserQuit] = List[I_On005Numeric] = List[I_OnUserPreNotice] = List[I_OnUserPreMessage] = 1;\r }\r\r     virtual void OnRehash(userrec* user, const std::string &parameter)\r     {\r              ConfigReader Conf(ServerInstance);\r             maxsilence = Conf.ReadInteger("silence", "maxentries", 0, true);\r               if (!maxsilence)\r                       maxsilence = 32;\r       }\r\r     virtual void OnUserQuit(userrec* user, const std::string &reason, const std::string &oper_message)\r     {\r              // when the user quits tidy up any silence list they might have just to keep things tidy\r               // and to prevent a HONKING BIG MEMORY LEAK!\r           silencelist* sl;\r               user->GetExt("silence_list", sl);\r              if (sl)\r                {\r                      DELETE(sl);\r                    user->Shrink("silence_list");\r          }\r      }\r\r     virtual void On005Numeric(std::string &output)\r {\r              // we don't really have a limit...\r             output = output + " SILENCE=" + ConvToStr(maxsilence);\r }\r      \r       virtual int OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)\r     {\r              // im not sure how unreal's silence operates but ours is sensible. It blocks notices and\r               // privmsgs from people on the silence list, directed privately at the user.\r           // channel messages are unaffected (ever tried to follow the flow of conversation in\r           // a channel when you've set an ignore on the two most talkative people?)\r              if ((target_type == TYPE_USER) && (IS_LOCAL(user)))\r            {\r                      userrec* u = (userrec*)dest;\r                   silencelist* sl;\r                       u->GetExt("silence_list", sl);\r                 if (sl)\r                        {\r                              for (silencelist::const_iterator c = sl->begin(); c != sl->end(); c++)\r                         {\r                                      if (match(user->GetFullHost(), c->first.c_str()))\r                                      {\r                                              return 1;\r                                      }\r                              }\r                      }\r              }\r              return 0;\r      }\r\r     virtual int OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)\r    {\r              return OnUserPreNotice(user,dest,target_type,text,status,exempt_list);\r }\r\r     virtual ~ModuleSilence()\r       {\r      }\r      \r       virtual Version GetVersion()\r   {\r              return Version(1,1,0,1,VF_VENDOR,API_VERSION);\r }\r};\r\rMODULE_INIT(ModuleSilence)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+#include "hashcomp.h"
+#include "wildcard.h"
+
+/* $ModDesc: Provides support for the /SILENCE command */
+
+// This typedef holds a silence list. Each user may or may not have a
+// silencelist, if a silence list is empty for a user, he/she does not
+// have one of these structures associated with their user record.
+typedef std::map<irc::string, time_t> silencelist;
+
+class cmd_silence : public command_t
+{
+       unsigned int& maxsilence;
+ public:
+       cmd_silence (InspIRCd* Instance, unsigned int &max) : command_t(Instance,"SILENCE", 0, 0), maxsilence(max)
+       {
+               this->source = "m_silence.so";
+               syntax = "{[+|-]<mask>}";
+       }
+
+       CmdResult Handle (const char** parameters, int pcnt, userrec *user)
+       {
+               if (!pcnt)
+               {
+                       // no parameters, show the current silence list.
+                       // Use Extensible::GetExt to fetch the silence list
+                       silencelist* sl;
+                       user->GetExt("silence_list", sl);
+                       // if the user has a silence list associated with their user record, show it
+                       if (sl)
+                       {
+                               for (silencelist::const_iterator c = sl->begin(); c != sl->end(); c++)
+                               {
+                                       user->WriteServ("271 %s %s %s :%lu",user->nick, user->nick, c->first.c_str(), (unsigned long)c->second);
+                               }
+                       }
+                       user->WriteServ("272 %s :End of Silence List",user->nick);
+
+                       return CMD_SUCCESS;
+               }
+               else if (pcnt > 0)
+               {
+                       // one or more parameters, add or delete entry from the list (only the first parameter is used)
+                       std::string mask = parameters[0] + 1;
+                       char action = *parameters[0];
+                       
+                       if (!mask.length())
+                       {
+                               // 'SILENCE +' or 'SILENCE -', assume *!*@*
+                               mask = "*!*@*";
+                       }
+                       
+                       ModeParser::CleanMask(mask);
+
+                       if (action == '-')
+                       {
+                               // fetch their silence list
+                               silencelist* sl;
+                               user->GetExt("silence_list", sl);
+                               // does it contain any entries and does it exist?
+                               if (sl)
+                               {
+                                       silencelist::iterator i = sl->find(mask.c_str());
+                                       if (i != sl->end())
+                                       {
+                                               sl->erase(i);
+                                               user->WriteServ("950 %s %s :Removed %s from silence list",user->nick, user->nick, mask.c_str());
+                                               if (!sl->size())
+                                               {
+                                                       // tidy up -- if a user's list is empty, theres no use having it
+                                                       // hanging around in the user record.
+                                                       DELETE(sl);
+                                                       user->Shrink("silence_list");
+                                               }
+                                       }
+                                       else
+                                               user->WriteServ("952 %s %s :%s does not exist on your silence list",user->nick, user->nick, mask.c_str());
+                               }
+                       }
+                       else if (action == '+')
+                       {
+                               // fetch the user's current silence list
+                               silencelist* sl;
+                               user->GetExt("silence_list", sl);
+                               // what, they dont have one??? WE'RE ALL GONNA DIE! ...no, we just create an empty one.
+                               if (!sl)
+                               {
+                                       sl = new silencelist;
+                                       user->Extend("silence_list", sl);
+                               }
+                               silencelist::iterator n = sl->find(mask.c_str());
+                               if (n != sl->end())
+                               {
+                                       user->WriteServ("952 %s %s :%s is already on your silence list",user->nick, user->nick, mask.c_str());
+                                       return CMD_FAILURE;
+                               }
+                               if (sl->size() >= maxsilence)
+                               {
+                                       user->WriteServ("952 %s %s :Your silence list is full",user->nick, user->nick, mask.c_str());
+                                       return CMD_FAILURE;
+                               }
+                               sl->insert(std::make_pair<irc::string, time_t>(mask.c_str(), ServerInstance->Time()));
+                               user->WriteServ("951 %s %s :Added %s to silence list",user->nick, user->nick, mask.c_str());
+                               return CMD_SUCCESS;
+                       }
+               }
+               return CMD_SUCCESS;
+       }
+};
+
+class ModuleSilence : public Module
+{
+       
+       cmd_silence* mycommand;
+       unsigned int maxsilence;
+ public:
+       ModuleSilence(InspIRCd* Me)
+               : Module(Me), maxsilence(32)
+       {
+               OnRehash(NULL, "");
+               mycommand = new cmd_silence(ServerInstance, maxsilence);
+               ServerInstance->AddCommand(mycommand);
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnRehash] = List[I_OnUserQuit] = List[I_On005Numeric] = List[I_OnUserPreNotice] = List[I_OnUserPreMessage] = 1;
+       }
+
+       virtual void OnRehash(userrec* user, const std::string &parameter)
+       {
+               ConfigReader Conf(ServerInstance);
+               maxsilence = Conf.ReadInteger("silence", "maxentries", 0, true);
+               if (!maxsilence)
+                       maxsilence = 32;
+       }
+
+       virtual void OnUserQuit(userrec* user, const std::string &reason, const std::string &oper_message)
+       {
+               // when the user quits tidy up any silence list they might have just to keep things tidy
+               // and to prevent a HONKING BIG MEMORY LEAK!
+               silencelist* sl;
+               user->GetExt("silence_list", sl);
+               if (sl)
+               {
+                       DELETE(sl);
+                       user->Shrink("silence_list");
+               }
+       }
+
+       virtual void On005Numeric(std::string &output)
+       {
+               // we don't really have a limit...
+               output = output + " SILENCE=" + ConvToStr(maxsilence);
+       }
+       
+       virtual int OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
+       {
+               // im not sure how unreal's silence operates but ours is sensible. It blocks notices and
+               // privmsgs from people on the silence list, directed privately at the user.
+               // channel messages are unaffected (ever tried to follow the flow of conversation in
+               // a channel when you've set an ignore on the two most talkative people?)
+               if ((target_type == TYPE_USER) && (IS_LOCAL(user)))
+               {
+                       userrec* u = (userrec*)dest;
+                       silencelist* sl;
+                       u->GetExt("silence_list", sl);
+                       if (sl)
+                       {
+                               for (silencelist::const_iterator c = sl->begin(); c != sl->end(); c++)
+                               {
+                                       if (match(user->GetFullHost(), c->first.c_str()))
+                                       {
+                                               return 1;
+                                       }
+                               }
+                       }
+               }
+               return 0;
+       }
+
+       virtual int OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
+       {
+               return OnUserPreNotice(user,dest,target_type,text,status,exempt_list);
+       }
+
+       virtual ~ModuleSilence()
+       {
+       }
+       
+       virtual Version GetVersion()
+       {
+               return Version(1,1,0,1,VF_VENDOR,API_VERSION);
+       }
+};
+
+MODULE_INIT(ModuleSilence)
index 7b1588043e41291131162788f3efd239287daac0..06eee9dd4fdc88db39c98a34068355f516e70bb2 100644 (file)
@@ -1 +1,372 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r#include "hashcomp.h"\r#include "wildcard.h"\r\r/* $ModDesc: Provides support for the /SILENCE command */\r\r/* Improved drop-in replacement for the /SILENCE command\r * syntax: /SILENCE [+|-]<mask> <p|c|i|n|t|a|x> as in <privatemessage|channelmessage|invites|privatenotice|channelnotice|all|exclude>\r *\r * example that blocks all except private messages\r *  /SILENCE +*!*@* a\r *  /SILENCE +*!*@* px\r *\r * example that blocks all invites except from channel services\r *  /SILENCE +*!*@* i\r *  /SILENCE +chanserv!services@chatters.net ix\r *\r * example that blocks some bad dude from private, notice and inviting you\r *  /SILENCE +*!kiddie@lamerz.net pin\r *\r * TODO: possibly have add and remove check for existing host and only modify flags according to\r *       what's been changed instead of having to remove first, then add if you want to change\r *       an entry.\r */\r\r// pair of hostmask and flags\rtypedef std::pair<std::string, int> silenceset;\r\r// deque list of pairs\rtypedef std::deque<silenceset> silencelist;\r\r// intmasks for flags\rstatic int SILENCE_PRIVATE  = 0x0001; /* p  private messages      */\rstatic int SILENCE_CHANNEL     = 0x0002; /* c  channel messages      */\rstatic int SILENCE_INVITE      = 0x0004; /* i  invites               */\rstatic int SILENCE_NOTICE      = 0x0008; /* n  notices               */\rstatic int SILENCE_CNOTICE     = 0x0010; /* t  channel notices       */\rstatic int SILENCE_ALL         = 0x0020; /* a  all, (pcint)          */\rstatic int SILENCE_EXCLUDE     = 0x0040; /* x  exclude this pattern  */\r\r\rclass cmd_silence : public command_t\r{\r      unsigned int& maxsilence;\r public:\r     cmd_silence (InspIRCd* Instance, unsigned int &max) : command_t(Instance,"SILENCE", 0, 0), maxsilence(max)\r     {\r              this->source = "m_silence_ext.so";\r             syntax = "{[+|-]<mask> <p|c|i|n|t|a|x>}";\r      }\r\r     CmdResult Handle (const char** parameters, int pcnt, userrec *user)\r    {\r              if (!pcnt)\r             {\r                      // no parameters, show the current silence list.\r                       // Use Extensible::GetExt to fetch the silence list\r                    silencelist* sl;\r                       user->GetExt("silence_list", sl);\r                      // if the user has a silence list associated with their user record, show it\r                   if (sl)\r                        {\r                              for (silencelist::const_iterator c = sl->begin(); c != sl->end(); c++)\r                         {\r                                      user->WriteServ("271 %s %s %s %s",user->nick, user->nick,c->first.c_str(), DecompPattern(c->second).c_str());\r                          }\r                      }\r                      user->WriteServ("272 %s :End of Silence List",user->nick);\r\r                    return CMD_LOCALONLY;\r          }\r              else if (pcnt > 0)\r             {\r                      // one or more parameters, add or delete entry from the list (only the first parameter is used)\r                        std::string mask = parameters[0] + 1;\r                  char action = *parameters[0];\r                  // Default is private and notice so clients do not break\r                       int pattern = CompilePattern("pn");\r\r                   // if pattern supplied, use it\r                 if (pcnt > 1) {\r                                pattern = CompilePattern(parameters[1]);\r                       }\r                      \r                       if (!mask.length())\r                    {\r                              // 'SILENCE +' or 'SILENCE -', assume *!*@*\r                            mask = "*!*@*";\r                        }\r                      \r                       ModeParser::CleanMask(mask);\r\r                  if (action == '-')\r                     {\r                              // fetch their silence list\r                            silencelist* sl;\r                               user->GetExt("silence_list", sl);\r                              // does it contain any entries and does it exist?\r                              if (sl)\r                                {\r                                      for (silencelist::iterator i = sl->begin(); i != sl->end(); i++)\r                                       {\r                                              // search through for the item\r                                         irc::string listitem = i->first.c_str();\r                                               if (listitem == mask && i->second == pattern)\r                                          {\r                                                      sl->erase(i);\r                                                  user->WriteServ("950 %s %s :Removed %s %s from silence list",user->nick, user->nick, mask.c_str(), DecompPattern(pattern).c_str());\r                                                    if (!sl->size())\r                                                       {\r                                                              DELETE(sl);\r                                                            user->Shrink("silence_list");\r                                                  }\r                                                      break;\r                                         }\r                                      }\r                              }\r                              user->WriteServ("952 %s %s :%s %s does not exist on your silence list",user->nick, user->nick, mask.c_str(), DecompPattern(pattern).c_str());\r                  }\r                      else if (action == '+')\r                        {\r                              // fetch the user's current silence list\r                               silencelist* sl;\r                               user->GetExt("silence_list", sl);\r                              // what, they dont have one??? WE'RE ALL GONNA DIE! ...no, we just create an empty one.\r                                if (!sl)\r                               {\r                                      sl = new silencelist;\r                                  user->Extend("silence_list", sl);\r                              }\r                              if (sl->size() > maxsilence)\r                           {\r                                      user->WriteServ("952 %s %s :Your silence list is full",user->nick, user->nick);\r                                        return CMD_FAILURE;\r                            }\r                              for (silencelist::iterator n = sl->begin(); n != sl->end();  n++)\r                              {\r                                      irc::string listitem = n->first.c_str();\r                                       if (listitem == mask && n->second == pattern)\r                                  {\r                                              user->WriteServ("952 %s %s :%s %s is already on your silence list",user->nick, user->nick, mask.c_str(), DecompPattern(pattern).c_str());\r                                              return CMD_FAILURE;\r                                    }\r                              }\r                              if (((pattern & SILENCE_EXCLUDE) > 0))\r                         {\r                                      sl->push_front(silenceset(mask,pattern));\r                              }\r                              else\r                           {\r                                      sl->push_back(silenceset(mask,pattern));\r                               }\r                              user->WriteServ("951 %s %s :Added %s %s to silence list",user->nick, user->nick, mask.c_str(), DecompPattern(pattern).c_str());\r                                return CMD_LOCALONLY;\r                  }\r              }\r              return CMD_LOCALONLY;\r  }\r\r     /* turn the nice human readable pattern into a mask */\r int CompilePattern(const char* pattern)\r        {\r              int p = 0;\r             for (const char* n = pattern; *n; n++)\r         {\r                      switch (*n)\r                    {\r                              case 'p':\r                                      p |= SILENCE_PRIVATE;\r                                  break;\r                         case 'c':\r                                      p |= SILENCE_CHANNEL;\r                                  break;\r                         case 'i': \r                                     p |= SILENCE_INVITE;\r                                   break;\r                         case 'n':\r                                      p |= SILENCE_NOTICE;\r                                   break;\r                         case 't':\r                                      p |= SILENCE_CNOTICE;\r                                  break;\r                         case 'a':\r                                      p |= SILENCE_ALL;\r                                      break;\r                         case 'x':\r                                      p |= SILENCE_EXCLUDE;\r                                  break;\r                         default:\r                                       break;\r                 }\r              }\r              return p;\r      }\r\r     /* turn the mask into a nice human readable format */\r  std::string DecompPattern (const int pattern)\r  {\r              std::string out;\r               if ((pattern & SILENCE_PRIVATE) > 0)\r                   out += ",privatemessages";\r             if ((pattern & SILENCE_CHANNEL) > 0)\r                   out += ",channelmessages";\r             if ((pattern & SILENCE_INVITE) > 0)\r                    out += ",invites";\r             if ((pattern & SILENCE_NOTICE) > 0)\r                    out += ",privatenotices";\r              if ((pattern & SILENCE_CNOTICE) > 0)\r                   out += ",channelnotices";\r              if ((pattern & SILENCE_ALL) > 0)\r                       out = ",all";\r          if ((pattern & SILENCE_EXCLUDE) > 0)\r                   out += ",exclude";\r             return "<" + out.substr(1) + ">";\r      }\r\r};\r\rclass ModuleSilence : public Module\r{\r   cmd_silence* mycommand;\r        unsigned int maxsilence;\r public:\r \r    ModuleSilence(InspIRCd* Me)\r            : Module(Me), maxsilence(32)\r   {\r              OnRehash(NULL, "");\r            mycommand = new cmd_silence(ServerInstance,maxsilence);\r                ServerInstance->AddCommand(mycommand);\r }\r\r     virtual void OnRehash(userrec* user, const std::string &parameter)\r     {\r              ConfigReader Conf(ServerInstance);\r             maxsilence = Conf.ReadInteger("silence", "maxentries", 0, true);\r               if (!maxsilence)\r                       maxsilence = 32;\r       }\r\r     void Implements(char* List)\r    {\r              List[I_OnRehash] = List[I_OnBuildExemptList] = List[I_OnUserQuit] = List[I_On005Numeric] = List[I_OnUserPreNotice] = List[I_OnUserPreMessage] = List[I_OnUserPreInvite] = 1;\r   }\r\r     virtual void OnUserQuit(userrec* user, const std::string &reason, const std::string &oper_message)\r     {\r              // when the user quits tidy up any silence list they might have just to keep things tidy\r               silencelist* sl;\r               user->GetExt("silence_list", sl);\r              if (sl)\r                {\r                      DELETE(sl);\r                    user->Shrink("silence_list");\r          }\r      }\r\r     virtual void On005Numeric(std::string &output)\r {\r              // we don't really have a limit...\r             output = output + " ESILENCE SILENCE=" + ConvToStr(maxsilence);\r        }\r\r     virtual void OnBuildExemptList(MessageType message_type, chanrec* chan, userrec* sender, char status, CUList &exempt_list)\r     {\r              int public_silence = (message_type == MSG_PRIVMSG ? SILENCE_CHANNEL : SILENCE_CNOTICE);\r                CUList *ulist;\r         switch (status)\r                {\r                      case '@':\r                              ulist = chan->GetOppedUsers();\r                         break;\r                 case '%':\r                              ulist = chan->GetHalfoppedUsers();\r                             break;\r                 case '+':\r                              ulist = chan->GetVoicedUsers();\r                                break;\r                 default:\r                               ulist = chan->GetUsers();\r                              break;\r         }\r\r             for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)\r              {\r                      if (IS_LOCAL(i->first))\r                        {\r                              if (MatchPattern(i->first, sender, public_silence) == 1)\r                               {\r                                      exempt_list[i->first] = i->first->nick;\r                                }\r                      }\r              }\r      }\r\r     virtual int PreText(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list, int silence_type)\r   {\r              if (!IS_LOCAL(user))\r                   return 0;\r\r             if (target_type == TYPE_USER)\r          {\r                      return MatchPattern((userrec*)dest, user, silence_type);\r               }\r              else if (target_type == TYPE_CHANNEL)\r          {\r                      chanrec* chan = (chanrec*)dest;\r                        if (chan)\r                      {\r                              this->OnBuildExemptList((silence_type == SILENCE_PRIVATE ? MSG_PRIVMSG : MSG_NOTICE), chan, user, status, exempt_list);\r                        }\r              }\r              return 0;\r      }\r\r     virtual int OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)\r    {\r              return PreText(user, dest, target_type, text, status, exempt_list, SILENCE_PRIVATE);\r   }\r\r     virtual int OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)\r     {\r              return PreText(user, dest, target_type, text, status, exempt_list, SILENCE_NOTICE);\r    }\r\r     virtual int OnUserPreInvite(userrec* source,userrec* dest,chanrec* channel)\r    {\r              return MatchPattern(dest, source, SILENCE_INVITE);\r     }\r\r     int MatchPattern(userrec* dest, userrec* source, int pattern)\r  {\r              silencelist* sl;\r               dest->GetExt("silence_list", sl);\r              if (sl)\r                {\r                      for (silencelist::const_iterator c = sl->begin(); c != sl->end(); c++)\r                 {\r                              if (((((c->second & pattern) > 0)) || ((c->second & SILENCE_ALL) > 0)) && (ServerInstance->MatchText(source->GetFullHost(), c->first)))\r                                        return !(((c->second & SILENCE_EXCLUDE) > 0));\r                 }\r              }\r              return 0;\r      }\r\r     virtual ~ModuleSilence()\r       {\r      }\r      \r       virtual Version GetVersion()\r   {\r              return Version(1,1,0,1,VF_VENDOR,API_VERSION);\r }\r};\r\rMODULE_INIT(ModuleSilence)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+#include "hashcomp.h"
+#include "wildcard.h"
+
+/* $ModDesc: Provides support for the /SILENCE command */
+
+/* Improved drop-in replacement for the /SILENCE command
+ * syntax: /SILENCE [+|-]<mask> <p|c|i|n|t|a|x> as in <privatemessage|channelmessage|invites|privatenotice|channelnotice|all|exclude>
+ *
+ * example that blocks all except private messages
+ *  /SILENCE +*!*@* a
+ *  /SILENCE +*!*@* px
+ *
+ * example that blocks all invites except from channel services
+ *  /SILENCE +*!*@* i
+ *  /SILENCE +chanserv!services@chatters.net ix
+ *
+ * example that blocks some bad dude from private, notice and inviting you
+ *  /SILENCE +*!kiddie@lamerz.net pin
+ *
+ * TODO: possibly have add and remove check for existing host and only modify flags according to
+ *       what's been changed instead of having to remove first, then add if you want to change
+ *       an entry.
+ */
+
+// pair of hostmask and flags
+typedef std::pair<std::string, int> silenceset;
+
+// deque list of pairs
+typedef std::deque<silenceset> silencelist;
+
+// intmasks for flags
+static int SILENCE_PRIVATE     = 0x0001; /* p  private messages      */
+static int SILENCE_CHANNEL     = 0x0002; /* c  channel messages      */
+static int SILENCE_INVITE      = 0x0004; /* i  invites               */
+static int SILENCE_NOTICE      = 0x0008; /* n  notices               */
+static int SILENCE_CNOTICE     = 0x0010; /* t  channel notices       */
+static int SILENCE_ALL         = 0x0020; /* a  all, (pcint)          */
+static int SILENCE_EXCLUDE     = 0x0040; /* x  exclude this pattern  */
+
+
+class cmd_silence : public command_t
+{
+       unsigned int& maxsilence;
+ public:
+       cmd_silence (InspIRCd* Instance, unsigned int &max) : command_t(Instance,"SILENCE", 0, 0), maxsilence(max)
+       {
+               this->source = "m_silence_ext.so";
+               syntax = "{[+|-]<mask> <p|c|i|n|t|a|x>}";
+       }
+
+       CmdResult Handle (const char** parameters, int pcnt, userrec *user)
+       {
+               if (!pcnt)
+               {
+                       // no parameters, show the current silence list.
+                       // Use Extensible::GetExt to fetch the silence list
+                       silencelist* sl;
+                       user->GetExt("silence_list", sl);
+                       // if the user has a silence list associated with their user record, show it
+                       if (sl)
+                       {
+                               for (silencelist::const_iterator c = sl->begin(); c != sl->end(); c++)
+                               {
+                                       user->WriteServ("271 %s %s %s %s",user->nick, user->nick,c->first.c_str(), DecompPattern(c->second).c_str());
+                               }
+                       }
+                       user->WriteServ("272 %s :End of Silence List",user->nick);
+
+                       return CMD_LOCALONLY;
+               }
+               else if (pcnt > 0)
+               {
+                       // one or more parameters, add or delete entry from the list (only the first parameter is used)
+                       std::string mask = parameters[0] + 1;
+                       char action = *parameters[0];
+                       // Default is private and notice so clients do not break
+                       int pattern = CompilePattern("pn");
+
+                       // if pattern supplied, use it
+                       if (pcnt > 1) {
+                               pattern = CompilePattern(parameters[1]);
+                       }
+                       
+                       if (!mask.length())
+                       {
+                               // 'SILENCE +' or 'SILENCE -', assume *!*@*
+                               mask = "*!*@*";
+                       }
+                       
+                       ModeParser::CleanMask(mask);
+
+                       if (action == '-')
+                       {
+                               // fetch their silence list
+                               silencelist* sl;
+                               user->GetExt("silence_list", sl);
+                               // does it contain any entries and does it exist?
+                               if (sl)
+                               {
+                                       for (silencelist::iterator i = sl->begin(); i != sl->end(); i++)
+                                       {
+                                               // search through for the item
+                                               irc::string listitem = i->first.c_str();
+                                               if (listitem == mask && i->second == pattern)
+                                               {
+                                                       sl->erase(i);
+                                                       user->WriteServ("950 %s %s :Removed %s %s from silence list",user->nick, user->nick, mask.c_str(), DecompPattern(pattern).c_str());
+                                                       if (!sl->size())
+                                                       {
+                                                               DELETE(sl);
+                                                               user->Shrink("silence_list");
+                                                       }
+                                                       break;
+                                               }
+                                       }
+                               }
+                               user->WriteServ("952 %s %s :%s %s does not exist on your silence list",user->nick, user->nick, mask.c_str(), DecompPattern(pattern).c_str());
+                       }
+                       else if (action == '+')
+                       {
+                               // fetch the user's current silence list
+                               silencelist* sl;
+                               user->GetExt("silence_list", sl);
+                               // what, they dont have one??? WE'RE ALL GONNA DIE! ...no, we just create an empty one.
+                               if (!sl)
+                               {
+                                       sl = new silencelist;
+                                       user->Extend("silence_list", sl);
+                               }
+                               if (sl->size() > maxsilence)
+                               {
+                                       user->WriteServ("952 %s %s :Your silence list is full",user->nick, user->nick);
+                                       return CMD_FAILURE;
+                               }
+                               for (silencelist::iterator n = sl->begin(); n != sl->end();  n++)
+                               {
+                                       irc::string listitem = n->first.c_str();
+                                       if (listitem == mask && n->second == pattern)
+                                       {
+                                               user->WriteServ("952 %s %s :%s %s is already on your silence list",user->nick, user->nick, mask.c_str(), DecompPattern(pattern).c_str());
+                                               return CMD_FAILURE;
+                                       }
+                               }
+                               if (((pattern & SILENCE_EXCLUDE) > 0))
+                               {
+                                       sl->push_front(silenceset(mask,pattern));
+                               }
+                               else
+                               {
+                                       sl->push_back(silenceset(mask,pattern));
+                               }
+                               user->WriteServ("951 %s %s :Added %s %s to silence list",user->nick, user->nick, mask.c_str(), DecompPattern(pattern).c_str());
+                               return CMD_LOCALONLY;
+                       }
+               }
+               return CMD_LOCALONLY;
+       }
+
+       /* turn the nice human readable pattern into a mask */
+       int CompilePattern(const char* pattern)
+       {
+               int p = 0;
+               for (const char* n = pattern; *n; n++)
+               {
+                       switch (*n)
+                       {
+                               case 'p':
+                                       p |= SILENCE_PRIVATE;
+                                       break;
+                               case 'c':
+                                       p |= SILENCE_CHANNEL;
+                                       break;
+                               case 'i': 
+                                       p |= SILENCE_INVITE;
+                                       break;
+                               case 'n':
+                                       p |= SILENCE_NOTICE;
+                                       break;
+                               case 't':
+                                       p |= SILENCE_CNOTICE;
+                                       break;
+                               case 'a':
+                                       p |= SILENCE_ALL;
+                                       break;
+                               case 'x':
+                                       p |= SILENCE_EXCLUDE;
+                                       break;
+                               default:
+                                       break;
+                       }
+               }
+               return p;
+       }
+
+       /* turn the mask into a nice human readable format */
+       std::string DecompPattern (const int pattern)
+       {
+               std::string out;
+               if ((pattern & SILENCE_PRIVATE) > 0)
+                       out += ",privatemessages";
+               if ((pattern & SILENCE_CHANNEL) > 0)
+                       out += ",channelmessages";
+               if ((pattern & SILENCE_INVITE) > 0)
+                       out += ",invites";
+               if ((pattern & SILENCE_NOTICE) > 0)
+                       out += ",privatenotices";
+               if ((pattern & SILENCE_CNOTICE) > 0)
+                       out += ",channelnotices";
+               if ((pattern & SILENCE_ALL) > 0)
+                       out = ",all";
+               if ((pattern & SILENCE_EXCLUDE) > 0)
+                       out += ",exclude";
+               return "<" + out.substr(1) + ">";
+       }
+
+};
+
+class ModuleSilence : public Module
+{
+       cmd_silence* mycommand;
+       unsigned int maxsilence;
+ public:
+       ModuleSilence(InspIRCd* Me)
+               : Module(Me), maxsilence(32)
+       {
+               OnRehash(NULL, "");
+               mycommand = new cmd_silence(ServerInstance,maxsilence);
+               ServerInstance->AddCommand(mycommand);
+       }
+
+       virtual void OnRehash(userrec* user, const std::string &parameter)
+       {
+               ConfigReader Conf(ServerInstance);
+               maxsilence = Conf.ReadInteger("silence", "maxentries", 0, true);
+               if (!maxsilence)
+                       maxsilence = 32;
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnRehash] = List[I_OnBuildExemptList] = List[I_OnUserQuit] = List[I_On005Numeric] = List[I_OnUserPreNotice] = List[I_OnUserPreMessage] = List[I_OnUserPreInvite] = 1;
+       }
+
+       virtual void OnUserQuit(userrec* user, const std::string &reason, const std::string &oper_message)
+       {
+               // when the user quits tidy up any silence list they might have just to keep things tidy
+               silencelist* sl;
+               user->GetExt("silence_list", sl);
+               if (sl)
+               {
+                       DELETE(sl);
+                       user->Shrink("silence_list");
+               }
+       }
+
+       virtual void On005Numeric(std::string &output)
+       {
+               // we don't really have a limit...
+               output = output + " ESILENCE SILENCE=" + ConvToStr(maxsilence);
+       }
+
+       virtual void OnBuildExemptList(MessageType message_type, chanrec* chan, userrec* sender, char status, CUList &exempt_list)
+       {
+               int public_silence = (message_type == MSG_PRIVMSG ? SILENCE_CHANNEL : SILENCE_CNOTICE);
+               CUList *ulist;
+               switch (status)
+               {
+                       case '@':
+                               ulist = chan->GetOppedUsers();
+                               break;
+                       case '%':
+                               ulist = chan->GetHalfoppedUsers();
+                               break;
+                       case '+':
+                               ulist = chan->GetVoicedUsers();
+                               break;
+                       default:
+                               ulist = chan->GetUsers();
+                               break;
+               }
+
+               for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
+               {
+                       if (IS_LOCAL(i->first))
+                       {
+                               if (MatchPattern(i->first, sender, public_silence) == 1)
+                               {
+                                       exempt_list[i->first] = i->first->nick;
+                               }
+                       }
+               }
+       }
+
+       virtual int PreText(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list, int silence_type)
+       {
+               if (!IS_LOCAL(user))
+                       return 0;
+
+               if (target_type == TYPE_USER)
+               {
+                       return MatchPattern((userrec*)dest, user, silence_type);
+               }
+               else if (target_type == TYPE_CHANNEL)
+               {
+                       chanrec* chan = (chanrec*)dest;
+                       if (chan)
+                       {
+                               this->OnBuildExemptList((silence_type == SILENCE_PRIVATE ? MSG_PRIVMSG : MSG_NOTICE), chan, user, status, exempt_list);
+                       }
+               }
+               return 0;
+       }
+
+       virtual int OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
+       {
+               return PreText(user, dest, target_type, text, status, exempt_list, SILENCE_PRIVATE);
+       }
+
+       virtual int OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
+       {
+               return PreText(user, dest, target_type, text, status, exempt_list, SILENCE_NOTICE);
+       }
+
+       virtual int OnUserPreInvite(userrec* source,userrec* dest,chanrec* channel)
+       {
+               return MatchPattern(dest, source, SILENCE_INVITE);
+       }
+
+       int MatchPattern(userrec* dest, userrec* source, int pattern)
+       {
+               silencelist* sl;
+               dest->GetExt("silence_list", sl);
+               if (sl)
+               {
+                       for (silencelist::const_iterator c = sl->begin(); c != sl->end(); c++)
+                       {
+                               if (((((c->second & pattern) > 0)) || ((c->second & SILENCE_ALL) > 0)) && (ServerInstance->MatchText(source->GetFullHost(), c->first)))
+                                       return !(((c->second & SILENCE_EXCLUDE) > 0));
+                       }
+               }
+               return 0;
+       }
+
+       virtual ~ModuleSilence()
+       {
+       }
+       
+       virtual Version GetVersion()
+       {
+               return Version(1,1,0,1,VF_VENDOR,API_VERSION);
+       }
+};
+
+MODULE_INIT(ModuleSilence)
index 76c678c1f74db5994c0b0ce06f6786914ce411f8..ff23e03814af91b103c741a9c1a28d2f68026c77 100644 (file)
@@ -1 +1,24 @@
-m_spanningtree\r--------------\r\rThis directory contains all files required to build the m_spanningtree.so module.\rDirectories like this one starting with m_ and containing .cpp files are aggregated\rtogether by the makefile to form a single .so, with the same name as the directory.\r\rThis directory contains the following files:\r\r* handshaketimer.cpp           Code for detecting end of ziplink/ssl handshake\r* handshaketimer.h              Header for above code\r* link.h                  Contains the definition of the Link block class\r* main.cpp                      The main group of classes and code for the module class\r* main.h                        The header for the main file\r* resolvers.h                      The header file that defines certain DNS utility classes\r* treesocket.cpp               Contains code that inherits InspSocket into a server socket\r* treesocket.h                      Header definitions for above code\r* treeserver.cpp              Contains code that defines the behaviour of a single server\r* treeserver.h                      Header definitions for above code\r* utils.cpp                   Contains general and message routing utility classes\r* utils.h                  Header code for general and message routing utilities\r\rHave fun\r  -- Brain :-)\r
\ No newline at end of file
+m_spanningtree
+--------------
+
+This directory contains all files required to build the m_spanningtree.so module.
+Directories like this one starting with m_ and containing .cpp files are aggregated
+together by the makefile to form a single .so, with the same name as the directory.
+
+This directory contains the following files:
+
+* handshaketimer.cpp           Code for detecting end of ziplink/ssl handshake
+* handshaketimer.h             Header for above code
+* link.h                       Contains the definition of the Link block class
+* main.cpp                     The main group of classes and code for the module class
+* main.h                       The header for the main file
+* resolvers.h                  The header file that defines certain DNS utility classes
+* treesocket.cpp               Contains code that inherits InspSocket into a server socket
+* treesocket.h                 Header definitions for above code
+* treeserver.cpp               Contains code that defines the behaviour of a single server
+* treeserver.h                 Header definitions for above code
+* utils.cpp                    Contains general and message routing utility classes
+* utils.h                      Header code for general and message routing utilities
+
+Have fun
+  -- Brain :-)
index 93856f46703da1025c8c623e523c60511d5c48ab..4aeb1da88e2eefd86321e9080ee373ad117e088f 100644 (file)
@@ -1 +1,62 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "configreader.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r#include "commands/cmd_whois.h"\r#include "commands/cmd_stats.h"\r#include "socket.h"\r#include "wildcard.h"\r#include "xline.h"\r#include "transport.h"\r\r#include "m_spanningtree/main.h"\r#include "m_spanningtree/utils.h"\r#include "m_spanningtree/treeserver.h"\r#include "m_spanningtree/link.h"\r#include "m_spanningtree/treesocket.h"\r#include "m_spanningtree/handshaketimer.h"\r\r/* $ModDep: m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/link.h m_spanningtree/treesocket.h */\r\rHandshakeTimer::HandshakeTimer(InspIRCd* Inst, TreeSocket* s, Link* l, SpanningTreeUtilities* u, int delay) : InspTimer(delay, time(NULL)), Instance(Inst), sock(s), lnk(l), Utils(u)\r{\r       thefd = sock->GetFd();\r}\r\rvoid HandshakeTimer::Tick(time_t TIME)\r{\r     if (Instance->SE->GetRef(thefd) == sock)\r       {\r              if (!sock->GetHook())\r          {\r                      sock->SendCapabilities();\r              }\r              else\r           {\r                      if (sock->GetHook() && InspSocketHSCompleteRequest(sock, (Module*)Utils->Creator, sock->GetHook()).Send())\r                     {\r                              InspSocketAttachCertRequest(sock, (Module*)Utils->Creator, sock->GetHook()).Send();\r                            sock->SendCapabilities();\r                      }\r                      else\r                   {\r                              Instance->Timers->AddTimer(new HandshakeTimer(Instance, sock, lnk, Utils, 1));\r                 }\r              }\r      }\r}\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "configreader.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+#include "commands/cmd_whois.h"
+#include "commands/cmd_stats.h"
+#include "socket.h"
+#include "wildcard.h"
+#include "xline.h"
+#include "transport.h"
+
+#include "m_spanningtree/main.h"
+#include "m_spanningtree/utils.h"
+#include "m_spanningtree/treeserver.h"
+#include "m_spanningtree/link.h"
+#include "m_spanningtree/treesocket.h"
+#include "m_spanningtree/handshaketimer.h"
+
+/* $ModDep: m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/link.h m_spanningtree/treesocket.h */
+
+HandshakeTimer::HandshakeTimer(InspIRCd* Inst, TreeSocket* s, Link* l, SpanningTreeUtilities* u, int delay) : InspTimer(delay, time(NULL)), Instance(Inst), sock(s), lnk(l), Utils(u)
+{
+       thefd = sock->GetFd();
+}
+
+void HandshakeTimer::Tick(time_t TIME)
+{
+       if (Instance->SE->GetRef(thefd) == sock)
+       {
+               if (!sock->GetHook())
+               {
+                       sock->SendCapabilities();
+               }
+               else
+               {
+                       if (sock->GetHook() && InspSocketHSCompleteRequest(sock, (Module*)Utils->Creator, sock->GetHook()).Send())
+                       {
+                               InspSocketAttachCertRequest(sock, (Module*)Utils->Creator, sock->GetHook()).Send();
+                               sock->SendCapabilities();
+                       }
+                       else
+                       {
+                               Instance->Timers->AddTimer(new HandshakeTimer(Instance, sock, lnk, Utils, 1));
+                       }
+               }
+       }
+}
+
index e94fe67d7c50377a767dbda7ef1766bbc49ae8b2..496102ddaefdb2605b0625d4219e6d338bb3b81c 100644 (file)
@@ -1 +1,37 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __HANDSHAKE_TIMER_H__\r#define __HANDSHAKE_TIMER_H__\r\r#include "inspircd.h"\r#include "timer.h"\r\rclass SpanningTreeUtilities;\rclass TreeSocket;\rclass Link;\r\rclass HandshakeTimer : public InspTimer\r{\r private:\r    InspIRCd* Instance;\r    TreeSocket* sock;\r      Link* lnk;\r     SpanningTreeUtilities* Utils;\r  int thefd;\r public:\r    HandshakeTimer(InspIRCd* Inst, TreeSocket* s, Link* l, SpanningTreeUtilities* u, int delay);\r   virtual void Tick(time_t TIME);\r};\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __HANDSHAKE_TIMER_H__
+#define __HANDSHAKE_TIMER_H__
+
+#include "inspircd.h"
+#include "timer.h"
+
+class SpanningTreeUtilities;
+class TreeSocket;
+class Link;
+
+class HandshakeTimer : public InspTimer
+{
+ private:
+       InspIRCd* Instance;
+       TreeSocket* sock;
+       Link* lnk;
+       SpanningTreeUtilities* Utils;
+       int thefd;
+ public:
+       HandshakeTimer(InspIRCd* Inst, TreeSocket* s, Link* l, SpanningTreeUtilities* u, int delay);
+       virtual void Tick(time_t TIME);
+};
+
+#endif
index 9636d565f1ed11b9592375228d2cf3e14e1973b3..3de32615397dbeec184714f163605a650f6d0ad3 100644 (file)
@@ -1 +1,42 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __LINK_H__\r#define __LINK_H__\r\r/** The Link class might as well be a struct,\r * but this is C++ and we don't believe in structs (!).\r * It holds the entire information of one <link>\r * tag from the main config file. We maintain a list\r * of them, and populate the list on rehash/load.\r */\rclass Link : public classbase\r{\r public:\r irc::string Name;\r      std::string IPAddr;\r    int Port;\r      std::string SendPass;\r  std::string RecvPass;\r  std::string AllowMask;\r unsigned long AutoConnect;\r     time_t NextConnectTime;\r        bool HiddenFromStats;\r  std::string FailOver;\r  std::string Hook;\r      int Timeout;\r   std::string Bind;\r      bool Hidden;\r};\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __LINK_H__
+#define __LINK_H__
+
+/** The Link class might as well be a struct,
+ * but this is C++ and we don't believe in structs (!).
+ * It holds the entire information of one <link>
+ * tag from the main config file. We maintain a list
+ * of them, and populate the list on rehash/load.
+ */
+class Link : public classbase
+{
+ public:
+       irc::string Name;
+       std::string IPAddr;
+       int Port;
+       std::string SendPass;
+       std::string RecvPass;
+       std::string AllowMask;
+       unsigned long AutoConnect;
+       time_t NextConnectTime;
+       bool HiddenFromStats;
+       std::string FailOver;
+       std::string Hook;
+       int Timeout;
+       std::string Bind;
+       bool Hidden;
+};
+
+#endif
index 352cae87022308c3f8cbb5846f24960fc0a56596..1cc18dae6f1e46cc145816225ff0730735722214 100644 (file)
@@ -1 +1,1392 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *        the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r/* $ModDesc: Provides a spanning tree server link protocol */\r\r#include "inspircd.h"\r#include "configreader.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r#include "commands/cmd_whois.h"\r#include "commands/cmd_stats.h"\r#include "socket.h"\r#include "wildcard.h"\r#include "xline.h"\r#include "transport.h"\r\r#include "m_spanningtree/timesynctimer.h"\r#include "m_spanningtree/resolvers.h"\r#include "m_spanningtree/main.h"\r#include "m_spanningtree/utils.h"\r#include "m_spanningtree/treeserver.h"\r#include "m_spanningtree/link.h"\r#include "m_spanningtree/treesocket.h"\r#include "m_spanningtree/rconnect.h"\r#include "m_spanningtree/rsquit.h"\r\r/* $ModDep: m_spanningtree/timesynctimer.h m_spanningtree/resolvers.h m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/link.h m_spanningtree/treesocket.h m_spanningtree/rconnect.h m_spanningtree/rsquit.h */\r\rModuleSpanningTree::ModuleSpanningTree(InspIRCd* Me)\r      : Module(Me), max_local(0), max_global(0)\r{\r    ServerInstance->UseInterface("InspSocketHook");\r        Utils = new SpanningTreeUtilities(Me, this);\r   command_rconnect = new cmd_rconnect(ServerInstance, this, Utils);\r      ServerInstance->AddCommand(command_rconnect);\r  command_rsquit = new cmd_rsquit(ServerInstance, this, Utils);\r  ServerInstance->AddCommand(command_rsquit);\r    if (Utils->EnableTimeSync)\r     {\r              SyncTimer = new TimeSyncTimer(ServerInstance, this);\r           ServerInstance->Timers->AddTimer(SyncTimer);\r   }\r      else\r           SyncTimer = NULL;\r\r     RefreshTimer = new CacheRefreshTimer(ServerInstance, Utils);\r   ServerInstance->Timers->AddTimer(RefreshTimer);\r}\r\rvoid ModuleSpanningTree::ShowLinks(TreeServer* Current, userrec* user, int hops)\r{\r  std::string Parent = Utils->TreeRoot->GetName();\r       if (Current->GetParent())\r      {\r              Parent = Current->GetParent()->GetName();\r      }\r      for (unsigned int q = 0; q < Current->ChildCount(); q++)\r       {\r              if ((Current->GetChild(q)->Hidden) || ((Utils->HideULines) && (ServerInstance->ULine(Current->GetChild(q)->GetName().c_str()))))\r               {\r                      if (*user->oper)\r                       {\r                               ShowLinks(Current->GetChild(q),user,hops+1);\r                  }\r              }\r              else\r           {\r                      ShowLinks(Current->GetChild(q),user,hops+1);\r           }\r      }\r      /* Don't display the line if its a uline, hide ulines is on, and the user isnt an oper */\r      if ((Utils->HideULines) && (ServerInstance->ULine(Current->GetName().c_str())) && (!IS_OPER(user)))\r            return;\r        /* Or if the server is hidden and they're not an oper */\r       else if ((Current->Hidden) && (!IS_OPER(user)))\r                return;\r\r       user->WriteServ("364 %s %s %s :%d %s",  user->nick,Current->GetName().c_str(),\r                 (Utils->FlatLinks && (!IS_OPER(user))) ? ServerInstance->Config->ServerName : Parent.c_str(),\r                  (Utils->FlatLinks && (!IS_OPER(user))) ? 0 : hops,\r                     Current->GetDesc().c_str());\r}\r\rint ModuleSpanningTree::CountLocalServs()\r{\r    return Utils->TreeRoot->ChildCount();\r}\r\rint ModuleSpanningTree::CountServs()\r{\r        return Utils->serverlist.size();\r}\r\rvoid ModuleSpanningTree::HandleLinks(const char** parameters, int pcnt, userrec* user)\r{\r   ShowLinks(Utils->TreeRoot,user,0);\r     user->WriteServ("365 %s * :End of /LINKS list.",user->nick);\r   return;\r}\r\rvoid ModuleSpanningTree::HandleLusers(const char** parameters, int pcnt, userrec* user)\r{\r   unsigned int n_users = ServerInstance->UserCount();\r\r   /* Only update these when someone wants to see them, more efficient */\r if ((unsigned int)ServerInstance->LocalUserCount() > max_local)\r                max_local = ServerInstance->LocalUserCount();\r  if (n_users > max_global)\r              max_global = n_users;\r\r unsigned int ulined_count = 0;\r unsigned int ulined_local_count = 0;\r\r  /* If ulined are hidden and we're not an oper, count the number of ulined servers hidden,\r       * locally and globally (locally means directly connected to us)\r        */\r    if ((Utils->HideULines) && (!*user->oper))\r     {\r              for (server_hash::iterator q = Utils->serverlist.begin(); q != Utils->serverlist.end(); q++)\r           {\r                      if (ServerInstance->ULine(q->second->GetName().c_str()))\r                       {\r                              ulined_count++;\r                                if (q->second->GetParent() == Utils->TreeRoot)\r                                 ulined_local_count++;\r                  }\r              }\r      }\r      user->WriteServ("251 %s :There are %d users and %d invisible on %d servers",user->nick,n_users-ServerInstance->InvisibleUserCount(),ServerInstance->InvisibleUserCount(),ulined_count ? this->CountServs() - ulined_count : this->CountServs());\r       if (ServerInstance->OperCount())\r               user->WriteServ("252 %s %d :operator(s) online",user->nick,ServerInstance->OperCount());\r       if (ServerInstance->UnregisteredUserCount())\r           user->WriteServ("253 %s %d :unknown connections",user->nick,ServerInstance->UnregisteredUserCount());\r  if (ServerInstance->ChannelCount())\r            user->WriteServ("254 %s %d :channels formed",user->nick,ServerInstance->ChannelCount());\r       user->WriteServ("255 %s :I have %d clients and %d servers",user->nick,ServerInstance->LocalUserCount(),ulined_local_count ? this->CountLocalServs() - ulined_local_count : this->CountLocalServs());\r   user->WriteServ("265 %s :Current Local Users: %d  Max: %d",user->nick,ServerInstance->LocalUserCount(),max_local);\r     user->WriteServ("266 %s :Current Global Users: %d  Max: %d",user->nick,n_users,max_global);\r    return;\r}\r\rstd::string ModuleSpanningTree::TimeToStr(time_t secs)\r{\r    time_t mins_up = secs / 60;\r    time_t hours_up = mins_up / 60;\r        time_t days_up = hours_up / 24;\r        secs = secs % 60;\r      mins_up = mins_up % 60;\r        hours_up = hours_up % 24;\r      return ((days_up ? (ConvToStr(days_up) + "d") : std::string(""))\r                       + (hours_up ? (ConvToStr(hours_up) + "h") : std::string(""))\r                   + (mins_up ? (ConvToStr(mins_up) + "m") : std::string(""))\r                     + ConvToStr(secs) + "s");\r}\r\rconst std::string ModuleSpanningTree::MapOperInfo(TreeServer* Current)\r{\r  time_t secs_up = ServerInstance->Time() - Current->age;\r        return (" [Up: " + TimeToStr(secs_up) + " Lag: "+ConvToStr(Current->rtt)+"s]");\r}\r\r// WARNING: NOT THREAD SAFE - DONT GET ANY SMART IDEAS.\rvoid ModuleSpanningTree::ShowMap(TreeServer* Current, userrec* user, int depth, char matrix[128][128], float &totusers, float &totservers)\r{\r        if (line < 128)\r        {\r              for (int t = 0; t < depth; t++)\r                {\r                      matrix[line][t] = ' ';\r         }\r              // For Aligning, we need to work out exactly how deep this thing is, and produce\r               // a 'Spacer' String to compensate.\r            char spacer[40];\r               memset(spacer,' ',40);\r         if ((40 - Current->GetName().length() - depth) > 1) {\r                  spacer[40 - Current->GetName().length() - depth] = '\0';\r               }\r              else\r           {\r                      spacer[5] = '\0';\r              }\r              float percent;\r         char text[128];\r                /* Neat and tidy default values, as we're dealing with a matrix not a simple string */\r         memset(text, 0, 128);\r\r         if (ServerInstance->clientlist->size() == 0) {\r                 // If there are no users, WHO THE HELL DID THE /MAP?!?!?!\r                      percent = 0;\r           }\r              else\r           {\r                      percent = ((float)Current->GetUserCount() / (float)ServerInstance->clientlist->size()) * 100;\r          }\r              const std::string operdata = IS_OPER(user) ? MapOperInfo(Current) : "";\r                snprintf(text, 126, "%s %s%5d [%5.2f%%]%s", Current->GetName().c_str(), spacer, Current->GetUserCount(), percent, operdata.c_str());\r           totusers += Current->GetUserCount();\r           totservers++;\r          strlcpy(&matrix[line][depth],text,126);\r                line++;\r                for (unsigned int q = 0; q < Current->ChildCount(); q++)\r               {\r                      if ((Current->GetChild(q)->Hidden) || ((Utils->HideULines) && (ServerInstance->ULine(Current->GetChild(q)->GetName().c_str()))))\r                       {\r                              if (*user->oper)\r                               {\r                                      ShowMap(Current->GetChild(q),user,(Utils->FlatLinks && (!*user->oper)) ? depth : depth+2,matrix,totusers,totservers);\r                          }\r                      }\r                      else\r                   {\r                              ShowMap(Current->GetChild(q),user,(Utils->FlatLinks && (!*user->oper)) ? depth : depth+2,matrix,totusers,totservers);\r                  }\r              }\r      }\r}\r\rint ModuleSpanningTree::HandleMotd(const char** parameters, int pcnt, userrec* user)\r{\r    if (pcnt > 0)\r  {\r              if (match(ServerInstance->Config->ServerName, parameters[0]))\r                  return 0;\r\r             /* Remote MOTD, the server is within the 1st parameter */\r              std::deque<std::string> params;\r                params.push_back(parameters[0]);\r               /* Send it out remotely, generate no reply yet */\r              TreeServer* s = Utils->FindServerMask(parameters[0]);\r          if (s)\r         {\r                      params[0] = s->GetName();\r                      Utils->DoOneToOne(user->nick, "MOTD", params, s->GetName());\r           }\r              else\r                   user->WriteServ( "402 %s %s :No such server", user->nick, parameters[0]);\r              return 1;\r      }\r      return 0;\r}\r\rint ModuleSpanningTree::HandleAdmin(const char** parameters, int pcnt, userrec* user)\r{\r   if (pcnt > 0)\r  {\r              if (match(ServerInstance->Config->ServerName, parameters[0]))\r                  return 0;\r\r             /* Remote ADMIN, the server is within the 1st parameter */\r             std::deque<std::string> params;\r                params.push_back(parameters[0]);\r               /* Send it out remotely, generate no reply yet */\r              TreeServer* s = Utils->FindServerMask(parameters[0]);\r          if (s)\r         {\r                      params[0] = s->GetName();\r                      Utils->DoOneToOne(user->nick, "ADMIN", params, s->GetName());\r          }\r              else\r                   user->WriteServ( "402 %s %s :No such server", user->nick, parameters[0]);\r              return 1;\r      }\r      return 0;\r}\r\rint ModuleSpanningTree::HandleModules(const char** parameters, int pcnt, userrec* user)\r{\r if (pcnt > 0)\r  {\r              if (match(ServerInstance->Config->ServerName, parameters[0]))\r                  return 0;\r\r             std::deque<std::string> params;\r                params.push_back(parameters[0]);\r               TreeServer* s = Utils->FindServerMask(parameters[0]);\r          if (s)\r         {\r                      params[0] = s->GetName();\r                      Utils->DoOneToOne(user->nick, "MODULES", params, s->GetName());\r                }\r              else\r                   user->WriteServ( "402 %s %s :No such server", user->nick, parameters[0]);\r              return 1;\r      }\r      return 0;\r}\r\rint ModuleSpanningTree::HandleStats(const char** parameters, int pcnt, userrec* user)\r{\r   if (pcnt > 1)\r  {\r              if (match(ServerInstance->Config->ServerName, parameters[1]))\r                  return 0;\r\r             /* Remote STATS, the server is within the 2nd parameter */\r             std::deque<std::string> params;\r                params.push_back(parameters[0]);\r               params.push_back(parameters[1]);\r               /* Send it out remotely, generate no reply yet */\r\r             TreeServer* s = Utils->FindServerMask(parameters[1]);\r          if (s)\r         {\r                      params[1] = s->GetName();\r                      Utils->DoOneToOne(user->nick, "STATS", params, s->GetName());\r          }\r              else\r           {\r                      user->WriteServ( "402 %s %s :No such server", user->nick, parameters[1]);\r              }\r              return 1;\r      }\r      return 0;\r}\r\r// Ok, prepare to be confused.\r// After much mulling over how to approach this, it struck me that\r// the 'usual' way of doing a /MAP isnt the best way. Instead of\r// keeping track of a ton of ascii characters, and line by line\r// under recursion working out where to place them using multiplications\r// and divisons, we instead render the map onto a backplane of characters\r// (a character matrix), then draw the branches as a series of "L" shapes\r// from the nodes. This is not only friendlier on CPU it uses less stack.\rvoid ModuleSpanningTree::HandleMap(const char** parameters, int pcnt, userrec* user)\r{\r  // This array represents a virtual screen which we will\r        // "scratch" draw to, as the console device of an irc\r  // client does not provide for a proper terminal.\r      float totusers = 0;\r    float totservers = 0;\r  char matrix[128][128];\r for (unsigned int t = 0; t < 128; t++)\r {\r              matrix[t][0] = '\0';\r   }\r      line = 0;\r      // The only recursive bit is called here.\r      ShowMap(Utils->TreeRoot,user,0,matrix,totusers,totservers);\r    // Process each line one by one. The algorithm has a limit of\r  // 128 servers (which is far more than a spanning tree should have\r     // anyway, so we're ok). This limit can be raised simply by making\r     // the character matrix deeper, 128 rows taking 10k of memory.\r for (int l = 1; l < line; l++)\r {\r              // scan across the line looking for the start of the\r           // servername (the recursive part of the algorithm has placed\r          // the servers at indented positions depending on what they\r            // are related to)\r             int first_nonspace = 0;\r                while (matrix[l][first_nonspace] == ' ')\r               {\r                      first_nonspace++;\r              }\r              first_nonspace--;\r              // Draw the `- (corner) section: this may be overwritten by\r            // another L shape passing along the same vertical pane, becoming\r              // a |- (branch) section instead.\r              matrix[l][first_nonspace] = '-';\r               matrix[l][first_nonspace-1] = '`';\r             int l2 = l - 1;\r                // Draw upwards until we hit the parent server, causing possibly\r               // other corners (`-) to become branches (|-)\r          while ((matrix[l2][first_nonspace-1] == ' ') || (matrix[l2][first_nonspace-1] == '`'))\r         {\r                      matrix[l2][first_nonspace-1] = '|';\r                    l2--;\r          }\r      }\r      // dump the whole lot to the user. This is the easy bit, honest.\r       for (int t = 0; t < line; t++)\r {\r              user->WriteServ("006 %s :%s",user->nick,&matrix[t][0]);\r        }\r      float avg_users = totusers / totservers;\r       user->WriteServ("270 %s :%.0f server%s and %.0f user%s, average %.2f users per server",user->nick,totservers,(totservers > 1 ? "s" : ""),totusers,(totusers > 1 ? "s" : ""),avg_users);\r        user->WriteServ("007 %s :End of /MAP",user->nick);\r     return;\r}\r\rint ModuleSpanningTree::HandleSquit(const char** parameters, int pcnt, userrec* user)\r{\r     TreeServer* s = Utils->FindServerMask(parameters[0]);\r  if (s)\r {\r              if (s == Utils->TreeRoot)\r              {\r                      user->WriteServ("NOTICE %s :*** SQUIT: Foolish mortal, you cannot make a server SQUIT itself! (%s matches local server name)",user->nick,parameters[0]);\r                       return 1;\r              }\r              TreeSocket* sock = s->GetSocket();\r             if (sock)\r              {\r                      ServerInstance->SNO->WriteToSnoMask('l',"SQUIT: Server \002%s\002 removed from network by %s",parameters[0],user->nick);\r                       sock->Squit(s,std::string("Server quit by ") + user->GetFullRealHost());\r                       ServerInstance->SE->DelFd(sock);\r                       sock->Close();\r         }\r              else\r           {\r                      if (IS_LOCAL(user))\r                            user->WriteServ("NOTICE %s :*** WARNING: Using SQUIT to split remote servers is deprecated. Please use RSQUIT instead.",user->nick);\r           }\r      }\r      else\r   {\r               user->WriteServ("NOTICE %s :*** SQUIT: The server \002%s\002 does not exist on the network.",user->nick,parameters[0]);\r       }\r      return 1;\r}\r\rint ModuleSpanningTree::HandleTime(const char** parameters, int pcnt, userrec* user)\r{\r    if ((IS_LOCAL(user)) && (pcnt))\r        {\r              TreeServer* found = Utils->FindServerMask(parameters[0]);\r              if (found)\r             {\r                      // we dont' override for local server\r                  if (found == Utils->TreeRoot)\r                          return 0;\r                      \r                       std::deque<std::string> params;\r                        params.push_back(found->GetName());\r                    params.push_back(user->nick);\r                  Utils->DoOneToOne(ServerInstance->Config->ServerName,"TIME",params,found->GetName());\r          }\r              else\r           {\r                      user->WriteServ("402 %s %s :No such server",user->nick,parameters[0]);\r         }\r      }\r      return 1;\r}\r\rint ModuleSpanningTree::HandleRemoteWhois(const char** parameters, int pcnt, userrec* user)\r{\r     if ((IS_LOCAL(user)) && (pcnt > 1))\r    {\r              userrec* remote = ServerInstance->FindNick(parameters[1]);\r             if ((remote) && (remote->GetFd() < 0))\r         {\r                      std::deque<std::string> params;\r                        params.push_back(parameters[1]);\r                       Utils->DoOneToOne(user->nick,"IDLE",params,remote->server);\r                    return 1;\r              }\r              else if (!remote)\r              {\r                      user->WriteServ("401 %s %s :No such nick/channel",user->nick, parameters[1]);\r                  user->WriteServ("318 %s %s :End of /WHOIS list.",user->nick, parameters[1]);\r                   return 1;\r              }\r      }\r      return 0;\r}\r\rvoid ModuleSpanningTree::DoPingChecks(time_t curtime)\r{\r   for (unsigned int j = 0; j < Utils->TreeRoot->ChildCount(); j++)\r       {\r              TreeServer* serv = Utils->TreeRoot->GetChild(j);\r               TreeSocket* sock = serv->GetSocket();\r          if (sock)\r              {\r                      if (curtime >= serv->NextPingTime())\r                   {\r                              if (serv->AnsweredLastPing())\r                          {\r                                      sock->WriteLine(std::string(":")+ServerInstance->Config->ServerName+" PING "+serv->GetName());\r                                 serv->SetNextPingTime(curtime + 60);\r                                   serv->LastPing = curtime;\r                                      serv->Warned = false;\r                          }\r                              else\r                           {\r                                      /* they didnt answer, boot them */\r                                     sock->SendError("Ping timeout");\r                                       sock->Squit(serv,"Ping timeout");\r                                      /*** XXX SOCKET CULL ***/\r                                      return;\r                                }\r                      }\r                      else if ((Utils->PingWarnTime) && (!serv->Warned) && (curtime >= serv->NextPingTime() - (60 - Utils->PingWarnTime)) && (!serv->AnsweredLastPing()))\r                    {\r                              /* The server hasnt responded, send a warning to opers */\r                              ServerInstance->SNO->WriteToSnoMask('l',"Server \002%s\002 has not responded to PING for %d seconds, high latency.", serv->GetName().c_str(), Utils->PingWarnTime);\r                            serv->Warned = true;\r                   }\r              }\r      }\r\r     /* Cancel remote burst mode on any servers which still have it enabled due to latency/lack of data.\r     * This prevents lost REMOTECONNECT notices\r     */\r    for (server_hash::iterator i = Utils->serverlist.begin(); i != Utils->serverlist.end(); i++)\r           Utils->SetRemoteBursting(i->second, false);\r}\r\rvoid ModuleSpanningTree::ConnectServer(Link* x)\r{\r       bool ipvalid = true;\r   QueryType start_type = DNS_QUERY_A;\r#ifdef IPV6\r        start_type = DNS_QUERY_AAAA;\r   if (strchr(x->IPAddr.c_str(),':'))\r     {\r              in6_addr n;\r            if (inet_pton(AF_INET6, x->IPAddr.c_str(), &n) < 1)\r                    ipvalid = false;\r       }\r      else\r#endif\r    {\r              in_addr n;\r             if (inet_aton(x->IPAddr.c_str(),&n) < 1)\r                       ipvalid = false;\r       }\r\r     /* Do we already have an IP? If so, no need to resolve it. */\r  if (ipvalid)\r   {\r              /* Gave a hook, but it wasnt one we know */\r            if ((!x->Hook.empty()) && (Utils->hooks.find(x->Hook.c_str()) == Utils->hooks.end()))\r                  return;\r                TreeSocket* newsocket = new TreeSocket(Utils, ServerInstance, x->IPAddr,x->Port,false,x->Timeout ? x->Timeout : 10,x->Name.c_str(), x->Bind, x->Hook.empty() ? NULL : Utils->hooks[x->Hook.c_str()]);\r          if (newsocket->GetFd() > -1)\r           {\r                      /* Handled automatically on success */\r         }\r              else\r           {\r                      ServerInstance->SNO->WriteToSnoMask('l',"CONNECT: Error connecting \002%s\002: %s.",x->Name.c_str(),strerror(errno));\r                  delete newsocket;\r                      Utils->DoFailOver(x);\r          }\r      }\r      else\r   {\r              try\r            {\r                      bool cached;\r                   ServernameResolver* snr = new ServernameResolver((Module*)this, Utils, ServerInstance,x->IPAddr, *x, cached, start_type);\r                      ServerInstance->AddResolver(snr, cached);\r              }\r              catch (ModuleException& e)\r             {\r                      ServerInstance->SNO->WriteToSnoMask('l',"CONNECT: Error connecting \002%s\002: %s.",x->Name.c_str(), e.GetReason());\r                   Utils->DoFailOver(x);\r          }\r      }\r}\r\rvoid ModuleSpanningTree::AutoConnectServers(time_t curtime)\r{\r     for (std::vector<Link>::iterator x = Utils->LinkBlocks.begin(); x < Utils->LinkBlocks.end(); x++)\r      {\r              if ((x->AutoConnect) && (curtime >= x->NextConnectTime))\r               {\r                      x->NextConnectTime = curtime + x->AutoConnect;\r                 TreeServer* CheckDupe = Utils->FindServer(x->Name.c_str());\r                    if (x->FailOver.length())\r                      {\r                              TreeServer* CheckFailOver = Utils->FindServer(x->FailOver.c_str());\r                            if (CheckFailOver)\r                             {\r                                      /* The failover for this server is currently a member of the network.\r                                   * The failover probably succeeded, where the main link did not.\r                                        * Don't try the main link until the failover is gone again.\r                                    */\r                                    continue;\r                              }\r                      }\r                      if (!CheckDupe)\r                        {\r                              // an autoconnected server is not connected. Check if its time to connect it\r                           ServerInstance->SNO->WriteToSnoMask('l',"AUTOCONNECT: Auto-connecting server \002%s\002 (%lu seconds until next attempt)",x->Name.c_str(),x->AutoConnect);\r                             this->ConnectServer(&(*x));\r                    }\r              }\r      }\r}\r\rint ModuleSpanningTree::HandleVersion(const char** parameters, int pcnt, userrec* user)\r{\r // we've already checked if pcnt > 0, so this is safe\r  TreeServer* found = Utils->FindServerMask(parameters[0]);\r      if (found)\r     {\r              std::string Version = found->GetVersion();\r             user->WriteServ("351 %s :%s",user->nick,Version.c_str());\r              if (found == Utils->TreeRoot)\r          {\r                      ServerInstance->Config->Send005(user);\r         }\r      }\r      else\r   {\r              user->WriteServ("402 %s %s :No such server",user->nick,parameters[0]);\r }\r      return 1;\r}\r    \rint ModuleSpanningTree::HandleConnect(const char** parameters, int pcnt, userrec* user)\r{\r     for (std::vector<Link>::iterator x = Utils->LinkBlocks.begin(); x < Utils->LinkBlocks.end(); x++)\r      {\r              if (ServerInstance->MatchText(x->Name.c_str(),parameters[0]))\r          {\r                      TreeServer* CheckDupe = Utils->FindServer(x->Name.c_str());\r                    if (!CheckDupe)\r                        {\r                              user->WriteServ("NOTICE %s :*** CONNECT: Connecting to server: \002%s\002 (%s:%d)",user->nick,x->Name.c_str(),(x->HiddenFromStats ? "<hidden>" : x->IPAddr.c_str()),x->Port);\r                          ConnectServer(&(*x));\r                          return 1;\r                      }\r                      else\r                   {\r                              user->WriteServ("NOTICE %s :*** CONNECT: Server \002%s\002 already exists on the network and is connected via \002%s\002",user->nick,x->Name.c_str(),CheckDupe->GetParent()->GetName().c_str());\r                               return 1;\r                      }\r              }\r      }\r      user->WriteServ("NOTICE %s :*** CONNECT: No server matching \002%s\002 could be found in the config file.",user->nick,parameters[0]);\r  return 1;\r}\r\rvoid ModuleSpanningTree::BroadcastTimeSync()\r{\r    if (Utils->MasterTime)\r {\r              std::deque<std::string> params;\r                params.push_back(ConvToStr(ServerInstance->Time(false)));\r              params.push_back("FORCE");\r             Utils->DoOneToMany(Utils->TreeRoot->GetName(), "TIMESET", params);\r     }\r}\r\rint ModuleSpanningTree::OnStats(char statschar, userrec* user, string_list &results)\r{\r    if ((statschar == 'c') || (statschar == 'n'))\r  {\r              for (unsigned int i = 0; i < Utils->LinkBlocks.size(); i++)\r            {\r                      results.push_back(std::string(ServerInstance->Config->ServerName)+" 213 "+user->nick+" "+statschar+" *@"+(Utils->LinkBlocks[i].HiddenFromStats ? "<hidden>" : Utils->LinkBlocks[i].IPAddr)+" * "+Utils->LinkBlocks[i].Name.c_str()+" "+ConvToStr(Utils->LinkBlocks[i].Port)+" "+(Utils->LinkBlocks[i].Hook.empty() ? "plaintext" : Utils->LinkBlocks[i].Hook)+" "+(Utils->LinkBlocks[i].AutoConnect ? 'a' : '-')+'s');\r                 if (statschar == 'c')\r                          results.push_back(std::string(ServerInstance->Config->ServerName)+" 244 "+user->nick+" H * * "+Utils->LinkBlocks[i].Name.c_str());\r             }\r              results.push_back(std::string(ServerInstance->Config->ServerName)+" 219 "+user->nick+" "+statschar+" :End of /STATS report");\r          ServerInstance->SNO->WriteToSnoMask('t',"%s '%c' requested by %s (%s@%s)",(!strcmp(user->server,ServerInstance->Config->ServerName) ? "Stats" : "Remote stats"),statschar,user->nick,user->ident,user->host);\r          return 1;\r      }\r\r     if (statschar == 'p')\r  {\r              /* show all server ports, after showing client ports. -- w00t */\r\r              for (unsigned int i = 0; i < Utils->Bindings.size(); i++)\r              {\r                      std::string ip = Utils->Bindings[i]->IP;\r                       if (ip.empty())\r                                ip = "*";\r\r                     std::string transport("plaintext");\r                    if (Utils->Bindings[i]->GetHook())\r                             transport = InspSocketNameRequest(this, Utils->Bindings[i]->GetHook()).Send();\r\r                        results.push_back(ConvToStr(ServerInstance->Config->ServerName) + " 249 "+user->nick+" :" + ip + ":" + ConvToStr(Utils->Bindings[i]->port)+\r                            " (server, " + transport + ")");\r               }\r      }\r      return 0;\r}\r\rint ModuleSpanningTree::OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line)\r{\r    /* If the command doesnt appear to be valid, we dont want to mess with it. */\r  if (!validated)\r                return 0;\r\r     if (command == "CONNECT")\r      {\r              return this->HandleConnect(parameters,pcnt,user);\r      }\r      else if (command == "STATS")\r   {\r              return this->HandleStats(parameters,pcnt,user);\r        }\r      else if (command == "MOTD")\r    {\r              return this->HandleMotd(parameters,pcnt,user);\r }\r      else if (command == "ADMIN")\r   {\r              return this->HandleAdmin(parameters,pcnt,user);\r        }\r      else if (command == "SQUIT")\r   {\r              return this->HandleSquit(parameters,pcnt,user);\r        }\r      else if (command == "MAP")\r     {\r              this->HandleMap(parameters,pcnt,user);\r         return 1;\r      }\r      else if ((command == "TIME") && (pcnt > 0))\r    {\r              return this->HandleTime(parameters,pcnt,user);\r }\r      else if (command == "LUSERS")\r  {\r              this->HandleLusers(parameters,pcnt,user);\r              return 1;\r      }\r      else if (command == "LINKS")\r   {\r              this->HandleLinks(parameters,pcnt,user);\r               return 1;\r      }\r      else if (command == "WHOIS")\r   {\r              if (pcnt > 1)\r          {\r                      // remote whois\r                        return this->HandleRemoteWhois(parameters,pcnt,user);\r          }\r      }\r      else if ((command == "VERSION") && (pcnt > 0))\r {\r              this->HandleVersion(parameters,pcnt,user);\r             return 1;\r      }\r      else if ((command == "MODULES") && (pcnt > 0))\r {\r              return this->HandleModules(parameters,pcnt,user);\r      }\r      return 0;\r}\r\rvoid ModuleSpanningTree::OnPostCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, CmdResult result, const std::string &original_line)\r{\r        if ((result == CMD_SUCCESS) && (ServerInstance->IsValidModuleCommand(command, pcnt, user)))\r    {\r              // this bit of code cleverly routes all module commands\r                // to all remote severs *automatically* so that modules\r                // can just handle commands locally, without having\r            // to have any special provision in place for remote\r           // commands and linking protocols.\r             std::deque<std::string> params;\r                params.clear();\r                for (int j = 0; j < pcnt; j++)\r         {\r                      if (strchr(parameters[j],' '))\r                 {\r                              params.push_back(":" + std::string(parameters[j]));\r                    }\r                      else\r                   {\r                              params.push_back(std::string(parameters[j]));\r                  }\r              }\r              Utils->DoOneToMany(user->nick,command,params);\r }\r}\r\rvoid ModuleSpanningTree::OnGetServerDescription(const std::string &servername,std::string &description)\r{\r TreeServer* s = Utils->FindServer(servername);\r if (s)\r {\r              description = s->GetDesc();\r    }\r}\r\rvoid ModuleSpanningTree::OnUserInvite(userrec* source,userrec* dest,chanrec* channel)\r{\r   if (IS_LOCAL(source))\r  {\r              std::deque<std::string> params;\r                params.push_back(dest->nick);\r          params.push_back(channel->name);\r               Utils->DoOneToMany(source->nick,"INVITE",params);\r      }\r}\r\rvoid ModuleSpanningTree::OnPostLocalTopicChange(userrec* user, chanrec* chan, const std::string &topic)\r{\r std::deque<std::string> params;\r        params.push_back(chan->name);\r  params.push_back(":"+topic);\r   Utils->DoOneToMany(user->nick,"TOPIC",params);\r}\r\rvoid ModuleSpanningTree::OnWallops(userrec* user, const std::string &text)\r{\r if (IS_LOCAL(user))\r    {\r              std::deque<std::string> params;\r                params.push_back(":"+text);\r            Utils->DoOneToMany(user->nick,"WALLOPS",params);\r       }\r}\r\rvoid ModuleSpanningTree::OnUserNotice(userrec* user, void* dest, int target_type, const std::string &text, char status, const CUList &exempt_list)\r{\r      if (target_type == TYPE_USER)\r  {\r              userrec* d = (userrec*)dest;\r           if ((d->GetFd() < 0) && (IS_LOCAL(user)))\r              {\r                      std::deque<std::string> params;\r                        params.clear();\r                        params.push_back(d->nick);\r                     params.push_back(":"+text);\r                    Utils->DoOneToOne(user->nick,"NOTICE",params,d->server);\r               }\r      }\r      else if (target_type == TYPE_CHANNEL)\r  {\r              if (IS_LOCAL(user))\r            {\r                      chanrec *c = (chanrec*)dest;\r                   if (c)\r                 {\r                              std::string cname = c->name;\r                           if (status)\r                                    cname = status + cname;\r                                TreeServerList list;\r                           Utils->GetListOfServersForChannel(c,list,status,exempt_list);\r                          for (TreeServerList::iterator i = list.begin(); i != list.end(); i++)\r                          {\r                                      TreeSocket* Sock = i->second->GetSocket();\r                                     if (Sock)\r                                              Sock->WriteLine(":"+std::string(user->nick)+" NOTICE "+cname+" :"+text);\r                               }\r                      }\r              }\r      }\r      else if (target_type == TYPE_SERVER)\r   {\r              if (IS_LOCAL(user))\r            {\r                      char* target = (char*)dest;\r                    std::deque<std::string> par;\r                   par.push_back(target);\r                 par.push_back(":"+text);\r                       Utils->DoOneToMany(user->nick,"NOTICE",par);\r           }\r      }\r}\r\rvoid ModuleSpanningTree::OnUserMessage(userrec* user, void* dest, int target_type, const std::string &text, char status, const CUList &exempt_list)\r{\r     if (target_type == TYPE_USER)\r  {\r              // route private messages which are targetted at clients only to the server\r            // which needs to receive them\r         userrec* d = (userrec*)dest;\r           if ((d->GetFd() < 0) && (IS_LOCAL(user)))\r              {\r                      std::deque<std::string> params;\r                        params.clear();\r                        params.push_back(d->nick);\r                     params.push_back(":"+text);\r                    Utils->DoOneToOne(user->nick,"PRIVMSG",params,d->server);\r              }\r      }\r      else if (target_type == TYPE_CHANNEL)\r  {\r              if (IS_LOCAL(user))\r            {\r                      chanrec *c = (chanrec*)dest;\r                   if (c)\r                 {\r                              std::string cname = c->name;\r                           if (status)\r                                    cname = status + cname;\r                                TreeServerList list;\r                           Utils->GetListOfServersForChannel(c,list,status,exempt_list);\r                          for (TreeServerList::iterator i = list.begin(); i != list.end(); i++)\r                          {\r                                      TreeSocket* Sock = i->second->GetSocket();\r                                     if (Sock)\r                                              Sock->WriteLine(":"+std::string(user->nick)+" PRIVMSG "+cname+" :"+text);\r                              }\r                      }\r              }\r      }\r      else if (target_type == TYPE_SERVER)\r   {\r              if (IS_LOCAL(user))\r            {\r                      char* target = (char*)dest;\r                    std::deque<std::string> par;\r                   par.push_back(target);\r                 par.push_back(":"+text);\r                       Utils->DoOneToMany(user->nick,"PRIVMSG",par);\r          }\r      }\r}\r\rvoid ModuleSpanningTree::OnBackgroundTimer(time_t curtime)\r{\r      AutoConnectServers(curtime);\r   DoPingChecks(curtime);\r}\r\rvoid ModuleSpanningTree::OnUserJoin(userrec* user, chanrec* channel, bool &silent)\r{\r // Only do this for local users\r        if (IS_LOCAL(user))\r    {\r              if (channel->GetUserCounter() == 1)\r            {\r                      std::deque<std::string> params;\r                        // set up their permissions and the channel TS with FJOIN.\r                     // All users are FJOINed now, because a module may specify\r                     // new joining permissions for the user.\r                       params.push_back(channel->name);\r                       params.push_back(ConvToStr(channel->age));\r                     params.push_back(std::string(channel->GetAllPrefixChars(user))+","+std::string(user->nick));\r                   Utils->DoOneToMany(ServerInstance->Config->ServerName,"FJOIN",params);\r                 /* First user in, sync the modes for the channel */\r                    params.pop_back();\r                     params.push_back(channel->ChanModes(true));\r                    Utils->DoOneToMany(ServerInstance->Config->ServerName,"FMODE",params);\r         }\r              else\r           {\r                      std::deque<std::string> params;\r                        params.push_back(channel->name);\r                       params.push_back(ConvToStr(channel->age));\r                     Utils->DoOneToMany(user->nick,"JOIN",params);\r          }\r      }\r}\r\rvoid ModuleSpanningTree::OnChangeHost(userrec* user, const std::string &newhost)\r{\r        // only occurs for local clients\r       if (user->registered != REG_ALL)\r               return;\r        std::deque<std::string> params;\r        params.push_back(newhost);\r     Utils->DoOneToMany(user->nick,"FHOST",params);\r}\r\rvoid ModuleSpanningTree::OnChangeName(userrec* user, const std::string &gecos)\r{\r     // only occurs for local clients\r       if (user->registered != REG_ALL)\r               return;\r        std::deque<std::string> params;\r        params.push_back(gecos);\r       Utils->DoOneToMany(user->nick,"FNAME",params);\r}\r\rvoid ModuleSpanningTree::OnUserPart(userrec* user, chanrec* channel, const std::string &partmessage, bool &silent)\r{\r if (IS_LOCAL(user))\r    {\r              std::deque<std::string> params;\r                params.push_back(channel->name);\r               if (!partmessage.empty())\r                      params.push_back(":"+partmessage);\r             Utils->DoOneToMany(user->nick,"PART",params);\r  }\r}\r\rvoid ModuleSpanningTree::OnUserConnect(userrec* user)\r{\r   char agestr[MAXBUF];\r   if (IS_LOCAL(user))\r    {\r              std::deque<std::string> params;\r                snprintf(agestr,MAXBUF,"%lu",(unsigned long)user->age);\r                params.push_back(agestr);\r              params.push_back(user->nick);\r          params.push_back(user->host);\r          params.push_back(user->dhost);\r         params.push_back(user->ident);\r         params.push_back("+"+std::string(user->FormatModes()));\r                params.push_back(user->GetIPString());\r         params.push_back(":"+std::string(user->fullname));\r             Utils->DoOneToMany(ServerInstance->Config->ServerName,"NICK",params);\r          // User is Local, change needs to be reflected!\r                TreeServer* SourceServer = Utils->FindServer(user->server);\r            if (SourceServer)\r              {\r                      SourceServer->AddUserCount();\r          }\r      }\r}\r\rvoid ModuleSpanningTree::OnUserQuit(userrec* user, const std::string &reason, const std::string &oper_message)\r{\r  if ((IS_LOCAL(user)) && (user->registered == REG_ALL))\r {\r              std::deque<std::string> params;\r\r               if (oper_message != reason)\r            {\r                      params.push_back(":"+oper_message);\r                    Utils->DoOneToMany(user->nick,"OPERQUIT",params);\r              }\r              params.clear();\r                params.push_back(":"+reason);\r          Utils->DoOneToMany(user->nick,"QUIT",params);\r  }\r      // Regardless, We need to modify the user Counts..\r     TreeServer* SourceServer = Utils->FindServer(user->server);\r    if (SourceServer)\r      {\r              SourceServer->DelUserCount();\r  }\r}\r\rvoid ModuleSpanningTree::OnUserPostNick(userrec* user, const std::string &oldnick)\r{\r      if (IS_LOCAL(user))\r    {\r              std::deque<std::string> params;\r                params.push_back(user->nick);\r          Utils->DoOneToMany(oldnick,"NICK",params);\r     }\r}\r\rvoid ModuleSpanningTree::OnUserKick(userrec* source, userrec* user, chanrec* chan, const std::string &reason, bool &silent)\r{\r     if ((source) && (IS_LOCAL(source)))\r    {\r              std::deque<std::string> params;\r                params.push_back(chan->name);\r          params.push_back(user->nick);\r          params.push_back(":"+reason);\r          Utils->DoOneToMany(source->nick,"KICK",params);\r        }\r      else if (!source)\r      {\r              std::deque<std::string> params;\r                params.push_back(chan->name);\r          params.push_back(user->nick);\r          params.push_back(":"+reason);\r          Utils->DoOneToMany(ServerInstance->Config->ServerName,"KICK",params);\r  }\r}\r\rvoid ModuleSpanningTree::OnRemoteKill(userrec* source, userrec* dest, const std::string &reason, const std::string &operreason)\r{\r std::deque<std::string> params;\r        params.push_back(":"+reason);\r  Utils->DoOneToMany(dest->nick,"OPERQUIT",params);\r      params.clear();\r        params.push_back(dest->nick);\r  params.push_back(":"+reason);\r  dest->SetOperQuit(operreason);\r Utils->DoOneToMany(source->nick,"KILL",params);\r}\r\rvoid ModuleSpanningTree::OnRehash(userrec* user, const std::string &parameter)\r{\r    if (!parameter.empty())\r        {\r              std::deque<std::string> params;\r                params.push_back(parameter);\r           Utils->DoOneToMany(user ? user->nick : ServerInstance->Config->ServerName, "REHASH", params);\r          // check for self\r              if (ServerInstance->MatchText(ServerInstance->Config->ServerName,parameter))\r           {\r                      ServerInstance->WriteOpers("*** Remote rehash initiated locally by \002%s\002", user ? user->nick : ServerInstance->Config->ServerName);\r                       ServerInstance->RehashServer();\r                }\r      }\r      Utils->ReadConfiguration(false);\r       InitializeDisabledCommands(ServerInstance->Config->DisabledCommands, ServerInstance);\r}\r\r// note: the protocol does not allow direct umode +o except\r// via NICK with 8 params. sending OPERTYPE infers +o modechange\r// locally.\rvoid ModuleSpanningTree::OnOper(userrec* user, const std::string &opertype)\r{\r        if (IS_LOCAL(user))\r    {\r              std::deque<std::string> params;\r                params.push_back(opertype);\r            Utils->DoOneToMany(user->nick,"OPERTYPE",params);\r      }\r}\r\rvoid ModuleSpanningTree::OnLine(userrec* source, const std::string &host, bool adding, char linetype, long duration, const std::string &reason)\r{\r if (!source)\r   {\r              /* Server-set lines */\r         char data[MAXBUF];\r             snprintf(data,MAXBUF,"%c %s %s %lu %lu :%s", linetype, host.c_str(), ServerInstance->Config->ServerName, (unsigned long)ServerInstance->Time(false),\r                           (unsigned long)duration, reason.c_str());\r              std::deque<std::string> params;\r                params.push_back(data);\r                Utils->DoOneToMany(ServerInstance->Config->ServerName, "ADDLINE", params);\r     }\r      else\r   {\r              if (IS_LOCAL(source))\r          {\r                      char type[8];\r                  snprintf(type,8,"%cLINE",linetype);\r                    std::string stype = type;\r                      if (adding)\r                    {\r                              char sduration[MAXBUF];\r                                snprintf(sduration,MAXBUF,"%ld",duration);\r                             std::deque<std::string> params;\r                                params.push_back(host);\r                                params.push_back(sduration);\r                           params.push_back(":"+reason);\r                          Utils->DoOneToMany(source->nick,stype,params);\r                 }\r                      else\r                   {\r                              std::deque<std::string> params;\r                                params.push_back(host);\r                                Utils->DoOneToMany(source->nick,stype,params);\r                 }\r              }\r      }\r}\r\rvoid ModuleSpanningTree::OnAddGLine(long duration, userrec* source, const std::string &reason, const std::string &hostmask)\r{\r     OnLine(source,hostmask,true,'G',duration,reason);\r}\r    \rvoid ModuleSpanningTree::OnAddZLine(long duration, userrec* source, const std::string &reason, const std::string &ipmask)\r{\r   OnLine(source,ipmask,true,'Z',duration,reason);\r}\r\rvoid ModuleSpanningTree::OnAddQLine(long duration, userrec* source, const std::string &reason, const std::string &nickmask)\r{\r       OnLine(source,nickmask,true,'Q',duration,reason);\r}\r\rvoid ModuleSpanningTree::OnAddELine(long duration, userrec* source, const std::string &reason, const std::string &hostmask)\r{\r     OnLine(source,hostmask,true,'E',duration,reason);\r}\r\rvoid ModuleSpanningTree::OnDelGLine(userrec* source, const std::string &hostmask)\r{\r       OnLine(source,hostmask,false,'G',0,"");\r}\r\rvoid ModuleSpanningTree::OnDelZLine(userrec* source, const std::string &ipmask)\r{\r   OnLine(source,ipmask,false,'Z',0,"");\r}\r\rvoid ModuleSpanningTree::OnDelQLine(userrec* source, const std::string &nickmask)\r{\r   OnLine(source,nickmask,false,'Q',0,"");\r}\r\rvoid ModuleSpanningTree::OnDelELine(userrec* source, const std::string &hostmask)\r{\r OnLine(source,hostmask,false,'E',0,"");\r}\r\rvoid ModuleSpanningTree::OnMode(userrec* user, void* dest, int target_type, const std::string &text)\r{\r      if ((IS_LOCAL(user)) && (user->registered == REG_ALL))\r {\r              std::deque<std::string> params;\r                std::string command;\r\r          if (target_type == TYPE_USER)\r          {\r                      userrec* u = (userrec*)dest;\r                   params.push_back(u->nick);\r                     params.push_back(text);\r                        command = "MODE";\r              }\r              else\r           {\r                      chanrec* c = (chanrec*)dest;\r                   params.push_back(c->name);\r                     params.push_back(ConvToStr(c->age));\r                   params.push_back(text);\r                        command = "FMODE";\r             }\r              Utils->DoOneToMany(user->nick, command, params);\r       }\r}\r\rvoid ModuleSpanningTree::OnSetAway(userrec* user)\r{\r       if (IS_LOCAL(user))\r    {\r              std::deque<std::string> params;\r                params.push_back(":"+std::string(user->awaymsg));\r              Utils->DoOneToMany(user->nick,"AWAY",params);\r  }\r}\r\rvoid ModuleSpanningTree::OnCancelAway(userrec* user)\r{\r    if (IS_LOCAL(user))\r    {\r              std::deque<std::string> params;\r                params.clear();\r                Utils->DoOneToMany(user->nick,"AWAY",params);\r  }\r}\r\rvoid ModuleSpanningTree::ProtoSendMode(void* opaque, int target_type, void* target, const std::string &modeline)\r{\r        TreeSocket* s = (TreeSocket*)opaque;\r   if (target)\r    {\r              if (target_type == TYPE_USER)\r          {\r                      userrec* u = (userrec*)target;\r                 s->WriteLine(std::string(":")+ServerInstance->Config->ServerName+" FMODE "+u->nick+" "+ConvToStr(u->age)+" "+modeline);\r                }\r              else\r           {\r                      chanrec* c = (chanrec*)target;\r                 s->WriteLine(std::string(":")+ServerInstance->Config->ServerName+" FMODE "+c->name+" "+ConvToStr(c->age)+" "+modeline);\r                }\r      }\r}\r\rvoid ModuleSpanningTree::ProtoSendMetaData(void* opaque, int target_type, void* target, const std::string &extname, const std::string &extdata)\r{\r TreeSocket* s = (TreeSocket*)opaque;\r   if (target)\r    {\r              if (target_type == TYPE_USER)\r          {\r                      userrec* u = (userrec*)target;\r                 s->WriteLine(std::string(":")+ServerInstance->Config->ServerName+" METADATA "+u->nick+" "+extname+" :"+extdata);\r               }\r              else if (target_type == TYPE_CHANNEL)\r          {\r                      chanrec* c = (chanrec*)target;\r                 s->WriteLine(std::string(":")+ServerInstance->Config->ServerName+" METADATA "+c->name+" "+extname+" :"+extdata);\r               }\r      }\r      if (target_type == TYPE_OTHER)\r {\r              s->WriteLine(std::string(":")+ServerInstance->Config->ServerName+" METADATA * "+extname+" :"+extdata);\r }\r}\r\rvoid ModuleSpanningTree::OnEvent(Event* event)\r{\r  std::deque<std::string>* params = (std::deque<std::string>*)event->GetData();\r  if (event->GetEventID() == "send_metadata")\r    {\r              if (params->size() < 3)\r                        return;\r                (*params)[2] = ":" + (*params)[2];\r             Utils->DoOneToMany(ServerInstance->Config->ServerName,"METADATA",*params);\r     }\r      else if (event->GetEventID() == "send_topic")\r  {\r              if (params->size() < 2)\r                        return;\r                (*params)[1] = ":" + (*params)[1];\r             params->insert(params->begin() + 1,ServerInstance->Config->ServerName);\r                params->insert(params->begin() + 1,ConvToStr(ServerInstance->Time(true)));\r             Utils->DoOneToMany(ServerInstance->Config->ServerName,"FTOPIC",*params);\r       }\r      else if (event->GetEventID() == "send_mode")\r   {\r              if (params->size() < 2)\r                        return;\r                // Insert the TS value of the object, either userrec or chanrec\r                time_t ourTS = 0;\r              userrec* a = ServerInstance->FindNick((*params)[0]);\r           if (a)\r         {\r                      ourTS = a->age;\r                        Utils->DoOneToMany(ServerInstance->Config->ServerName,"MODE",*params);\r                 return;\r                }\r              else\r           {\r                      chanrec* a = ServerInstance->FindChan((*params)[0]);\r                   if (a)\r                 {\r                              ourTS = a->age;\r                                params->insert(params->begin() + 1,ConvToStr(ourTS));\r                          Utils->DoOneToMany(ServerInstance->Config->ServerName,"FMODE",*params);\r                        }\r              }\r      }\r      else if (event->GetEventID() == "send_mode_explicit")\r  {\r              if (params->size() < 2)\r                        return;\r                Utils->DoOneToMany(ServerInstance->Config->ServerName,"MODE",*params);\r }\r      else if (event->GetEventID() == "send_opers")\r  {\r              if (params->size() < 1)\r                        return;\r                (*params)[0] = ":" + (*params)[0];\r             Utils->DoOneToMany(ServerInstance->Config->ServerName,"OPERNOTICE",*params);\r   }\r      else if (event->GetEventID() == "send_modeset")\r        {\r              if (params->size() < 2)\r                        return;\r                (*params)[1] = ":" + (*params)[1];\r             Utils->DoOneToMany(ServerInstance->Config->ServerName,"MODENOTICE",*params);\r   }\r      else if (event->GetEventID() == "send_snoset")\r {\r              if (params->size() < 2)\r                        return;\r                (*params)[1] = ":" + (*params)[1];\r             Utils->DoOneToMany(ServerInstance->Config->ServerName,"SNONOTICE",*params);\r    }\r      else if (event->GetEventID() == "send_push")\r   {\r              if (params->size() < 2)\r                        return;\r                        \r               userrec *a = ServerInstance->FindNick((*params)[0]);\r                   \r               if (!a)\r                        return;\r                        \r               (*params)[1] = ":" + (*params)[1];\r             Utils->DoOneToOne(ServerInstance->Config->ServerName, "PUSH", *params, a->server);\r     }\r}\r\rModuleSpanningTree::~ModuleSpanningTree()\r{\r       /* This will also free the listeners */\r        delete Utils;\r  if (SyncTimer)\r         ServerInstance->Timers->DelTimer(SyncTimer);\r\r  ServerInstance->Timers->DelTimer(RefreshTimer);\r\r       ServerInstance->DoneWithInterface("InspSocketHook");\r}\r\rVersion ModuleSpanningTree::GetVersion()\r{\r     return Version(1,1,0,2,VF_VENDOR,API_VERSION);\r}\r\rvoid ModuleSpanningTree::Implements(char* List)\r{\r    List[I_OnPreCommand] = List[I_OnGetServerDescription] = List[I_OnUserInvite] = List[I_OnPostLocalTopicChange] = 1;\r     List[I_OnWallops] = List[I_OnUserNotice] = List[I_OnUserMessage] = List[I_OnBackgroundTimer] = 1;\r      List[I_OnUserJoin] = List[I_OnChangeHost] = List[I_OnChangeName] = List[I_OnUserPart] = List[I_OnUserConnect] = 1;\r     List[I_OnUserQuit] = List[I_OnUserPostNick] = List[I_OnUserKick] = List[I_OnRemoteKill] = List[I_OnRehash] = 1;\r        List[I_OnOper] = List[I_OnAddGLine] = List[I_OnAddZLine] = List[I_OnAddQLine] = List[I_OnAddELine] = 1;\r        List[I_OnDelGLine] = List[I_OnDelZLine] = List[I_OnDelQLine] = List[I_OnDelELine] = List[I_ProtoSendMode] = List[I_OnMode] = 1;\r        List[I_OnStats] = List[I_ProtoSendMetaData] = List[I_OnEvent] = List[I_OnSetAway] = List[I_OnCancelAway] = List[I_OnPostCommand] = 1;\r}\r\r/* It is IMPORTANT that m_spanningtree is the last module in the chain\r * so that any activity it sees is FINAL, e.g. we arent going to send out\r * a NICK message before m_cloaking has finished putting the +x on the user,\r * etc etc.\r * Therefore, we return PRIORITY_LAST to make sure we end up at the END of\r * the module call queue.\r */\rPriority ModuleSpanningTree::Prioritize()\r{\r        return PRIORITY_LAST;\r}\r\rMODULE_INIT(ModuleSpanningTree)\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *         the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+/* $ModDesc: Provides a spanning tree server link protocol */
+
+#include "inspircd.h"
+#include "configreader.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+#include "commands/cmd_whois.h"
+#include "commands/cmd_stats.h"
+#include "socket.h"
+#include "wildcard.h"
+#include "xline.h"
+#include "transport.h"
+
+#include "m_spanningtree/timesynctimer.h"
+#include "m_spanningtree/resolvers.h"
+#include "m_spanningtree/main.h"
+#include "m_spanningtree/utils.h"
+#include "m_spanningtree/treeserver.h"
+#include "m_spanningtree/link.h"
+#include "m_spanningtree/treesocket.h"
+#include "m_spanningtree/rconnect.h"
+#include "m_spanningtree/rsquit.h"
+
+/* $ModDep: m_spanningtree/timesynctimer.h m_spanningtree/resolvers.h m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/link.h m_spanningtree/treesocket.h m_spanningtree/rconnect.h m_spanningtree/rsquit.h */
+
+ModuleSpanningTree::ModuleSpanningTree(InspIRCd* Me)
+       : Module(Me), max_local(0), max_global(0)
+{
+       ServerInstance->UseInterface("InspSocketHook");
+       Utils = new SpanningTreeUtilities(Me, this);
+       command_rconnect = new cmd_rconnect(ServerInstance, this, Utils);
+       ServerInstance->AddCommand(command_rconnect);
+       command_rsquit = new cmd_rsquit(ServerInstance, this, Utils);
+       ServerInstance->AddCommand(command_rsquit);
+       if (Utils->EnableTimeSync)
+       {
+               SyncTimer = new TimeSyncTimer(ServerInstance, this);
+               ServerInstance->Timers->AddTimer(SyncTimer);
+       }
+       else
+               SyncTimer = NULL;
+
+       RefreshTimer = new CacheRefreshTimer(ServerInstance, Utils);
+       ServerInstance->Timers->AddTimer(RefreshTimer);
+}
+
+void ModuleSpanningTree::ShowLinks(TreeServer* Current, userrec* user, int hops)
+{
+       std::string Parent = Utils->TreeRoot->GetName();
+       if (Current->GetParent())
+       {
+               Parent = Current->GetParent()->GetName();
+       }
+       for (unsigned int q = 0; q < Current->ChildCount(); q++)
+       {
+               if ((Current->GetChild(q)->Hidden) || ((Utils->HideULines) && (ServerInstance->ULine(Current->GetChild(q)->GetName().c_str()))))
+               {
+                       if (*user->oper)
+                       {
+                                ShowLinks(Current->GetChild(q),user,hops+1);
+                       }
+               }
+               else
+               {
+                       ShowLinks(Current->GetChild(q),user,hops+1);
+               }
+       }
+       /* Don't display the line if its a uline, hide ulines is on, and the user isnt an oper */
+       if ((Utils->HideULines) && (ServerInstance->ULine(Current->GetName().c_str())) && (!IS_OPER(user)))
+               return;
+       /* Or if the server is hidden and they're not an oper */
+       else if ((Current->Hidden) && (!IS_OPER(user)))
+               return;
+
+       user->WriteServ("364 %s %s %s :%d %s",  user->nick,Current->GetName().c_str(),
+                       (Utils->FlatLinks && (!IS_OPER(user))) ? ServerInstance->Config->ServerName : Parent.c_str(),
+                       (Utils->FlatLinks && (!IS_OPER(user))) ? 0 : hops,
+                       Current->GetDesc().c_str());
+}
+
+int ModuleSpanningTree::CountLocalServs()
+{
+       return Utils->TreeRoot->ChildCount();
+}
+
+int ModuleSpanningTree::CountServs()
+{
+       return Utils->serverlist.size();
+}
+
+void ModuleSpanningTree::HandleLinks(const char** parameters, int pcnt, userrec* user)
+{
+       ShowLinks(Utils->TreeRoot,user,0);
+       user->WriteServ("365 %s * :End of /LINKS list.",user->nick);
+       return;
+}
+
+void ModuleSpanningTree::HandleLusers(const char** parameters, int pcnt, userrec* user)
+{
+       unsigned int n_users = ServerInstance->UserCount();
+
+       /* Only update these when someone wants to see them, more efficient */
+       if ((unsigned int)ServerInstance->LocalUserCount() > max_local)
+               max_local = ServerInstance->LocalUserCount();
+       if (n_users > max_global)
+               max_global = n_users;
+
+       unsigned int ulined_count = 0;
+       unsigned int ulined_local_count = 0;
+
+       /* If ulined are hidden and we're not an oper, count the number of ulined servers hidden,
+        * locally and globally (locally means directly connected to us)
+        */
+       if ((Utils->HideULines) && (!*user->oper))
+       {
+               for (server_hash::iterator q = Utils->serverlist.begin(); q != Utils->serverlist.end(); q++)
+               {
+                       if (ServerInstance->ULine(q->second->GetName().c_str()))
+                       {
+                               ulined_count++;
+                               if (q->second->GetParent() == Utils->TreeRoot)
+                                       ulined_local_count++;
+                       }
+               }
+       }
+       user->WriteServ("251 %s :There are %d users and %d invisible on %d servers",user->nick,n_users-ServerInstance->InvisibleUserCount(),ServerInstance->InvisibleUserCount(),ulined_count ? this->CountServs() - ulined_count : this->CountServs());
+       if (ServerInstance->OperCount())
+               user->WriteServ("252 %s %d :operator(s) online",user->nick,ServerInstance->OperCount());
+       if (ServerInstance->UnregisteredUserCount())
+               user->WriteServ("253 %s %d :unknown connections",user->nick,ServerInstance->UnregisteredUserCount());
+       if (ServerInstance->ChannelCount())
+               user->WriteServ("254 %s %d :channels formed",user->nick,ServerInstance->ChannelCount());
+       user->WriteServ("255 %s :I have %d clients and %d servers",user->nick,ServerInstance->LocalUserCount(),ulined_local_count ? this->CountLocalServs() - ulined_local_count : this->CountLocalServs());
+       user->WriteServ("265 %s :Current Local Users: %d  Max: %d",user->nick,ServerInstance->LocalUserCount(),max_local);
+       user->WriteServ("266 %s :Current Global Users: %d  Max: %d",user->nick,n_users,max_global);
+       return;
+}
+
+std::string ModuleSpanningTree::TimeToStr(time_t secs)
+{
+       time_t mins_up = secs / 60;
+       time_t hours_up = mins_up / 60;
+       time_t days_up = hours_up / 24;
+       secs = secs % 60;
+       mins_up = mins_up % 60;
+       hours_up = hours_up % 24;
+       return ((days_up ? (ConvToStr(days_up) + "d") : std::string(""))
+                       + (hours_up ? (ConvToStr(hours_up) + "h") : std::string(""))
+                       + (mins_up ? (ConvToStr(mins_up) + "m") : std::string(""))
+                       + ConvToStr(secs) + "s");
+}
+
+const std::string ModuleSpanningTree::MapOperInfo(TreeServer* Current)
+{
+       time_t secs_up = ServerInstance->Time() - Current->age;
+       return (" [Up: " + TimeToStr(secs_up) + " Lag: "+ConvToStr(Current->rtt)+"s]");
+}
+
+// WARNING: NOT THREAD SAFE - DONT GET ANY SMART IDEAS.
+void ModuleSpanningTree::ShowMap(TreeServer* Current, userrec* user, int depth, char matrix[128][128], float &totusers, float &totservers)
+{
+       if (line < 128)
+       {
+               for (int t = 0; t < depth; t++)
+               {
+                       matrix[line][t] = ' ';
+               }
+               // For Aligning, we need to work out exactly how deep this thing is, and produce
+               // a 'Spacer' String to compensate.
+               char spacer[40];
+               memset(spacer,' ',40);
+               if ((40 - Current->GetName().length() - depth) > 1) {
+                       spacer[40 - Current->GetName().length() - depth] = '\0';
+               }
+               else
+               {
+                       spacer[5] = '\0';
+               }
+               float percent;
+               char text[128];
+               /* Neat and tidy default values, as we're dealing with a matrix not a simple string */
+               memset(text, 0, 128);
+
+               if (ServerInstance->clientlist->size() == 0) {
+                       // If there are no users, WHO THE HELL DID THE /MAP?!?!?!
+                       percent = 0;
+               }
+               else
+               {
+                       percent = ((float)Current->GetUserCount() / (float)ServerInstance->clientlist->size()) * 100;
+               }
+               const std::string operdata = IS_OPER(user) ? MapOperInfo(Current) : "";
+               snprintf(text, 126, "%s %s%5d [%5.2f%%]%s", Current->GetName().c_str(), spacer, Current->GetUserCount(), percent, operdata.c_str());
+               totusers += Current->GetUserCount();
+               totservers++;
+               strlcpy(&matrix[line][depth],text,126);
+               line++;
+               for (unsigned int q = 0; q < Current->ChildCount(); q++)
+               {
+                       if ((Current->GetChild(q)->Hidden) || ((Utils->HideULines) && (ServerInstance->ULine(Current->GetChild(q)->GetName().c_str()))))
+                       {
+                               if (*user->oper)
+                               {
+                                       ShowMap(Current->GetChild(q),user,(Utils->FlatLinks && (!*user->oper)) ? depth : depth+2,matrix,totusers,totservers);
+                               }
+                       }
+                       else
+                       {
+                               ShowMap(Current->GetChild(q),user,(Utils->FlatLinks && (!*user->oper)) ? depth : depth+2,matrix,totusers,totservers);
+                       }
+               }
+       }
+}
+
+int ModuleSpanningTree::HandleMotd(const char** parameters, int pcnt, userrec* user)
+{
+       if (pcnt > 0)
+       {
+               if (match(ServerInstance->Config->ServerName, parameters[0]))
+                       return 0;
+
+               /* Remote MOTD, the server is within the 1st parameter */
+               std::deque<std::string> params;
+               params.push_back(parameters[0]);
+               /* Send it out remotely, generate no reply yet */
+               TreeServer* s = Utils->FindServerMask(parameters[0]);
+               if (s)
+               {
+                       params[0] = s->GetName();
+                       Utils->DoOneToOne(user->nick, "MOTD", params, s->GetName());
+               }
+               else
+                       user->WriteServ( "402 %s %s :No such server", user->nick, parameters[0]);
+               return 1;
+       }
+       return 0;
+}
+
+int ModuleSpanningTree::HandleAdmin(const char** parameters, int pcnt, userrec* user)
+{
+       if (pcnt > 0)
+       {
+               if (match(ServerInstance->Config->ServerName, parameters[0]))
+                       return 0;
+
+               /* Remote ADMIN, the server is within the 1st parameter */
+               std::deque<std::string> params;
+               params.push_back(parameters[0]);
+               /* Send it out remotely, generate no reply yet */
+               TreeServer* s = Utils->FindServerMask(parameters[0]);
+               if (s)
+               {
+                       params[0] = s->GetName();
+                       Utils->DoOneToOne(user->nick, "ADMIN", params, s->GetName());
+               }
+               else
+                       user->WriteServ( "402 %s %s :No such server", user->nick, parameters[0]);
+               return 1;
+       }
+       return 0;
+}
+
+int ModuleSpanningTree::HandleModules(const char** parameters, int pcnt, userrec* user)
+{
+       if (pcnt > 0)
+       {
+               if (match(ServerInstance->Config->ServerName, parameters[0]))
+                       return 0;
+
+               std::deque<std::string> params;
+               params.push_back(parameters[0]);
+               TreeServer* s = Utils->FindServerMask(parameters[0]);
+               if (s)
+               {
+                       params[0] = s->GetName();
+                       Utils->DoOneToOne(user->nick, "MODULES", params, s->GetName());
+               }
+               else
+                       user->WriteServ( "402 %s %s :No such server", user->nick, parameters[0]);
+               return 1;
+       }
+       return 0;
+}
+
+int ModuleSpanningTree::HandleStats(const char** parameters, int pcnt, userrec* user)
+{
+       if (pcnt > 1)
+       {
+               if (match(ServerInstance->Config->ServerName, parameters[1]))
+                       return 0;
+
+               /* Remote STATS, the server is within the 2nd parameter */
+               std::deque<std::string> params;
+               params.push_back(parameters[0]);
+               params.push_back(parameters[1]);
+               /* Send it out remotely, generate no reply yet */
+
+               TreeServer* s = Utils->FindServerMask(parameters[1]);
+               if (s)
+               {
+                       params[1] = s->GetName();
+                       Utils->DoOneToOne(user->nick, "STATS", params, s->GetName());
+               }
+               else
+               {
+                       user->WriteServ( "402 %s %s :No such server", user->nick, parameters[1]);
+               }
+               return 1;
+       }
+       return 0;
+}
+
+// Ok, prepare to be confused.
+// After much mulling over how to approach this, it struck me that
+// the 'usual' way of doing a /MAP isnt the best way. Instead of
+// keeping track of a ton of ascii characters, and line by line
+// under recursion working out where to place them using multiplications
+// and divisons, we instead render the map onto a backplane of characters
+// (a character matrix), then draw the branches as a series of "L" shapes
+// from the nodes. This is not only friendlier on CPU it uses less stack.
+void ModuleSpanningTree::HandleMap(const char** parameters, int pcnt, userrec* user)
+{
+       // This array represents a virtual screen which we will
+       // "scratch" draw to, as the console device of an irc
+       // client does not provide for a proper terminal.
+       float totusers = 0;
+       float totservers = 0;
+       char matrix[128][128];
+       for (unsigned int t = 0; t < 128; t++)
+       {
+               matrix[t][0] = '\0';
+       }
+       line = 0;
+       // The only recursive bit is called here.
+       ShowMap(Utils->TreeRoot,user,0,matrix,totusers,totservers);
+       // Process each line one by one. The algorithm has a limit of
+       // 128 servers (which is far more than a spanning tree should have
+       // anyway, so we're ok). This limit can be raised simply by making
+       // the character matrix deeper, 128 rows taking 10k of memory.
+       for (int l = 1; l < line; l++)
+       {
+               // scan across the line looking for the start of the
+               // servername (the recursive part of the algorithm has placed
+               // the servers at indented positions depending on what they
+               // are related to)
+               int first_nonspace = 0;
+               while (matrix[l][first_nonspace] == ' ')
+               {
+                       first_nonspace++;
+               }
+               first_nonspace--;
+               // Draw the `- (corner) section: this may be overwritten by
+               // another L shape passing along the same vertical pane, becoming
+               // a |- (branch) section instead.
+               matrix[l][first_nonspace] = '-';
+               matrix[l][first_nonspace-1] = '`';
+               int l2 = l - 1;
+               // Draw upwards until we hit the parent server, causing possibly
+               // other corners (`-) to become branches (|-)
+               while ((matrix[l2][first_nonspace-1] == ' ') || (matrix[l2][first_nonspace-1] == '`'))
+               {
+                       matrix[l2][first_nonspace-1] = '|';
+                       l2--;
+               }
+       }
+       // dump the whole lot to the user. This is the easy bit, honest.
+       for (int t = 0; t < line; t++)
+       {
+               user->WriteServ("006 %s :%s",user->nick,&matrix[t][0]);
+       }
+       float avg_users = totusers / totservers;
+       user->WriteServ("270 %s :%.0f server%s and %.0f user%s, average %.2f users per server",user->nick,totservers,(totservers > 1 ? "s" : ""),totusers,(totusers > 1 ? "s" : ""),avg_users);
+       user->WriteServ("007 %s :End of /MAP",user->nick);
+       return;
+}
+
+int ModuleSpanningTree::HandleSquit(const char** parameters, int pcnt, userrec* user)
+{
+       TreeServer* s = Utils->FindServerMask(parameters[0]);
+       if (s)
+       {
+               if (s == Utils->TreeRoot)
+               {
+                       user->WriteServ("NOTICE %s :*** SQUIT: Foolish mortal, you cannot make a server SQUIT itself! (%s matches local server name)",user->nick,parameters[0]);
+                       return 1;
+               }
+               TreeSocket* sock = s->GetSocket();
+               if (sock)
+               {
+                       ServerInstance->SNO->WriteToSnoMask('l',"SQUIT: Server \002%s\002 removed from network by %s",parameters[0],user->nick);
+                       sock->Squit(s,std::string("Server quit by ") + user->GetFullRealHost());
+                       ServerInstance->SE->DelFd(sock);
+                       sock->Close();
+               }
+               else
+               {
+                       if (IS_LOCAL(user))
+                               user->WriteServ("NOTICE %s :*** WARNING: Using SQUIT to split remote servers is deprecated. Please use RSQUIT instead.",user->nick);
+               }
+       }
+       else
+       {
+                user->WriteServ("NOTICE %s :*** SQUIT: The server \002%s\002 does not exist on the network.",user->nick,parameters[0]);
+       }
+       return 1;
+}
+
+int ModuleSpanningTree::HandleTime(const char** parameters, int pcnt, userrec* user)
+{
+       if ((IS_LOCAL(user)) && (pcnt))
+       {
+               TreeServer* found = Utils->FindServerMask(parameters[0]);
+               if (found)
+               {
+                       // we dont' override for local server
+                       if (found == Utils->TreeRoot)
+                               return 0;
+                       
+                       std::deque<std::string> params;
+                       params.push_back(found->GetName());
+                       params.push_back(user->nick);
+                       Utils->DoOneToOne(ServerInstance->Config->ServerName,"TIME",params,found->GetName());
+               }
+               else
+               {
+                       user->WriteServ("402 %s %s :No such server",user->nick,parameters[0]);
+               }
+       }
+       return 1;
+}
+
+int ModuleSpanningTree::HandleRemoteWhois(const char** parameters, int pcnt, userrec* user)
+{
+       if ((IS_LOCAL(user)) && (pcnt > 1))
+       {
+               userrec* remote = ServerInstance->FindNick(parameters[1]);
+               if ((remote) && (remote->GetFd() < 0))
+               {
+                       std::deque<std::string> params;
+                       params.push_back(parameters[1]);
+                       Utils->DoOneToOne(user->nick,"IDLE",params,remote->server);
+                       return 1;
+               }
+               else if (!remote)
+               {
+                       user->WriteServ("401 %s %s :No such nick/channel",user->nick, parameters[1]);
+                       user->WriteServ("318 %s %s :End of /WHOIS list.",user->nick, parameters[1]);
+                       return 1;
+               }
+       }
+       return 0;
+}
+
+void ModuleSpanningTree::DoPingChecks(time_t curtime)
+{
+       for (unsigned int j = 0; j < Utils->TreeRoot->ChildCount(); j++)
+       {
+               TreeServer* serv = Utils->TreeRoot->GetChild(j);
+               TreeSocket* sock = serv->GetSocket();
+               if (sock)
+               {
+                       if (curtime >= serv->NextPingTime())
+                       {
+                               if (serv->AnsweredLastPing())
+                               {
+                                       sock->WriteLine(std::string(":")+ServerInstance->Config->ServerName+" PING "+serv->GetName());
+                                       serv->SetNextPingTime(curtime + 60);
+                                       serv->LastPing = curtime;
+                                       serv->Warned = false;
+                               }
+                               else
+                               {
+                                       /* they didnt answer, boot them */
+                                       sock->SendError("Ping timeout");
+                                       sock->Squit(serv,"Ping timeout");
+                                       /*** XXX SOCKET CULL ***/
+                                       return;
+                               }
+                       }
+                       else if ((Utils->PingWarnTime) && (!serv->Warned) && (curtime >= serv->NextPingTime() - (60 - Utils->PingWarnTime)) && (!serv->AnsweredLastPing()))
+                       {
+                               /* The server hasnt responded, send a warning to opers */
+                               ServerInstance->SNO->WriteToSnoMask('l',"Server \002%s\002 has not responded to PING for %d seconds, high latency.", serv->GetName().c_str(), Utils->PingWarnTime);
+                               serv->Warned = true;
+                       }
+               }
+       }
+
+       /* Cancel remote burst mode on any servers which still have it enabled due to latency/lack of data.
+        * This prevents lost REMOTECONNECT notices
+        */
+       for (server_hash::iterator i = Utils->serverlist.begin(); i != Utils->serverlist.end(); i++)
+               Utils->SetRemoteBursting(i->second, false);
+}
+
+void ModuleSpanningTree::ConnectServer(Link* x)
+{
+       bool ipvalid = true;
+       QueryType start_type = DNS_QUERY_A;
+#ifdef IPV6
+       start_type = DNS_QUERY_AAAA;
+       if (strchr(x->IPAddr.c_str(),':'))
+       {
+               in6_addr n;
+               if (inet_pton(AF_INET6, x->IPAddr.c_str(), &n) < 1)
+                       ipvalid = false;
+       }
+       else
+#endif
+       {
+               in_addr n;
+               if (inet_aton(x->IPAddr.c_str(),&n) < 1)
+                       ipvalid = false;
+       }
+
+       /* Do we already have an IP? If so, no need to resolve it. */
+       if (ipvalid)
+       {
+               /* Gave a hook, but it wasnt one we know */
+               if ((!x->Hook.empty()) && (Utils->hooks.find(x->Hook.c_str()) == Utils->hooks.end()))
+                       return;
+               TreeSocket* newsocket = new TreeSocket(Utils, ServerInstance, x->IPAddr,x->Port,false,x->Timeout ? x->Timeout : 10,x->Name.c_str(), x->Bind, x->Hook.empty() ? NULL : Utils->hooks[x->Hook.c_str()]);
+               if (newsocket->GetFd() > -1)
+               {
+                       /* Handled automatically on success */
+               }
+               else
+               {
+                       ServerInstance->SNO->WriteToSnoMask('l',"CONNECT: Error connecting \002%s\002: %s.",x->Name.c_str(),strerror(errno));
+                       delete newsocket;
+                       Utils->DoFailOver(x);
+               }
+       }
+       else
+       {
+               try
+               {
+                       bool cached;
+                       ServernameResolver* snr = new ServernameResolver((Module*)this, Utils, ServerInstance,x->IPAddr, *x, cached, start_type);
+                       ServerInstance->AddResolver(snr, cached);
+               }
+               catch (ModuleException& e)
+               {
+                       ServerInstance->SNO->WriteToSnoMask('l',"CONNECT: Error connecting \002%s\002: %s.",x->Name.c_str(), e.GetReason());
+                       Utils->DoFailOver(x);
+               }
+       }
+}
+
+void ModuleSpanningTree::AutoConnectServers(time_t curtime)
+{
+       for (std::vector<Link>::iterator x = Utils->LinkBlocks.begin(); x < Utils->LinkBlocks.end(); x++)
+       {
+               if ((x->AutoConnect) && (curtime >= x->NextConnectTime))
+               {
+                       x->NextConnectTime = curtime + x->AutoConnect;
+                       TreeServer* CheckDupe = Utils->FindServer(x->Name.c_str());
+                       if (x->FailOver.length())
+                       {
+                               TreeServer* CheckFailOver = Utils->FindServer(x->FailOver.c_str());
+                               if (CheckFailOver)
+                               {
+                                       /* The failover for this server is currently a member of the network.
+                                        * The failover probably succeeded, where the main link did not.
+                                        * Don't try the main link until the failover is gone again.
+                                        */
+                                       continue;
+                               }
+                       }
+                       if (!CheckDupe)
+                       {
+                               // an autoconnected server is not connected. Check if its time to connect it
+                               ServerInstance->SNO->WriteToSnoMask('l',"AUTOCONNECT: Auto-connecting server \002%s\002 (%lu seconds until next attempt)",x->Name.c_str(),x->AutoConnect);
+                               this->ConnectServer(&(*x));
+                       }
+               }
+       }
+}
+
+int ModuleSpanningTree::HandleVersion(const char** parameters, int pcnt, userrec* user)
+{
+       // we've already checked if pcnt > 0, so this is safe
+       TreeServer* found = Utils->FindServerMask(parameters[0]);
+       if (found)
+       {
+               std::string Version = found->GetVersion();
+               user->WriteServ("351 %s :%s",user->nick,Version.c_str());
+               if (found == Utils->TreeRoot)
+               {
+                       ServerInstance->Config->Send005(user);
+               }
+       }
+       else
+       {
+               user->WriteServ("402 %s %s :No such server",user->nick,parameters[0]);
+       }
+       return 1;
+}
+       
+int ModuleSpanningTree::HandleConnect(const char** parameters, int pcnt, userrec* user)
+{
+       for (std::vector<Link>::iterator x = Utils->LinkBlocks.begin(); x < Utils->LinkBlocks.end(); x++)
+       {
+               if (ServerInstance->MatchText(x->Name.c_str(),parameters[0]))
+               {
+                       TreeServer* CheckDupe = Utils->FindServer(x->Name.c_str());
+                       if (!CheckDupe)
+                       {
+                               user->WriteServ("NOTICE %s :*** CONNECT: Connecting to server: \002%s\002 (%s:%d)",user->nick,x->Name.c_str(),(x->HiddenFromStats ? "<hidden>" : x->IPAddr.c_str()),x->Port);
+                               ConnectServer(&(*x));
+                               return 1;
+                       }
+                       else
+                       {
+                               user->WriteServ("NOTICE %s :*** CONNECT: Server \002%s\002 already exists on the network and is connected via \002%s\002",user->nick,x->Name.c_str(),CheckDupe->GetParent()->GetName().c_str());
+                               return 1;
+                       }
+               }
+       }
+       user->WriteServ("NOTICE %s :*** CONNECT: No server matching \002%s\002 could be found in the config file.",user->nick,parameters[0]);
+       return 1;
+}
+
+void ModuleSpanningTree::BroadcastTimeSync()
+{
+       if (Utils->MasterTime)
+       {
+               std::deque<std::string> params;
+               params.push_back(ConvToStr(ServerInstance->Time(false)));
+               params.push_back("FORCE");
+               Utils->DoOneToMany(Utils->TreeRoot->GetName(), "TIMESET", params);
+       }
+}
+
+int ModuleSpanningTree::OnStats(char statschar, userrec* user, string_list &results)
+{
+       if ((statschar == 'c') || (statschar == 'n'))
+       {
+               for (unsigned int i = 0; i < Utils->LinkBlocks.size(); i++)
+               {
+                       results.push_back(std::string(ServerInstance->Config->ServerName)+" 213 "+user->nick+" "+statschar+" *@"+(Utils->LinkBlocks[i].HiddenFromStats ? "<hidden>" : Utils->LinkBlocks[i].IPAddr)+" * "+Utils->LinkBlocks[i].Name.c_str()+" "+ConvToStr(Utils->LinkBlocks[i].Port)+" "+(Utils->LinkBlocks[i].Hook.empty() ? "plaintext" : Utils->LinkBlocks[i].Hook)+" "+(Utils->LinkBlocks[i].AutoConnect ? 'a' : '-')+'s');
+                       if (statschar == 'c')
+                               results.push_back(std::string(ServerInstance->Config->ServerName)+" 244 "+user->nick+" H * * "+Utils->LinkBlocks[i].Name.c_str());
+               }
+               results.push_back(std::string(ServerInstance->Config->ServerName)+" 219 "+user->nick+" "+statschar+" :End of /STATS report");
+               ServerInstance->SNO->WriteToSnoMask('t',"%s '%c' requested by %s (%s@%s)",(!strcmp(user->server,ServerInstance->Config->ServerName) ? "Stats" : "Remote stats"),statschar,user->nick,user->ident,user->host);
+               return 1;
+       }
+
+       if (statschar == 'p')
+       {
+               /* show all server ports, after showing client ports. -- w00t */
+
+               for (unsigned int i = 0; i < Utils->Bindings.size(); i++)
+               {
+                       std::string ip = Utils->Bindings[i]->IP;
+                       if (ip.empty())
+                               ip = "*";
+
+                       std::string transport("plaintext");
+                       if (Utils->Bindings[i]->GetHook())
+                               transport = InspSocketNameRequest(this, Utils->Bindings[i]->GetHook()).Send();
+
+                       results.push_back(ConvToStr(ServerInstance->Config->ServerName) + " 249 "+user->nick+" :" + ip + ":" + ConvToStr(Utils->Bindings[i]->port)+
+                               " (server, " + transport + ")");
+               }
+       }
+       return 0;
+}
+
+int ModuleSpanningTree::OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line)
+{
+       /* If the command doesnt appear to be valid, we dont want to mess with it. */
+       if (!validated)
+               return 0;
+
+       if (command == "CONNECT")
+       {
+               return this->HandleConnect(parameters,pcnt,user);
+       }
+       else if (command == "STATS")
+       {
+               return this->HandleStats(parameters,pcnt,user);
+       }
+       else if (command == "MOTD")
+       {
+               return this->HandleMotd(parameters,pcnt,user);
+       }
+       else if (command == "ADMIN")
+       {
+               return this->HandleAdmin(parameters,pcnt,user);
+       }
+       else if (command == "SQUIT")
+       {
+               return this->HandleSquit(parameters,pcnt,user);
+       }
+       else if (command == "MAP")
+       {
+               this->HandleMap(parameters,pcnt,user);
+               return 1;
+       }
+       else if ((command == "TIME") && (pcnt > 0))
+       {
+               return this->HandleTime(parameters,pcnt,user);
+       }
+       else if (command == "LUSERS")
+       {
+               this->HandleLusers(parameters,pcnt,user);
+               return 1;
+       }
+       else if (command == "LINKS")
+       {
+               this->HandleLinks(parameters,pcnt,user);
+               return 1;
+       }
+       else if (command == "WHOIS")
+       {
+               if (pcnt > 1)
+               {
+                       // remote whois
+                       return this->HandleRemoteWhois(parameters,pcnt,user);
+               }
+       }
+       else if ((command == "VERSION") && (pcnt > 0))
+       {
+               this->HandleVersion(parameters,pcnt,user);
+               return 1;
+       }
+       else if ((command == "MODULES") && (pcnt > 0))
+       {
+               return this->HandleModules(parameters,pcnt,user);
+       }
+       return 0;
+}
+
+void ModuleSpanningTree::OnPostCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, CmdResult result, const std::string &original_line)
+{
+       if ((result == CMD_SUCCESS) && (ServerInstance->IsValidModuleCommand(command, pcnt, user)))
+       {
+               // this bit of code cleverly routes all module commands
+               // to all remote severs *automatically* so that modules
+               // can just handle commands locally, without having
+               // to have any special provision in place for remote
+               // commands and linking protocols.
+               std::deque<std::string> params;
+               params.clear();
+               for (int j = 0; j < pcnt; j++)
+               {
+                       if (strchr(parameters[j],' '))
+                       {
+                               params.push_back(":" + std::string(parameters[j]));
+                       }
+                       else
+                       {
+                               params.push_back(std::string(parameters[j]));
+                       }
+               }
+               Utils->DoOneToMany(user->nick,command,params);
+       }
+}
+
+void ModuleSpanningTree::OnGetServerDescription(const std::string &servername,std::string &description)
+{
+       TreeServer* s = Utils->FindServer(servername);
+       if (s)
+       {
+               description = s->GetDesc();
+       }
+}
+
+void ModuleSpanningTree::OnUserInvite(userrec* source,userrec* dest,chanrec* channel)
+{
+       if (IS_LOCAL(source))
+       {
+               std::deque<std::string> params;
+               params.push_back(dest->nick);
+               params.push_back(channel->name);
+               Utils->DoOneToMany(source->nick,"INVITE",params);
+       }
+}
+
+void ModuleSpanningTree::OnPostLocalTopicChange(userrec* user, chanrec* chan, const std::string &topic)
+{
+       std::deque<std::string> params;
+       params.push_back(chan->name);
+       params.push_back(":"+topic);
+       Utils->DoOneToMany(user->nick,"TOPIC",params);
+}
+
+void ModuleSpanningTree::OnWallops(userrec* user, const std::string &text)
+{
+       if (IS_LOCAL(user))
+       {
+               std::deque<std::string> params;
+               params.push_back(":"+text);
+               Utils->DoOneToMany(user->nick,"WALLOPS",params);
+       }
+}
+
+void ModuleSpanningTree::OnUserNotice(userrec* user, void* dest, int target_type, const std::string &text, char status, const CUList &exempt_list)
+{
+       if (target_type == TYPE_USER)
+       {
+               userrec* d = (userrec*)dest;
+               if ((d->GetFd() < 0) && (IS_LOCAL(user)))
+               {
+                       std::deque<std::string> params;
+                       params.clear();
+                       params.push_back(d->nick);
+                       params.push_back(":"+text);
+                       Utils->DoOneToOne(user->nick,"NOTICE",params,d->server);
+               }
+       }
+       else if (target_type == TYPE_CHANNEL)
+       {
+               if (IS_LOCAL(user))
+               {
+                       chanrec *c = (chanrec*)dest;
+                       if (c)
+                       {
+                               std::string cname = c->name;
+                               if (status)
+                                       cname = status + cname;
+                               TreeServerList list;
+                               Utils->GetListOfServersForChannel(c,list,status,exempt_list);
+                               for (TreeServerList::iterator i = list.begin(); i != list.end(); i++)
+                               {
+                                       TreeSocket* Sock = i->second->GetSocket();
+                                       if (Sock)
+                                               Sock->WriteLine(":"+std::string(user->nick)+" NOTICE "+cname+" :"+text);
+                               }
+                       }
+               }
+       }
+       else if (target_type == TYPE_SERVER)
+       {
+               if (IS_LOCAL(user))
+               {
+                       char* target = (char*)dest;
+                       std::deque<std::string> par;
+                       par.push_back(target);
+                       par.push_back(":"+text);
+                       Utils->DoOneToMany(user->nick,"NOTICE",par);
+               }
+       }
+}
+
+void ModuleSpanningTree::OnUserMessage(userrec* user, void* dest, int target_type, const std::string &text, char status, const CUList &exempt_list)
+{
+       if (target_type == TYPE_USER)
+       {
+               // route private messages which are targetted at clients only to the server
+               // which needs to receive them
+               userrec* d = (userrec*)dest;
+               if ((d->GetFd() < 0) && (IS_LOCAL(user)))
+               {
+                       std::deque<std::string> params;
+                       params.clear();
+                       params.push_back(d->nick);
+                       params.push_back(":"+text);
+                       Utils->DoOneToOne(user->nick,"PRIVMSG",params,d->server);
+               }
+       }
+       else if (target_type == TYPE_CHANNEL)
+       {
+               if (IS_LOCAL(user))
+               {
+                       chanrec *c = (chanrec*)dest;
+                       if (c)
+                       {
+                               std::string cname = c->name;
+                               if (status)
+                                       cname = status + cname;
+                               TreeServerList list;
+                               Utils->GetListOfServersForChannel(c,list,status,exempt_list);
+                               for (TreeServerList::iterator i = list.begin(); i != list.end(); i++)
+                               {
+                                       TreeSocket* Sock = i->second->GetSocket();
+                                       if (Sock)
+                                               Sock->WriteLine(":"+std::string(user->nick)+" PRIVMSG "+cname+" :"+text);
+                               }
+                       }
+               }
+       }
+       else if (target_type == TYPE_SERVER)
+       {
+               if (IS_LOCAL(user))
+               {
+                       char* target = (char*)dest;
+                       std::deque<std::string> par;
+                       par.push_back(target);
+                       par.push_back(":"+text);
+                       Utils->DoOneToMany(user->nick,"PRIVMSG",par);
+               }
+       }
+}
+
+void ModuleSpanningTree::OnBackgroundTimer(time_t curtime)
+{
+       AutoConnectServers(curtime);
+       DoPingChecks(curtime);
+}
+
+void ModuleSpanningTree::OnUserJoin(userrec* user, chanrec* channel, bool &silent)
+{
+       // Only do this for local users
+       if (IS_LOCAL(user))
+       {
+               if (channel->GetUserCounter() == 1)
+               {
+                       std::deque<std::string> params;
+                       // set up their permissions and the channel TS with FJOIN.
+                       // All users are FJOINed now, because a module may specify
+                       // new joining permissions for the user.
+                       params.push_back(channel->name);
+                       params.push_back(ConvToStr(channel->age));
+                       params.push_back(std::string(channel->GetAllPrefixChars(user))+","+std::string(user->nick));
+                       Utils->DoOneToMany(ServerInstance->Config->ServerName,"FJOIN",params);
+                       /* First user in, sync the modes for the channel */
+                       params.pop_back();
+                       params.push_back(channel->ChanModes(true));
+                       Utils->DoOneToMany(ServerInstance->Config->ServerName,"FMODE",params);
+               }
+               else
+               {
+                       std::deque<std::string> params;
+                       params.push_back(channel->name);
+                       params.push_back(ConvToStr(channel->age));
+                       Utils->DoOneToMany(user->nick,"JOIN",params);
+               }
+       }
+}
+
+void ModuleSpanningTree::OnChangeHost(userrec* user, const std::string &newhost)
+{
+       // only occurs for local clients
+       if (user->registered != REG_ALL)
+               return;
+       std::deque<std::string> params;
+       params.push_back(newhost);
+       Utils->DoOneToMany(user->nick,"FHOST",params);
+}
+
+void ModuleSpanningTree::OnChangeName(userrec* user, const std::string &gecos)
+{
+       // only occurs for local clients
+       if (user->registered != REG_ALL)
+               return;
+       std::deque<std::string> params;
+       params.push_back(gecos);
+       Utils->DoOneToMany(user->nick,"FNAME",params);
+}
+
+void ModuleSpanningTree::OnUserPart(userrec* user, chanrec* channel, const std::string &partmessage, bool &silent)
+{
+       if (IS_LOCAL(user))
+       {
+               std::deque<std::string> params;
+               params.push_back(channel->name);
+               if (!partmessage.empty())
+                       params.push_back(":"+partmessage);
+               Utils->DoOneToMany(user->nick,"PART",params);
+       }
+}
+
+void ModuleSpanningTree::OnUserConnect(userrec* user)
+{
+       char agestr[MAXBUF];
+       if (IS_LOCAL(user))
+       {
+               std::deque<std::string> params;
+               snprintf(agestr,MAXBUF,"%lu",(unsigned long)user->age);
+               params.push_back(agestr);
+               params.push_back(user->nick);
+               params.push_back(user->host);
+               params.push_back(user->dhost);
+               params.push_back(user->ident);
+               params.push_back("+"+std::string(user->FormatModes()));
+               params.push_back(user->GetIPString());
+               params.push_back(":"+std::string(user->fullname));
+               Utils->DoOneToMany(ServerInstance->Config->ServerName,"NICK",params);
+               // User is Local, change needs to be reflected!
+               TreeServer* SourceServer = Utils->FindServer(user->server);
+               if (SourceServer)
+               {
+                       SourceServer->AddUserCount();
+               }
+       }
+}
+
+void ModuleSpanningTree::OnUserQuit(userrec* user, const std::string &reason, const std::string &oper_message)
+{
+       if ((IS_LOCAL(user)) && (user->registered == REG_ALL))
+       {
+               std::deque<std::string> params;
+
+               if (oper_message != reason)
+               {
+                       params.push_back(":"+oper_message);
+                       Utils->DoOneToMany(user->nick,"OPERQUIT",params);
+               }
+               params.clear();
+               params.push_back(":"+reason);
+               Utils->DoOneToMany(user->nick,"QUIT",params);
+       }
+       // Regardless, We need to modify the user Counts..
+       TreeServer* SourceServer = Utils->FindServer(user->server);
+       if (SourceServer)
+       {
+               SourceServer->DelUserCount();
+       }
+}
+
+void ModuleSpanningTree::OnUserPostNick(userrec* user, const std::string &oldnick)
+{
+       if (IS_LOCAL(user))
+       {
+               std::deque<std::string> params;
+               params.push_back(user->nick);
+               Utils->DoOneToMany(oldnick,"NICK",params);
+       }
+}
+
+void ModuleSpanningTree::OnUserKick(userrec* source, userrec* user, chanrec* chan, const std::string &reason, bool &silent)
+{
+       if ((source) && (IS_LOCAL(source)))
+       {
+               std::deque<std::string> params;
+               params.push_back(chan->name);
+               params.push_back(user->nick);
+               params.push_back(":"+reason);
+               Utils->DoOneToMany(source->nick,"KICK",params);
+       }
+       else if (!source)
+       {
+               std::deque<std::string> params;
+               params.push_back(chan->name);
+               params.push_back(user->nick);
+               params.push_back(":"+reason);
+               Utils->DoOneToMany(ServerInstance->Config->ServerName,"KICK",params);
+       }
+}
+
+void ModuleSpanningTree::OnRemoteKill(userrec* source, userrec* dest, const std::string &reason, const std::string &operreason)
+{
+       std::deque<std::string> params;
+       params.push_back(":"+reason);
+       Utils->DoOneToMany(dest->nick,"OPERQUIT",params);
+       params.clear();
+       params.push_back(dest->nick);
+       params.push_back(":"+reason);
+       dest->SetOperQuit(operreason);
+       Utils->DoOneToMany(source->nick,"KILL",params);
+}
+
+void ModuleSpanningTree::OnRehash(userrec* user, const std::string &parameter)
+{
+       if (!parameter.empty())
+       {
+               std::deque<std::string> params;
+               params.push_back(parameter);
+               Utils->DoOneToMany(user ? user->nick : ServerInstance->Config->ServerName, "REHASH", params);
+               // check for self
+               if (ServerInstance->MatchText(ServerInstance->Config->ServerName,parameter))
+               {
+                       ServerInstance->WriteOpers("*** Remote rehash initiated locally by \002%s\002", user ? user->nick : ServerInstance->Config->ServerName);
+                       ServerInstance->RehashServer();
+               }
+       }
+       Utils->ReadConfiguration(false);
+       InitializeDisabledCommands(ServerInstance->Config->DisabledCommands, ServerInstance);
+}
+
+// note: the protocol does not allow direct umode +o except
+// via NICK with 8 params. sending OPERTYPE infers +o modechange
+// locally.
+void ModuleSpanningTree::OnOper(userrec* user, const std::string &opertype)
+{
+       if (IS_LOCAL(user))
+       {
+               std::deque<std::string> params;
+               params.push_back(opertype);
+               Utils->DoOneToMany(user->nick,"OPERTYPE",params);
+       }
+}
+
+void ModuleSpanningTree::OnLine(userrec* source, const std::string &host, bool adding, char linetype, long duration, const std::string &reason)
+{
+       if (!source)
+       {
+               /* Server-set lines */
+               char data[MAXBUF];
+               snprintf(data,MAXBUF,"%c %s %s %lu %lu :%s", linetype, host.c_str(), ServerInstance->Config->ServerName, (unsigned long)ServerInstance->Time(false),
+                               (unsigned long)duration, reason.c_str());
+               std::deque<std::string> params;
+               params.push_back(data);
+               Utils->DoOneToMany(ServerInstance->Config->ServerName, "ADDLINE", params);
+       }
+       else
+       {
+               if (IS_LOCAL(source))
+               {
+                       char type[8];
+                       snprintf(type,8,"%cLINE",linetype);
+                       std::string stype = type;
+                       if (adding)
+                       {
+                               char sduration[MAXBUF];
+                               snprintf(sduration,MAXBUF,"%ld",duration);
+                               std::deque<std::string> params;
+                               params.push_back(host);
+                               params.push_back(sduration);
+                               params.push_back(":"+reason);
+                               Utils->DoOneToMany(source->nick,stype,params);
+                       }
+                       else
+                       {
+                               std::deque<std::string> params;
+                               params.push_back(host);
+                               Utils->DoOneToMany(source->nick,stype,params);
+                       }
+               }
+       }
+}
+
+void ModuleSpanningTree::OnAddGLine(long duration, userrec* source, const std::string &reason, const std::string &hostmask)
+{
+       OnLine(source,hostmask,true,'G',duration,reason);
+}
+       
+void ModuleSpanningTree::OnAddZLine(long duration, userrec* source, const std::string &reason, const std::string &ipmask)
+{
+       OnLine(source,ipmask,true,'Z',duration,reason);
+}
+
+void ModuleSpanningTree::OnAddQLine(long duration, userrec* source, const std::string &reason, const std::string &nickmask)
+{
+       OnLine(source,nickmask,true,'Q',duration,reason);
+}
+
+void ModuleSpanningTree::OnAddELine(long duration, userrec* source, const std::string &reason, const std::string &hostmask)
+{
+       OnLine(source,hostmask,true,'E',duration,reason);
+}
+
+void ModuleSpanningTree::OnDelGLine(userrec* source, const std::string &hostmask)
+{
+       OnLine(source,hostmask,false,'G',0,"");
+}
+
+void ModuleSpanningTree::OnDelZLine(userrec* source, const std::string &ipmask)
+{
+       OnLine(source,ipmask,false,'Z',0,"");
+}
+
+void ModuleSpanningTree::OnDelQLine(userrec* source, const std::string &nickmask)
+{
+       OnLine(source,nickmask,false,'Q',0,"");
+}
+
+void ModuleSpanningTree::OnDelELine(userrec* source, const std::string &hostmask)
+{
+       OnLine(source,hostmask,false,'E',0,"");
+}
+
+void ModuleSpanningTree::OnMode(userrec* user, void* dest, int target_type, const std::string &text)
+{
+       if ((IS_LOCAL(user)) && (user->registered == REG_ALL))
+       {
+               std::deque<std::string> params;
+               std::string command;
+
+               if (target_type == TYPE_USER)
+               {
+                       userrec* u = (userrec*)dest;
+                       params.push_back(u->nick);
+                       params.push_back(text);
+                       command = "MODE";
+               }
+               else
+               {
+                       chanrec* c = (chanrec*)dest;
+                       params.push_back(c->name);
+                       params.push_back(ConvToStr(c->age));
+                       params.push_back(text);
+                       command = "FMODE";
+               }
+               Utils->DoOneToMany(user->nick, command, params);
+       }
+}
+
+void ModuleSpanningTree::OnSetAway(userrec* user)
+{
+       if (IS_LOCAL(user))
+       {
+               std::deque<std::string> params;
+               params.push_back(":"+std::string(user->awaymsg));
+               Utils->DoOneToMany(user->nick,"AWAY",params);
+       }
+}
+
+void ModuleSpanningTree::OnCancelAway(userrec* user)
+{
+       if (IS_LOCAL(user))
+       {
+               std::deque<std::string> params;
+               params.clear();
+               Utils->DoOneToMany(user->nick,"AWAY",params);
+       }
+}
+
+void ModuleSpanningTree::ProtoSendMode(void* opaque, int target_type, void* target, const std::string &modeline)
+{
+       TreeSocket* s = (TreeSocket*)opaque;
+       if (target)
+       {
+               if (target_type == TYPE_USER)
+               {
+                       userrec* u = (userrec*)target;
+                       s->WriteLine(std::string(":")+ServerInstance->Config->ServerName+" FMODE "+u->nick+" "+ConvToStr(u->age)+" "+modeline);
+               }
+               else
+               {
+                       chanrec* c = (chanrec*)target;
+                       s->WriteLine(std::string(":")+ServerInstance->Config->ServerName+" FMODE "+c->name+" "+ConvToStr(c->age)+" "+modeline);
+               }
+       }
+}
+
+void ModuleSpanningTree::ProtoSendMetaData(void* opaque, int target_type, void* target, const std::string &extname, const std::string &extdata)
+{
+       TreeSocket* s = (TreeSocket*)opaque;
+       if (target)
+       {
+               if (target_type == TYPE_USER)
+               {
+                       userrec* u = (userrec*)target;
+                       s->WriteLine(std::string(":")+ServerInstance->Config->ServerName+" METADATA "+u->nick+" "+extname+" :"+extdata);
+               }
+               else if (target_type == TYPE_CHANNEL)
+               {
+                       chanrec* c = (chanrec*)target;
+                       s->WriteLine(std::string(":")+ServerInstance->Config->ServerName+" METADATA "+c->name+" "+extname+" :"+extdata);
+               }
+       }
+       if (target_type == TYPE_OTHER)
+       {
+               s->WriteLine(std::string(":")+ServerInstance->Config->ServerName+" METADATA * "+extname+" :"+extdata);
+       }
+}
+
+void ModuleSpanningTree::OnEvent(Event* event)
+{
+       std::deque<std::string>* params = (std::deque<std::string>*)event->GetData();
+       if (event->GetEventID() == "send_metadata")
+       {
+               if (params->size() < 3)
+                       return;
+               (*params)[2] = ":" + (*params)[2];
+               Utils->DoOneToMany(ServerInstance->Config->ServerName,"METADATA",*params);
+       }
+       else if (event->GetEventID() == "send_topic")
+       {
+               if (params->size() < 2)
+                       return;
+               (*params)[1] = ":" + (*params)[1];
+               params->insert(params->begin() + 1,ServerInstance->Config->ServerName);
+               params->insert(params->begin() + 1,ConvToStr(ServerInstance->Time(true)));
+               Utils->DoOneToMany(ServerInstance->Config->ServerName,"FTOPIC",*params);
+       }
+       else if (event->GetEventID() == "send_mode")
+       {
+               if (params->size() < 2)
+                       return;
+               // Insert the TS value of the object, either userrec or chanrec
+               time_t ourTS = 0;
+               userrec* a = ServerInstance->FindNick((*params)[0]);
+               if (a)
+               {
+                       ourTS = a->age;
+                       Utils->DoOneToMany(ServerInstance->Config->ServerName,"MODE",*params);
+                       return;
+               }
+               else
+               {
+                       chanrec* a = ServerInstance->FindChan((*params)[0]);
+                       if (a)
+                       {
+                               ourTS = a->age;
+                               params->insert(params->begin() + 1,ConvToStr(ourTS));
+                               Utils->DoOneToMany(ServerInstance->Config->ServerName,"FMODE",*params);
+                       }
+               }
+       }
+       else if (event->GetEventID() == "send_mode_explicit")
+       {
+               if (params->size() < 2)
+                       return;
+               Utils->DoOneToMany(ServerInstance->Config->ServerName,"MODE",*params);
+       }
+       else if (event->GetEventID() == "send_opers")
+       {
+               if (params->size() < 1)
+                       return;
+               (*params)[0] = ":" + (*params)[0];
+               Utils->DoOneToMany(ServerInstance->Config->ServerName,"OPERNOTICE",*params);
+       }
+       else if (event->GetEventID() == "send_modeset")
+       {
+               if (params->size() < 2)
+                       return;
+               (*params)[1] = ":" + (*params)[1];
+               Utils->DoOneToMany(ServerInstance->Config->ServerName,"MODENOTICE",*params);
+       }
+       else if (event->GetEventID() == "send_snoset")
+       {
+               if (params->size() < 2)
+                       return;
+               (*params)[1] = ":" + (*params)[1];
+               Utils->DoOneToMany(ServerInstance->Config->ServerName,"SNONOTICE",*params);
+       }
+       else if (event->GetEventID() == "send_push")
+       {
+               if (params->size() < 2)
+                       return;
+                       
+               userrec *a = ServerInstance->FindNick((*params)[0]);
+                       
+               if (!a)
+                       return;
+                       
+               (*params)[1] = ":" + (*params)[1];
+               Utils->DoOneToOne(ServerInstance->Config->ServerName, "PUSH", *params, a->server);
+       }
+}
+
+ModuleSpanningTree::~ModuleSpanningTree()
+{
+       /* This will also free the listeners */
+       delete Utils;
+       if (SyncTimer)
+               ServerInstance->Timers->DelTimer(SyncTimer);
+
+       ServerInstance->Timers->DelTimer(RefreshTimer);
+
+       ServerInstance->DoneWithInterface("InspSocketHook");
+}
+
+Version ModuleSpanningTree::GetVersion()
+{
+       return Version(1,1,0,2,VF_VENDOR,API_VERSION);
+}
+
+void ModuleSpanningTree::Implements(char* List)
+{
+       List[I_OnPreCommand] = List[I_OnGetServerDescription] = List[I_OnUserInvite] = List[I_OnPostLocalTopicChange] = 1;
+       List[I_OnWallops] = List[I_OnUserNotice] = List[I_OnUserMessage] = List[I_OnBackgroundTimer] = 1;
+       List[I_OnUserJoin] = List[I_OnChangeHost] = List[I_OnChangeName] = List[I_OnUserPart] = List[I_OnUserConnect] = 1;
+       List[I_OnUserQuit] = List[I_OnUserPostNick] = List[I_OnUserKick] = List[I_OnRemoteKill] = List[I_OnRehash] = 1;
+       List[I_OnOper] = List[I_OnAddGLine] = List[I_OnAddZLine] = List[I_OnAddQLine] = List[I_OnAddELine] = 1;
+       List[I_OnDelGLine] = List[I_OnDelZLine] = List[I_OnDelQLine] = List[I_OnDelELine] = List[I_ProtoSendMode] = List[I_OnMode] = 1;
+       List[I_OnStats] = List[I_ProtoSendMetaData] = List[I_OnEvent] = List[I_OnSetAway] = List[I_OnCancelAway] = List[I_OnPostCommand] = 1;
+}
+
+/* It is IMPORTANT that m_spanningtree is the last module in the chain
+ * so that any activity it sees is FINAL, e.g. we arent going to send out
+ * a NICK message before m_cloaking has finished putting the +x on the user,
+ * etc etc.
+ * Therefore, we return PRIORITY_LAST to make sure we end up at the END of
+ * the module call queue.
+ */
+Priority ModuleSpanningTree::Prioritize()
+{
+       return PRIORITY_LAST;
+}
+
+MODULE_INIT(ModuleSpanningTree)
+
index 5bfb73e6ae60296b27aeb4f8a1e18d6ea5fc6662..c184ef07663a24f9bf92269eaddc6370d608821b 100644 (file)
@@ -1 +1,198 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __ST_MAIN__\r#define __ST_MAIN__\r\r#include "inspircd.h"\r#include "modules.h"\r\r/** If you make a change which breaks the protocol, increment this.\r * If you  completely change the protocol, completely change the number.\r *\r * IMPORTANT: If you make changes, document your changes here, without fail:\r * http://www.inspircd.org/wiki/List_of_protocol_changes_between_versions\r *\r * Failure to document your protocol changes will result in a painfully\r * painful death by pain. You have been warned.\r */\rconst long ProtocolVersion = 1105;\r\r/** Forward declarations\r */\rclass cmd_rconnect;\rclass cmd_rsquit;\rclass SpanningTreeUtilities;\rclass TimeSyncTimer;\rclass CacheRefreshTimer;\rclass TreeServer;\rclass Link;\r\r/** This is the main class for the spanningtree module\r */\rclass ModuleSpanningTree : public Module\r{\r int line;\r      int NumServers;\r        unsigned int max_local;\r        unsigned int max_global;\r       cmd_rconnect* command_rconnect;\r        cmd_rsquit* command_rsquit;\r    SpanningTreeUtilities* Utils;\r\r public:\r        /** Timer for clock syncs\r       */\r    TimeSyncTimer *SyncTimer;\r\r     CacheRefreshTimer *RefreshTimer;\r\r      /** Constructor\r         */\r    ModuleSpanningTree(InspIRCd* Me);\r\r     /** Shows /LINKS\r        */\r    void ShowLinks(TreeServer* Current, userrec* user, int hops);\r\r /** Counts local servers\r        */\r    int CountLocalServs();\r\r        /** Counts local and remote servers\r     */\r    int CountServs();\r\r     /** Handle LINKS command\r        */\r    void HandleLinks(const char** parameters, int pcnt, userrec* user);\r\r   /** Handle LUSERS command\r       */\r    void HandleLusers(const char** parameters, int pcnt, userrec* user);\r\r  /** Show MAP output to a user (recursive)\r       */\r    void ShowMap(TreeServer* Current, userrec* user, int depth, char matrix[128][128], float &totusers, float &totservers);\r\r       /** Handle remote MOTD\r  */\r    int HandleMotd(const char** parameters, int pcnt, userrec* user);\r\r     /** Handle remote ADMIN\r         */\r    int HandleAdmin(const char** parameters, int pcnt, userrec* user);\r\r    /** Handle remote STATS\r         */\r    int HandleStats(const char** parameters, int pcnt, userrec* user);\r\r    /** Handle MAP command\r  */\r    void HandleMap(const char** parameters, int pcnt, userrec* user);\r\r     /** Handle SQUIT\r        */\r    int HandleSquit(const char** parameters, int pcnt, userrec* user);\r\r    /** Handle TIME\r         */\r    int HandleTime(const char** parameters, int pcnt, userrec* user);\r\r     /** Handle remote WHOIS\r         */\r    int HandleRemoteWhois(const char** parameters, int pcnt, userrec* user);\r\r      /** Handle remote MODULES\r       */\r    int HandleModules(const char** parameters, int pcnt, userrec* user);\r\r  /** Ping all local servers\r      */\r    void DoPingChecks(time_t curtime);\r\r    /** Connect a server locally\r    */\r    void ConnectServer(Link* x);\r\r  /** Check if any servers are due to be autoconnected\r    */\r    void AutoConnectServers(time_t curtime);\r\r      /** Handle remote VERSON\r        */\r    int HandleVersion(const char** parameters, int pcnt, userrec* user);\r\r  /** Handle CONNECT\r      */\r    int HandleConnect(const char** parameters, int pcnt, userrec* user);\r\r  /** Send out time sync to all servers\r   */\r    void BroadcastTimeSync();\r\r     /** Returns oper-specific MAP information\r       */\r    const std::string MapOperInfo(TreeServer* Current);\r\r   /** Display a time as a human readable string\r   */\r    std::string TimeToStr(time_t secs);\r\r   /**\r     ** *** MODULE EVENTS ***\r       **/\r\r  virtual int OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line);\r      virtual void OnPostCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, CmdResult result, const std::string &original_line);\r  virtual void OnGetServerDescription(const std::string &servername,std::string &description);\r   virtual void OnUserInvite(userrec* source,userrec* dest,chanrec* channel);\r     virtual void OnPostLocalTopicChange(userrec* user, chanrec* chan, const std::string &topic);\r   virtual void OnWallops(userrec* user, const std::string &text);\r        virtual void OnUserNotice(userrec* user, void* dest, int target_type, const std::string &text, char status, const CUList &exempt_list);\r        virtual void OnUserMessage(userrec* user, void* dest, int target_type, const std::string &text, char status, const CUList &exempt_list);\r       virtual void OnBackgroundTimer(time_t curtime);\r        virtual void OnUserJoin(userrec* user, chanrec* channel, bool &silent);\r        virtual void OnChangeHost(userrec* user, const std::string &newhost);\r  virtual void OnChangeName(userrec* user, const std::string &gecos);\r    virtual void OnUserPart(userrec* user, chanrec* channel, const std::string &partmessage, bool &silent);\r        virtual void OnUserConnect(userrec* user);\r     virtual void OnUserQuit(userrec* user, const std::string &reason, const std::string &oper_message);\r    virtual void OnUserPostNick(userrec* user, const std::string &oldnick);\r        virtual void OnUserKick(userrec* source, userrec* user, chanrec* chan, const std::string &reason, bool &silent);\r       virtual void OnRemoteKill(userrec* source, userrec* dest, const std::string &reason, const std::string &operreason);\r   virtual void OnRehash(userrec* user, const std::string &parameter);\r    virtual void OnOper(userrec* user, const std::string &opertype);\r       void OnLine(userrec* source, const std::string &host, bool adding, char linetype, long duration, const std::string &reason);\r   virtual void OnAddGLine(long duration, userrec* source, const std::string &reason, const std::string &hostmask);\r       virtual void OnAddZLine(long duration, userrec* source, const std::string &reason, const std::string &ipmask);\r virtual void OnAddQLine(long duration, userrec* source, const std::string &reason, const std::string &nickmask);\r       virtual void OnAddELine(long duration, userrec* source, const std::string &reason, const std::string &hostmask);\r       virtual void OnDelGLine(userrec* source, const std::string &hostmask);\r virtual void OnDelZLine(userrec* source, const std::string &ipmask);\r   virtual void OnDelQLine(userrec* source, const std::string &nickmask);\r virtual void OnDelELine(userrec* source, const std::string &hostmask);\r virtual void OnMode(userrec* user, void* dest, int target_type, const std::string &text);\r      virtual int OnStats(char statschar, userrec* user, string_list &results);\r      virtual void OnSetAway(userrec* user);\r virtual void OnCancelAway(userrec* user);\r      virtual void ProtoSendMode(void* opaque, int target_type, void* target, const std::string &modeline);\r  virtual void ProtoSendMetaData(void* opaque, int target_type, void* target, const std::string &extname, const std::string &extdata);\r   virtual void OnEvent(Event* event);\r    virtual ~ModuleSpanningTree();\r virtual Version GetVersion();\r  void Implements(char* List);\r   Priority Prioritize();\r};\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __ST_MAIN__
+#define __ST_MAIN__
+
+#include "inspircd.h"
+#include "modules.h"
+
+/** If you make a change which breaks the protocol, increment this.
+ * If you  completely change the protocol, completely change the number.
+ *
+ * IMPORTANT: If you make changes, document your changes here, without fail:
+ * http://www.inspircd.org/wiki/List_of_protocol_changes_between_versions
+ *
+ * Failure to document your protocol changes will result in a painfully
+ * painful death by pain. You have been warned.
+ */
+const long ProtocolVersion = 1105;
+
+/** Forward declarations
+ */
+class cmd_rconnect;
+class cmd_rsquit;
+class SpanningTreeUtilities;
+class TimeSyncTimer;
+class CacheRefreshTimer;
+class TreeServer;
+class Link;
+
+/** This is the main class for the spanningtree module
+ */
+class ModuleSpanningTree : public Module
+{
+       int line;
+       int NumServers;
+       unsigned int max_local;
+       unsigned int max_global;
+       cmd_rconnect* command_rconnect;
+       cmd_rsquit* command_rsquit;
+       SpanningTreeUtilities* Utils;
+
+ public:
+       /** Timer for clock syncs
+        */
+       TimeSyncTimer *SyncTimer;
+
+       CacheRefreshTimer *RefreshTimer;
+
+       /** Constructor
+        */
+       ModuleSpanningTree(InspIRCd* Me);
+
+       /** Shows /LINKS
+        */
+       void ShowLinks(TreeServer* Current, userrec* user, int hops);
+
+       /** Counts local servers
+        */
+       int CountLocalServs();
+
+       /** Counts local and remote servers
+        */
+       int CountServs();
+
+       /** Handle LINKS command
+        */
+       void HandleLinks(const char** parameters, int pcnt, userrec* user);
+
+       /** Handle LUSERS command
+        */
+       void HandleLusers(const char** parameters, int pcnt, userrec* user);
+
+       /** Show MAP output to a user (recursive)
+        */
+       void ShowMap(TreeServer* Current, userrec* user, int depth, char matrix[128][128], float &totusers, float &totservers);
+
+       /** Handle remote MOTD
+        */
+       int HandleMotd(const char** parameters, int pcnt, userrec* user);
+
+       /** Handle remote ADMIN
+        */
+       int HandleAdmin(const char** parameters, int pcnt, userrec* user);
+
+       /** Handle remote STATS
+        */
+       int HandleStats(const char** parameters, int pcnt, userrec* user);
+
+       /** Handle MAP command
+        */
+       void HandleMap(const char** parameters, int pcnt, userrec* user);
+
+       /** Handle SQUIT
+        */
+       int HandleSquit(const char** parameters, int pcnt, userrec* user);
+
+       /** Handle TIME
+        */
+       int HandleTime(const char** parameters, int pcnt, userrec* user);
+
+       /** Handle remote WHOIS
+        */
+       int HandleRemoteWhois(const char** parameters, int pcnt, userrec* user);
+
+       /** Handle remote MODULES
+        */
+       int HandleModules(const char** parameters, int pcnt, userrec* user);
+
+       /** Ping all local servers
+        */
+       void DoPingChecks(time_t curtime);
+
+       /** Connect a server locally
+        */
+       void ConnectServer(Link* x);
+
+       /** Check if any servers are due to be autoconnected
+        */
+       void AutoConnectServers(time_t curtime);
+
+       /** Handle remote VERSON
+        */
+       int HandleVersion(const char** parameters, int pcnt, userrec* user);
+
+       /** Handle CONNECT
+        */
+       int HandleConnect(const char** parameters, int pcnt, userrec* user);
+
+       /** Send out time sync to all servers
+        */
+       void BroadcastTimeSync();
+
+       /** Returns oper-specific MAP information
+        */
+       const std::string MapOperInfo(TreeServer* Current);
+
+       /** Display a time as a human readable string
+        */
+       std::string TimeToStr(time_t secs);
+
+       /**
+        ** *** MODULE EVENTS ***
+        **/
+
+       virtual int OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line);
+       virtual void OnPostCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, CmdResult result, const std::string &original_line);
+       virtual void OnGetServerDescription(const std::string &servername,std::string &description);
+       virtual void OnUserInvite(userrec* source,userrec* dest,chanrec* channel);
+       virtual void OnPostLocalTopicChange(userrec* user, chanrec* chan, const std::string &topic);
+       virtual void OnWallops(userrec* user, const std::string &text);
+       virtual void OnUserNotice(userrec* user, void* dest, int target_type, const std::string &text, char status, const CUList &exempt_list);
+       virtual void OnUserMessage(userrec* user, void* dest, int target_type, const std::string &text, char status, const CUList &exempt_list);
+       virtual void OnBackgroundTimer(time_t curtime);
+       virtual void OnUserJoin(userrec* user, chanrec* channel, bool &silent);
+       virtual void OnChangeHost(userrec* user, const std::string &newhost);
+       virtual void OnChangeName(userrec* user, const std::string &gecos);
+       virtual void OnUserPart(userrec* user, chanrec* channel, const std::string &partmessage, bool &silent);
+       virtual void OnUserConnect(userrec* user);
+       virtual void OnUserQuit(userrec* user, const std::string &reason, const std::string &oper_message);
+       virtual void OnUserPostNick(userrec* user, const std::string &oldnick);
+       virtual void OnUserKick(userrec* source, userrec* user, chanrec* chan, const std::string &reason, bool &silent);
+       virtual void OnRemoteKill(userrec* source, userrec* dest, const std::string &reason, const std::string &operreason);
+       virtual void OnRehash(userrec* user, const std::string &parameter);
+       virtual void OnOper(userrec* user, const std::string &opertype);
+       void OnLine(userrec* source, const std::string &host, bool adding, char linetype, long duration, const std::string &reason);
+       virtual void OnAddGLine(long duration, userrec* source, const std::string &reason, const std::string &hostmask);
+       virtual void OnAddZLine(long duration, userrec* source, const std::string &reason, const std::string &ipmask);
+       virtual void OnAddQLine(long duration, userrec* source, const std::string &reason, const std::string &nickmask);
+       virtual void OnAddELine(long duration, userrec* source, const std::string &reason, const std::string &hostmask);
+       virtual void OnDelGLine(userrec* source, const std::string &hostmask);
+       virtual void OnDelZLine(userrec* source, const std::string &ipmask);
+       virtual void OnDelQLine(userrec* source, const std::string &nickmask);
+       virtual void OnDelELine(userrec* source, const std::string &hostmask);
+       virtual void OnMode(userrec* user, void* dest, int target_type, const std::string &text);
+       virtual int OnStats(char statschar, userrec* user, string_list &results);
+       virtual void OnSetAway(userrec* user);
+       virtual void OnCancelAway(userrec* user);
+       virtual void ProtoSendMode(void* opaque, int target_type, void* target, const std::string &modeline);
+       virtual void ProtoSendMetaData(void* opaque, int target_type, void* target, const std::string &extname, const std::string &extdata);
+       virtual void OnEvent(Event* event);
+       virtual ~ModuleSpanningTree();
+       virtual Version GetVersion();
+       void Implements(char* List);
+       Priority Prioritize();
+};
+
+#endif
index 88b1fde8b5a3b5bfc19564078ee1307f834ea9fc..5500ccdc0b78e76cb85091af3f0284df2baf5e06 100644 (file)
@@ -1 +1,67 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "configreader.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r#include "commands/cmd_whois.h"\r#include "commands/cmd_stats.h"\r#include "socket.h"\r#include "wildcard.h"\r#include "xline.h"\r#include "transport.h"\r\r#include "m_spanningtree/timesynctimer.h"\r#include "m_spanningtree/resolvers.h"\r#include "m_spanningtree/main.h"\r#include "m_spanningtree/utils.h"\r#include "m_spanningtree/treeserver.h"\r#include "m_spanningtree/link.h"\r#include "m_spanningtree/treesocket.h"\r#include "m_spanningtree/rconnect.h"\r\r/* $ModDep: m_spanningtree/timesynctimer.h m_spanningtree/resolvers.h m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/link.h m_spanningtree/treesocket.h m_spanningtree/rconnect.h */\r\rcmd_rconnect::cmd_rconnect (InspIRCd* Instance, Module* Callback, SpanningTreeUtilities* Util) : command_t(Instance, "RCONNECT", 'o', 2), Creator(Callback), Utils(Util)\r{\r      this->source = "m_spanningtree.so";\r    syntax = "<remote-server-mask> <target-server-mask>";\r}\r\rCmdResult cmd_rconnect::Handle (const char** parameters, int pcnt, userrec *user)\r{\r   if (IS_LOCAL(user))\r    {\r              if (!Utils->FindServerMask(parameters[0]))\r             {\r                      user->WriteServ("NOTICE %s :*** RCONNECT: Server \002%s\002 isn't connected to the network!", user->nick, parameters[0]);\r                      return CMD_FAILURE;\r            }\r              user->WriteServ("NOTICE %s :*** RCONNECT: Sending remote connect to \002%s\002 to connect server \002%s\002.",user->nick,parameters[0],parameters[1]);\r }\r\r     /* Is this aimed at our server? */\r     if (ServerInstance->MatchText(ServerInstance->Config->ServerName,parameters[0]))\r       {\r              /* Yes, initiate the given connect */\r          ServerInstance->SNO->WriteToSnoMask('l',"Remote CONNECT from %s matching \002%s\002, connecting server \002%s\002",user->nick,parameters[0],parameters[1]);\r            const char* para[1];\r           para[0] = parameters[1];\r               std::string original_command = std::string("CONNECT ") + parameters[1];\r                Creator->OnPreCommand("CONNECT", para, 1, user, true, original_command);\r       }\r      return CMD_SUCCESS;\r}\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "configreader.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+#include "commands/cmd_whois.h"
+#include "commands/cmd_stats.h"
+#include "socket.h"
+#include "wildcard.h"
+#include "xline.h"
+#include "transport.h"
+
+#include "m_spanningtree/timesynctimer.h"
+#include "m_spanningtree/resolvers.h"
+#include "m_spanningtree/main.h"
+#include "m_spanningtree/utils.h"
+#include "m_spanningtree/treeserver.h"
+#include "m_spanningtree/link.h"
+#include "m_spanningtree/treesocket.h"
+#include "m_spanningtree/rconnect.h"
+
+/* $ModDep: m_spanningtree/timesynctimer.h m_spanningtree/resolvers.h m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/link.h m_spanningtree/treesocket.h m_spanningtree/rconnect.h */
+
+cmd_rconnect::cmd_rconnect (InspIRCd* Instance, Module* Callback, SpanningTreeUtilities* Util) : command_t(Instance, "RCONNECT", 'o', 2), Creator(Callback), Utils(Util)
+{
+       this->source = "m_spanningtree.so";
+       syntax = "<remote-server-mask> <target-server-mask>";
+}
+
+CmdResult cmd_rconnect::Handle (const char** parameters, int pcnt, userrec *user)
+{
+       if (IS_LOCAL(user))
+       {
+               if (!Utils->FindServerMask(parameters[0]))
+               {
+                       user->WriteServ("NOTICE %s :*** RCONNECT: Server \002%s\002 isn't connected to the network!", user->nick, parameters[0]);
+                       return CMD_FAILURE;
+               }
+               user->WriteServ("NOTICE %s :*** RCONNECT: Sending remote connect to \002%s\002 to connect server \002%s\002.",user->nick,parameters[0],parameters[1]);
+       }
+
+       /* Is this aimed at our server? */
+       if (ServerInstance->MatchText(ServerInstance->Config->ServerName,parameters[0]))
+       {
+               /* Yes, initiate the given connect */
+               ServerInstance->SNO->WriteToSnoMask('l',"Remote CONNECT from %s matching \002%s\002, connecting server \002%s\002",user->nick,parameters[0],parameters[1]);
+               const char* para[1];
+               para[0] = parameters[1];
+               std::string original_command = std::string("CONNECT ") + parameters[1];
+               Creator->OnPreCommand("CONNECT", para, 1, user, true, original_command);
+       }
+       return CMD_SUCCESS;
+}
+
index fca96f4a808c2e06311f77d0dc921c68016247ee..77e271949f76e95b972962ea5796f36d25fd7b06 100644 (file)
@@ -1 +1,28 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __RCONNECT_H__\r#define __RCONNECT_H__\r\r/** Handle /RCONNECT\r */\rclass cmd_rconnect : public command_t\r{\r        Module* Creator;           /* Creator */\r        SpanningTreeUtilities* Utils;     /* Utility class */\r public:\r        cmd_rconnect (InspIRCd* Instance, Module* Callback, SpanningTreeUtilities* Util);\r        CmdResult Handle (const char** parameters, int pcnt, userrec *user);\r};\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __RCONNECT_H__
+#define __RCONNECT_H__
+
+/** Handle /RCONNECT
+ */
+class cmd_rconnect : public command_t
+{
+        Module* Creator;               /* Creator */
+        SpanningTreeUtilities* Utils;  /* Utility class */
+ public:
+        cmd_rconnect (InspIRCd* Instance, Module* Callback, SpanningTreeUtilities* Util);
+        CmdResult Handle (const char** parameters, int pcnt, userrec *user);
+};
+
+#endif
index 80971c69979e8a0cacba9b2812f2b9e636483351..0d94da99f81191b17632a92e898cb88a550ea3a8 100644 (file)
@@ -1 +1,88 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "configreader.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r#include "commands/cmd_whois.h"\r#include "commands/cmd_stats.h"\r#include "socket.h"\r#include "wildcard.h"\r#include "xline.h"\r#include "transport.h"\r\r#include "m_spanningtree/resolvers.h"\r#include "m_spanningtree/main.h"\r#include "m_spanningtree/utils.h"\r#include "m_spanningtree/treeserver.h"\r#include "m_spanningtree/link.h"\r#include "m_spanningtree/treesocket.h"\r\r/* $ModDep: m_spanningtree/timesynctimer.h m_spanningtree/resolvers.h m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/link.h m_spanningtree/treesocket.h */\r\r/** This class is used to resolve server hostnames during /connect and autoconnect.\r * As of 1.1, the resolver system is seperated out from InspSocket, so we must do this\r * resolver step first ourselves if we need it. This is totally nonblocking, and will\r * callback to OnLookupComplete or OnError when completed. Once it has completed we\r * will have an IP address which we can then use to continue our connection.\r */\rServernameResolver::ServernameResolver(Module* me, SpanningTreeUtilities* Util, InspIRCd* Instance, const std::string &hostname, Link x, bool &cached, QueryType qt) : Resolver(Instance, hostname, qt, cached, me), MyLink(x), Utils(Util), query(qt), host(hostname), mine(me)\r{\r /* Nothing in here, folks */\r}\r\rvoid ServernameResolver::OnLookupComplete(const std::string &result, unsigned int ttl, bool cached)\r{\r  /* Initiate the connection, now that we have an IP to use.\r      * Passing a hostname directly to InspSocket causes it to\r       * just bail and set its FD to -1.\r      */\r    TreeServer* CheckDupe = Utils->FindServer(MyLink.Name.c_str());\r        if (!CheckDupe) /* Check that nobody tried to connect it successfully while we were resolving */\r       {\r\r             if ((!MyLink.Hook.empty()) && (Utils->hooks.find(MyLink.Hook.c_str()) ==  Utils->hooks.end()))\r                 return;\r\r               TreeSocket* newsocket = new TreeSocket(this->Utils, ServerInstance, result,MyLink.Port,false,MyLink.Timeout ? MyLink.Timeout : 10,MyLink.Name.c_str(),\r                                                 MyLink.Bind, MyLink.Hook.empty() ? NULL : Utils->hooks[MyLink.Hook.c_str()]);\r          if (newsocket->GetFd() > -1)\r           {\r                      /* We're all OK */\r             }\r              else\r           {\r                      /* Something barfed, show the opers */\r                 ServerInstance->SNO->WriteToSnoMask('l',"CONNECT: Error connecting \002%s\002: %s.",MyLink.Name.c_str(),strerror(errno));\r                      delete newsocket;\r                      Utils->DoFailOver(&MyLink);\r            }\r      }\r}\r\rvoid ServernameResolver::OnError(ResolverError e, const std::string &errormessage)\r{\r      /* Ooops! */\r   if (query == DNS_QUERY_AAAA)\r   {\r              bool cached;\r           ServernameResolver* snr = new ServernameResolver(mine, Utils, ServerInstance, host, MyLink, cached, DNS_QUERY_A);\r              ServerInstance->AddResolver(snr, cached);\r              return;\r        }\r      ServerInstance->SNO->WriteToSnoMask('l',"CONNECT: Error connecting \002%s\002: Unable to resolve hostname - %s",MyLink.Name.c_str(),errormessage.c_str());\r     Utils->DoFailOver(&MyLink);\r}\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "configreader.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+#include "commands/cmd_whois.h"
+#include "commands/cmd_stats.h"
+#include "socket.h"
+#include "wildcard.h"
+#include "xline.h"
+#include "transport.h"
+
+#include "m_spanningtree/resolvers.h"
+#include "m_spanningtree/main.h"
+#include "m_spanningtree/utils.h"
+#include "m_spanningtree/treeserver.h"
+#include "m_spanningtree/link.h"
+#include "m_spanningtree/treesocket.h"
+
+/* $ModDep: m_spanningtree/timesynctimer.h m_spanningtree/resolvers.h m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/link.h m_spanningtree/treesocket.h */
+
+/** This class is used to resolve server hostnames during /connect and autoconnect.
+ * As of 1.1, the resolver system is seperated out from InspSocket, so we must do this
+ * resolver step first ourselves if we need it. This is totally nonblocking, and will
+ * callback to OnLookupComplete or OnError when completed. Once it has completed we
+ * will have an IP address which we can then use to continue our connection.
+ */
+ServernameResolver::ServernameResolver(Module* me, SpanningTreeUtilities* Util, InspIRCd* Instance, const std::string &hostname, Link x, bool &cached, QueryType qt) : Resolver(Instance, hostname, qt, cached, me), MyLink(x), Utils(Util), query(qt), host(hostname), mine(me)
+{
+       /* Nothing in here, folks */
+}
+
+void ServernameResolver::OnLookupComplete(const std::string &result, unsigned int ttl, bool cached)
+{
+       /* Initiate the connection, now that we have an IP to use.
+        * Passing a hostname directly to InspSocket causes it to
+        * just bail and set its FD to -1.
+        */
+       TreeServer* CheckDupe = Utils->FindServer(MyLink.Name.c_str());
+       if (!CheckDupe) /* Check that nobody tried to connect it successfully while we were resolving */
+       {
+
+               if ((!MyLink.Hook.empty()) && (Utils->hooks.find(MyLink.Hook.c_str()) ==  Utils->hooks.end()))
+                       return;
+
+               TreeSocket* newsocket = new TreeSocket(this->Utils, ServerInstance, result,MyLink.Port,false,MyLink.Timeout ? MyLink.Timeout : 10,MyLink.Name.c_str(),
+                                                       MyLink.Bind, MyLink.Hook.empty() ? NULL : Utils->hooks[MyLink.Hook.c_str()]);
+               if (newsocket->GetFd() > -1)
+               {
+                       /* We're all OK */
+               }
+               else
+               {
+                       /* Something barfed, show the opers */
+                       ServerInstance->SNO->WriteToSnoMask('l',"CONNECT: Error connecting \002%s\002: %s.",MyLink.Name.c_str(),strerror(errno));
+                       delete newsocket;
+                       Utils->DoFailOver(&MyLink);
+               }
+       }
+}
+
+void ServernameResolver::OnError(ResolverError e, const std::string &errormessage)
+{
+       /* Ooops! */
+       if (query == DNS_QUERY_AAAA)
+       {
+               bool cached;
+               ServernameResolver* snr = new ServernameResolver(mine, Utils, ServerInstance, host, MyLink, cached, DNS_QUERY_A);
+               ServerInstance->AddResolver(snr, cached);
+               return;
+       }
+       ServerInstance->SNO->WriteToSnoMask('l',"CONNECT: Error connecting \002%s\002: Unable to resolve hostname - %s",MyLink.Name.c_str(),errormessage.c_str());
+       Utils->DoFailOver(&MyLink);
+}
+
index 0ba9d6bd6b81277fcd3b570291604fc1687284d2..06fd05bad1ce15857d10b4329380ea9106ac8d59 100644 (file)
@@ -1 +1,90 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __RESOLVERS__H__\r#define __RESOLVERS__H__\r\r#include "configreader.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r#include "commands/cmd_whois.h"\r#include "commands/cmd_stats.h"\r#include "socket.h"\r#include "inspircd.h"\r#include "wildcard.h"\r#include "xline.h"\r#include "transport.h"\r\r#include "m_spanningtree/utils.h"\r#include "m_spanningtree/link.h"\r\r/** Handle resolving of server IPs for the cache\r */\rclass SecurityIPResolver : public Resolver\r{\r private:\r     Link MyLink;\r   SpanningTreeUtilities* Utils;\r  Module* mine;\r  std::string host;\r      QueryType query;\r public:\r      SecurityIPResolver(Module* me, SpanningTreeUtilities* U, InspIRCd* Instance, const std::string &hostname, Link x, bool &cached, QueryType qt)\r          : Resolver(Instance, hostname, qt, cached, me), MyLink(x), Utils(U), mine(me), host(hostname), query(qt)\r       {\r      }\r\r     void OnLookupComplete(const std::string &result, unsigned int ttl, bool cached)\r        {\r              Utils->ValidIPs.push_back(result);\r     }\r\r     void OnError(ResolverError e, const std::string &errormessage)\r {\r              if (query == DNS_QUERY_AAAA)\r           {\r                      bool cached;\r                   SecurityIPResolver* res = new SecurityIPResolver(mine, Utils, ServerInstance, host, MyLink, cached, DNS_QUERY_A);\r                      ServerInstance->AddResolver(res, cached);\r                      return;\r                }\r              ServerInstance->Log(DEFAULT,"Could not resolve IP associated with Link '%s': %s",MyLink.Name.c_str(),errormessage.c_str());\r    }\r};\r\r/** This class is used to resolve server hostnames during /connect and autoconnect.\r * As of 1.1, the resolver system is seperated out from InspSocket, so we must do this\r * resolver step first ourselves if we need it. This is totally nonblocking, and will\r * callback to OnLookupComplete or OnError when completed. Once it has completed we\r * will have an IP address which we can then use to continue our connection.\r */\rclass ServernameResolver : public Resolver\r{\r private:\r        /** A copy of the Link tag info for what we're connecting to.\r         * We take a copy, rather than using a pointer, just in case the\r         * admin takes the tag away and rehashes while the domain is resolving.\r         */\r        Link MyLink;\r        SpanningTreeUtilities* Utils;\r       QueryType query;\r       std::string host;\r      Module* mine;\r public:\r        ServernameResolver(Module* me, SpanningTreeUtilities* Util, InspIRCd* Instance, const std::string &hostname, Link x, bool &cached, QueryType qt);\r        void OnLookupComplete(const std::string &result, unsigned int ttl, bool cached);\r        void OnError(ResolverError e, const std::string &errormessage);\r};\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __RESOLVERS__H__
+#define __RESOLVERS__H__
+
+#include "configreader.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+#include "commands/cmd_whois.h"
+#include "commands/cmd_stats.h"
+#include "socket.h"
+#include "inspircd.h"
+#include "wildcard.h"
+#include "xline.h"
+#include "transport.h"
+
+#include "m_spanningtree/utils.h"
+#include "m_spanningtree/link.h"
+
+/** Handle resolving of server IPs for the cache
+ */
+class SecurityIPResolver : public Resolver
+{
+ private:
+       Link MyLink;
+       SpanningTreeUtilities* Utils;
+       Module* mine;
+       std::string host;
+       QueryType query;
+ public:
+       SecurityIPResolver(Module* me, SpanningTreeUtilities* U, InspIRCd* Instance, const std::string &hostname, Link x, bool &cached, QueryType qt)
+               : Resolver(Instance, hostname, qt, cached, me), MyLink(x), Utils(U), mine(me), host(hostname), query(qt)
+       {
+       }
+
+       void OnLookupComplete(const std::string &result, unsigned int ttl, bool cached)
+       {
+               Utils->ValidIPs.push_back(result);
+       }
+
+       void OnError(ResolverError e, const std::string &errormessage)
+       {
+               if (query == DNS_QUERY_AAAA)
+               {
+                       bool cached;
+                       SecurityIPResolver* res = new SecurityIPResolver(mine, Utils, ServerInstance, host, MyLink, cached, DNS_QUERY_A);
+                       ServerInstance->AddResolver(res, cached);
+                       return;
+               }
+               ServerInstance->Log(DEFAULT,"Could not resolve IP associated with Link '%s': %s",MyLink.Name.c_str(),errormessage.c_str());
+       }
+};
+
+/** This class is used to resolve server hostnames during /connect and autoconnect.
+ * As of 1.1, the resolver system is seperated out from InspSocket, so we must do this
+ * resolver step first ourselves if we need it. This is totally nonblocking, and will
+ * callback to OnLookupComplete or OnError when completed. Once it has completed we
+ * will have an IP address which we can then use to continue our connection.
+ */
+class ServernameResolver : public Resolver
+{
+ private:
+        /** A copy of the Link tag info for what we're connecting to.
+         * We take a copy, rather than using a pointer, just in case the
+         * admin takes the tag away and rehashes while the domain is resolving.
+         */
+        Link MyLink;
+        SpanningTreeUtilities* Utils;
+       QueryType query;
+       std::string host;
+       Module* mine;
+ public:
+        ServernameResolver(Module* me, SpanningTreeUtilities* Util, InspIRCd* Instance, const std::string &hostname, Link x, bool &cached, QueryType qt);
+        void OnLookupComplete(const std::string &result, unsigned int ttl, bool cached);
+        void OnError(ResolverError e, const std::string &errormessage);
+};
+
+#endif
index 7bb6abfc1aa306586d873d48824aaef4a8b12954..5f3d33fc0680915b2d677ea3d5c9454658d7841c 100644 (file)
@@ -1 +1,123 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "configreader.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r#include "commands/cmd_whois.h"\r#include "commands/cmd_stats.h"\r#include "socket.h"\r#include "wildcard.h"\r#include "xline.h"\r#include "transport.h"\r\r#include "m_spanningtree/timesynctimer.h"\r#include "m_spanningtree/resolvers.h"\r#include "m_spanningtree/main.h"\r#include "m_spanningtree/utils.h"\r#include "m_spanningtree/treeserver.h"\r#include "m_spanningtree/link.h"\r#include "m_spanningtree/treesocket.h"\r#include "m_spanningtree/rsquit.h"\r\r/* $ModDep: m_spanningtree/timesynctimer.h m_spanningtree/resolvers.h m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/link.h m_spanningtree/treesocket.h m_spanningtree/rsquit.h */\r\rcmd_rsquit::cmd_rsquit (InspIRCd* Instance, Module* Callback, SpanningTreeUtilities* Util) : command_t(Instance, "RSQUIT", 'o', 1), Creator(Callback), Utils(Util)\r{\r        this->source = "m_spanningtree.so";\r    syntax = "<remote-server-mask> [target-server-mask]";\r}\r\rCmdResult cmd_rsquit::Handle (const char** parameters, int pcnt, userrec *user)\r{\r     if (IS_LOCAL(user))\r    {\r              if (!Utils->FindServerMask(parameters[0]))\r             {\r                      user->WriteServ("NOTICE %s :*** RSQUIT: Server \002%s\002 isn't connected to the network!", user->nick, parameters[0]);\r                        return CMD_FAILURE;\r            }\r              if (pcnt > 1)\r                  user->WriteServ("NOTICE %s :*** RSQUIT: Sending remote squit to \002%s\002 to squit server \002%s\002.",user->nick,parameters[0],parameters[1]);\r               else\r                   user->WriteServ("NOTICE %s :*** RSQUIT: Sending remote squit for server \002%s\002.",user->nick,parameters[0]);\r        }\r\r     TreeServer* s = (pcnt > 1) ? Utils->FindServerMask(parameters[1]) : Utils->FindServerMask(parameters[0]);\r\r     if (pcnt > 1)\r  {\r              if (ServerInstance->MatchText(ServerInstance->Config->ServerName,parameters[0]))\r               {\r                      if (s)\r                 {\r                              if (s == Utils->TreeRoot)\r                              {\r                                      NoticeUser(user, "*** RSQUIT: Foolish mortal, you cannot make a server SQUIT itself! ("+ConvToStr(parameters[1])+" matches local server name)");\r                                       return CMD_FAILURE;\r                            }\r                              TreeSocket* sock = s->GetSocket();\r                             if (!sock)\r                             {\r                                      NoticeUser(user, "*** RSQUIT: Server \002"+ConvToStr(parameters[1])+"\002 isn't connected to \002"+ConvToStr(parameters[0])+"\002.");\r                                  return CMD_FAILURE;\r                            }\r                              ServerInstance->SNO->WriteToSnoMask('l',"Remote SQUIT from %s matching \002%s\002, squitting server \002%s\002",user->nick,parameters[0],parameters[1]);\r                               const char* para[1];\r                           para[0] = parameters[1];\r                               std::string original_command = std::string("SQUIT ") + parameters[1];\r                          Creator->OnPreCommand("SQUIT", para, 1, user, true, original_command);\r                         return CMD_LOCALONLY;\r                  }\r              }\r      }\r      else\r   {\r              if (s)\r         {\r                      if (s == Utils->TreeRoot)\r                      {\r                              NoticeUser(user, "*** RSQUIT: Foolish mortal, you cannot make a server SQUIT itself! ("+ConvToStr(parameters[0])+" matches local server name)");\r                               return CMD_FAILURE;\r                    }\r                      TreeSocket* sock = s->GetSocket();\r                     if (sock)\r                      {\r                              ServerInstance->SNO->WriteToSnoMask('l',"RSQUIT: Server \002%s\002 removed from network by %s",parameters[0],user->nick);\r                              sock->Squit(s,std::string("Server quit by ") + user->GetFullRealHost());\r                               ServerInstance->SE->DelFd(sock);\r                               sock->Close();\r                         return CMD_LOCALONLY;\r                  }\r              }\r      }\r\r     return CMD_SUCCESS;\r}\r\rvoid cmd_rsquit::NoticeUser(userrec* user, const std::string &msg)\r{\r    if (IS_LOCAL(user))\r    {\r              user->WriteServ("NOTICE %s :%s",user->nick,msg.c_str());\r       }\r      else\r   {\r              std::deque<std::string> params;\r                params.push_back(user->nick);\r          params.push_back("NOTICE "+ConvToStr(user->nick)+" :"+msg);\r            Utils->DoOneToOne(ServerInstance->Config->ServerName, "PUSH", params, user->server);\r   }\r}\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "configreader.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+#include "commands/cmd_whois.h"
+#include "commands/cmd_stats.h"
+#include "socket.h"
+#include "wildcard.h"
+#include "xline.h"
+#include "transport.h"
+
+#include "m_spanningtree/timesynctimer.h"
+#include "m_spanningtree/resolvers.h"
+#include "m_spanningtree/main.h"
+#include "m_spanningtree/utils.h"
+#include "m_spanningtree/treeserver.h"
+#include "m_spanningtree/link.h"
+#include "m_spanningtree/treesocket.h"
+#include "m_spanningtree/rsquit.h"
+
+/* $ModDep: m_spanningtree/timesynctimer.h m_spanningtree/resolvers.h m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/link.h m_spanningtree/treesocket.h m_spanningtree/rsquit.h */
+
+cmd_rsquit::cmd_rsquit (InspIRCd* Instance, Module* Callback, SpanningTreeUtilities* Util) : command_t(Instance, "RSQUIT", 'o', 1), Creator(Callback), Utils(Util)
+{
+       this->source = "m_spanningtree.so";
+       syntax = "<remote-server-mask> [target-server-mask]";
+}
+
+CmdResult cmd_rsquit::Handle (const char** parameters, int pcnt, userrec *user)
+{
+       if (IS_LOCAL(user))
+       {
+               if (!Utils->FindServerMask(parameters[0]))
+               {
+                       user->WriteServ("NOTICE %s :*** RSQUIT: Server \002%s\002 isn't connected to the network!", user->nick, parameters[0]);
+                       return CMD_FAILURE;
+               }
+               if (pcnt > 1)
+                       user->WriteServ("NOTICE %s :*** RSQUIT: Sending remote squit to \002%s\002 to squit server \002%s\002.",user->nick,parameters[0],parameters[1]);
+               else
+                       user->WriteServ("NOTICE %s :*** RSQUIT: Sending remote squit for server \002%s\002.",user->nick,parameters[0]);
+       }
+
+       TreeServer* s = (pcnt > 1) ? Utils->FindServerMask(parameters[1]) : Utils->FindServerMask(parameters[0]);
+
+       if (pcnt > 1)
+       {
+               if (ServerInstance->MatchText(ServerInstance->Config->ServerName,parameters[0]))
+               {
+                       if (s)
+                       {
+                               if (s == Utils->TreeRoot)
+                               {
+                                       NoticeUser(user, "*** RSQUIT: Foolish mortal, you cannot make a server SQUIT itself! ("+ConvToStr(parameters[1])+" matches local server name)");
+                                       return CMD_FAILURE;
+                               }
+                               TreeSocket* sock = s->GetSocket();
+                               if (!sock)
+                               {
+                                       NoticeUser(user, "*** RSQUIT: Server \002"+ConvToStr(parameters[1])+"\002 isn't connected to \002"+ConvToStr(parameters[0])+"\002.");
+                                       return CMD_FAILURE;
+                               }
+                               ServerInstance->SNO->WriteToSnoMask('l',"Remote SQUIT from %s matching \002%s\002, squitting server \002%s\002",user->nick,parameters[0],parameters[1]);
+                               const char* para[1];
+                               para[0] = parameters[1];
+                               std::string original_command = std::string("SQUIT ") + parameters[1];
+                               Creator->OnPreCommand("SQUIT", para, 1, user, true, original_command);
+                               return CMD_LOCALONLY;
+                       }
+               }
+       }
+       else
+       {
+               if (s)
+               {
+                       if (s == Utils->TreeRoot)
+                       {
+                               NoticeUser(user, "*** RSQUIT: Foolish mortal, you cannot make a server SQUIT itself! ("+ConvToStr(parameters[0])+" matches local server name)");
+                               return CMD_FAILURE;
+                       }
+                       TreeSocket* sock = s->GetSocket();
+                       if (sock)
+                       {
+                               ServerInstance->SNO->WriteToSnoMask('l',"RSQUIT: Server \002%s\002 removed from network by %s",parameters[0],user->nick);
+                               sock->Squit(s,std::string("Server quit by ") + user->GetFullRealHost());
+                               ServerInstance->SE->DelFd(sock);
+                               sock->Close();
+                               return CMD_LOCALONLY;
+                       }
+               }
+       }
+
+       return CMD_SUCCESS;
+}
+
+void cmd_rsquit::NoticeUser(userrec* user, const std::string &msg)
+{
+       if (IS_LOCAL(user))
+       {
+               user->WriteServ("NOTICE %s :%s",user->nick,msg.c_str());
+       }
+       else
+       {
+               std::deque<std::string> params;
+               params.push_back(user->nick);
+               params.push_back("NOTICE "+ConvToStr(user->nick)+" :"+msg);
+               Utils->DoOneToOne(ServerInstance->Config->ServerName, "PUSH", params, user->server);
+       }
+}
index ed9eb83d4642677964c1c01553adeeec392ef4ab..81e9bc2b7237b3eb9fc5798659f2fc94ebbbbfb8 100644 (file)
@@ -1 +1,29 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __RSQUIT_H__\r#define __RSQUIT_H__\r\r/** Handle /RCONNECT\r */\rclass cmd_rsquit : public command_t\r{\r        Module* Creator;         /* Creator */\r        SpanningTreeUtilities* Utils;     /* Utility class */\r public:\r        cmd_rsquit (InspIRCd* Instance, Module* Callback, SpanningTreeUtilities* Util);\r        CmdResult Handle (const char** parameters, int pcnt, userrec *user);\r        void NoticeUser(userrec* user, const std::string &msg);\r};\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __RSQUIT_H__
+#define __RSQUIT_H__
+
+/** Handle /RCONNECT
+ */
+class cmd_rsquit : public command_t
+{
+        Module* Creator;               /* Creator */
+        SpanningTreeUtilities* Utils;  /* Utility class */
+ public:
+        cmd_rsquit (InspIRCd* Instance, Module* Callback, SpanningTreeUtilities* Util);
+        CmdResult Handle (const char** parameters, int pcnt, userrec *user);
+        void NoticeUser(userrec* user, const std::string &msg);
+};
+
+#endif
index 8ecb84a4baf1629adac93819f2e6f619f6793a46..af615e91eb5f48c7fc32f9a8b83f546e707378de 100644 (file)
@@ -1 +1,52 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "configreader.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r#include "commands/cmd_whois.h"\r#include "commands/cmd_stats.h"\r#include "socket.h"\r#include "wildcard.h"\r#include "xline.h"\r#include "transport.h"\r\r#include "m_spanningtree/timesynctimer.h"\r#include "m_spanningtree/main.h"\r#include "m_spanningtree/utils.h"\r#include "m_spanningtree/treeserver.h"\r#include "m_spanningtree/link.h"\r#include "m_spanningtree/treesocket.h"\r\r/* $ModDep: m_spanningtree/timesynctimer.h m_spanningtree/resolvers.h m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/link.h m_spanningtree/treesocket.h */\r\rTimeSyncTimer::TimeSyncTimer(InspIRCd *Inst, ModuleSpanningTree *Mod) : InspTimer(600, Inst->Time(), true), Instance(Inst), Module(Mod)\r{\r}\r\rvoid TimeSyncTimer::Tick(time_t TIME)\r{\r Module->BroadcastTimeSync();\r}\r\rCacheRefreshTimer::CacheRefreshTimer(InspIRCd *Inst, SpanningTreeUtilities *Util) : InspTimer(3600, Inst->Time(), true), Instance(Inst), Utils(Util)\r{\r}\r\rvoid CacheRefreshTimer::Tick(time_t TIME)\r{\r  Utils->RefreshIPCache();\r}\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "configreader.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+#include "commands/cmd_whois.h"
+#include "commands/cmd_stats.h"
+#include "socket.h"
+#include "wildcard.h"
+#include "xline.h"
+#include "transport.h"
+
+#include "m_spanningtree/timesynctimer.h"
+#include "m_spanningtree/main.h"
+#include "m_spanningtree/utils.h"
+#include "m_spanningtree/treeserver.h"
+#include "m_spanningtree/link.h"
+#include "m_spanningtree/treesocket.h"
+
+/* $ModDep: m_spanningtree/timesynctimer.h m_spanningtree/resolvers.h m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/link.h m_spanningtree/treesocket.h */
+
+TimeSyncTimer::TimeSyncTimer(InspIRCd *Inst, ModuleSpanningTree *Mod) : InspTimer(600, Inst->Time(), true), Instance(Inst), Module(Mod)
+{
+}
+
+void TimeSyncTimer::Tick(time_t TIME)
+{
+       Module->BroadcastTimeSync();
+}
+
+CacheRefreshTimer::CacheRefreshTimer(InspIRCd *Inst, SpanningTreeUtilities *Util) : InspTimer(3600, Inst->Time(), true), Instance(Inst), Utils(Util)
+{
+}
+
+void CacheRefreshTimer::Tick(time_t TIME)
+{
+       Utils->RefreshIPCache();
+}
+
index dd23ee1719b6184df65673a1bb0a1b2b449267f3..434ee253c33fe95f2e2fa7f08565817ee027c7f3 100644 (file)
@@ -1 +1,47 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __TIMESYNC_H__\r#define __TIMESYNC_H__\r\r#include "timer.h"\r\rclass ModuleSpanningTree;\rclass SpanningTreeUtilities;\rclass InspIRCd;\r\r/** Create a timer which recurs every second, we inherit from InspTimer.\r * InspTimer is only one-shot however, so at the end of each Tick() we simply\r * insert another of ourselves into the pending queue :)\r */\rclass TimeSyncTimer : public InspTimer\r{\r private:\r InspIRCd *Instance;\r    ModuleSpanningTree *Module;\r public:\r   TimeSyncTimer(InspIRCd *Instance, ModuleSpanningTree *Mod);\r    virtual void Tick(time_t TIME);\r};\r\rclass CacheRefreshTimer : public InspTimer\r{\r private:\r     InspIRCd *Instance;\r    SpanningTreeUtilities *Utils;\r public:\r CacheRefreshTimer(InspIRCd *Instance, SpanningTreeUtilities* Util);\r    virtual void Tick(time_t TIME);\r};\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __TIMESYNC_H__
+#define __TIMESYNC_H__
+
+#include "timer.h"
+
+class ModuleSpanningTree;
+class SpanningTreeUtilities;
+class InspIRCd;
+
+/** Create a timer which recurs every second, we inherit from InspTimer.
+ * InspTimer is only one-shot however, so at the end of each Tick() we simply
+ * insert another of ourselves into the pending queue :)
+ */
+class TimeSyncTimer : public InspTimer
+{
+ private:
+       InspIRCd *Instance;
+       ModuleSpanningTree *Module;
+ public:
+       TimeSyncTimer(InspIRCd *Instance, ModuleSpanningTree *Mod);
+       virtual void Tick(time_t TIME);
+};
+
+class CacheRefreshTimer : public InspTimer
+{
+ private:
+       InspIRCd *Instance;
+       SpanningTreeUtilities *Utils;
+ public:
+       CacheRefreshTimer(InspIRCd *Instance, SpanningTreeUtilities* Util);
+       virtual void Tick(time_t TIME);
+};
+
+#endif
index 670f7e420e06f63c4fbdd1a0f4698e94deac300b..b5cac18021a42d74e8d4aa95c88dbeefaef3ca1a 100644 (file)
@@ -1 +1,325 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "configreader.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r#include "commands/cmd_whois.h"\r#include "commands/cmd_stats.h"\r#include "socket.h"\r#include "wildcard.h"\r#include "xline.h"\r#include "transport.h"\r\r#include "m_spanningtree/utils.h"\r#include "m_spanningtree/treeserver.h"\r\r/* $ModDep: m_spanningtree/utils.h m_spanningtree/treeserver.h */\r\rTreeServer::TreeServer(SpanningTreeUtilities* Util, InspIRCd* Instance) : ServerInstance(Instance), Utils(Util)\r{\r Parent = NULL;\r ServerName.clear();\r    ServerDesc.clear();\r    VersionString.clear();\r UserCount = OperCount = 0;\r     rtt = LastPing = 0;\r    Hidden = false;\r        VersionString = ServerInstance->GetVersionString();\r}\r\r/** We use this constructor only to create the 'root' item, Utils->TreeRoot, which\r * represents our own server. Therefore, it has no route, no parent, and\r * no socket associated with it. Its version string is our own local version.\r */\rTreeServer::TreeServer(SpanningTreeUtilities* Util, InspIRCd* Instance, std::string Name, std::string Desc) : ServerInstance(Instance), ServerName(Name.c_str()), ServerDesc(Desc), Utils(Util)\r{\r Parent = NULL;\r VersionString.clear();\r UserCount = ServerInstance->UserCount();\r       OperCount = ServerInstance->OperCount();\r       VersionString = ServerInstance->GetVersionString();\r    Route = NULL;\r  Socket = NULL; /* Fix by brain */\r      rtt = LastPing = 0;\r    Hidden = false;\r        AddHashEntry();\r}\r\r/** When we create a new server, we call this constructor to initialize it.\r * This constructor initializes the server's Route and Parent, and sets up\r * its ping counters so that it will be pinged one minute from now.\r */\rTreeServer::TreeServer(SpanningTreeUtilities* Util, InspIRCd* Instance, std::string Name, std::string Desc, TreeServer* Above, TreeSocket* Sock, bool Hide)\r  : ServerInstance(Instance), Parent(Above), ServerName(Name.c_str()), ServerDesc(Desc), Socket(Sock), Utils(Util), Hidden(Hide)\r{\r       VersionString.clear();\r UserCount = OperCount = 0;\r     this->SetNextPingTime(time(NULL) + 60);\r        this->SetPingFlag();\r   rtt = LastPing = 0;\r    /* find the 'route' for this server (e.g. the one directly connected\r    * to the local server, which we can use to reach it)\r   *\r      * In the following example, consider we have just added a TreeServer\r   * class for server G on our network, of which we are server A.\r         * To route traffic to G (marked with a *) we must send the data to\r     * B (marked with a +) so this algorithm initializes the 'Route'\r        * value to point at whichever server traffic must be routed through\r    * to get here. If we were to try this algorithm with server B,\r         * the Route pointer would point at its own object ('this').\r    *\r      *            A\r         *           / \\r        *        + B   C\r       *         / \   \\r      *        D   E   F\r     *       /         \\r    *    * G           H\r   *\r      * We only run this algorithm when a server is created, as\r      * the routes remain constant while ever the server exists, and\r         * do not need to be re-calculated.\r     */\r\r   Route = Above;\r if (Route == Utils->TreeRoot)\r  {\r              Route = this;\r  }\r      else\r   {\r              while (this->Route->GetParent() != Utils->TreeRoot)\r            {\r                      this->Route = Route->GetParent();\r              }\r      }\r\r     /* Because recursive code is slow and takes a lot of resources,\r         * we store two representations of the server tree. The first\r   * is a recursive structure where each server references its\r    * children and its parent, which is used for netbursts and\r     * netsplits to dump the whole dataset to the other server,\r     * and the second is used for very fast lookups when routing\r    * messages and is instead a hash_map, where each item can\r      * be referenced by its server name. The AddHashEntry()\r         * call below automatically inserts each TreeServer class\r       * into the hash_map as it is created. There is a similar\r       * maintainance call in the destructor to tidy up deleted\r       * servers.\r     */\r\r   this->AddHashEntry();\r}\r\rint TreeServer::QuitUsers(const std::string &reason)\r{\r        const char* reason_s = reason.c_str();\r std::vector<userrec*> time_to_die;\r     for (user_hash::iterator n = ServerInstance->clientlist->begin(); n != ServerInstance->clientlist->end(); n++)\r {\r              if (!strcmp(n->second->server, this->ServerName.c_str()))\r              {\r                      time_to_die.push_back(n->second);\r              }\r      }\r      for (std::vector<userrec*>::iterator n = time_to_die.begin(); n != time_to_die.end(); n++)\r     {\r              userrec* a = (userrec*)*n;\r             if (!IS_LOCAL(a))\r              {\r                      if (ServerInstance->Config->HideSplits)\r                                userrec::QuitUser(ServerInstance, a, "*.net *.split", reason_s);\r                       else\r                           userrec::QuitUser(ServerInstance, a, reason_s);\r\r                       if (this->Utils->quiet_bursts)\r                         ServerInstance->GlobalCulls.MakeSilent(a);\r             }\r      }\r      return time_to_die.size();\r}\r\r/** This method is used to add the structure to the\r * hash_map for linear searches. It is only called\r * by the constructors.\r */\rvoid TreeServer::AddHashEntry()\r{\r     server_hash::iterator iter = Utils->serverlist.find(this->ServerName.c_str());\r if (iter == Utils->serverlist.end())\r           Utils->serverlist[this->ServerName.c_str()] = this;\r}\r\r/** This method removes the reference to this object\r * from the hash_map which is used for linear searches.\r * It is only called by the default destructor.\r */\rvoid TreeServer::DelHashEntry()\r{\r      server_hash::iterator iter = Utils->serverlist.find(this->ServerName.c_str());\r if (iter != Utils->serverlist.end())\r           Utils->serverlist.erase(iter);\r}\r\r/** These accessors etc should be pretty self-\r * explanitory.\r */\rTreeServer* TreeServer::GetRoute()\r{\r      return Route;\r}\r\rstd::string TreeServer::GetName()\r{\r   return ServerName.c_str();\r}\r\rstd::string TreeServer::GetDesc()\r{\r      return ServerDesc;\r}\r\rstd::string TreeServer::GetVersion()\r{\r   return VersionString;\r}\r\rvoid TreeServer::SetNextPingTime(time_t t)\r{\r  this->NextPing = t;\r    LastPingWasGood = false;\r}\r\rtime_t TreeServer::NextPingTime()\r{\r        return NextPing;\r}\r\rbool TreeServer::AnsweredLastPing()\r{\r      return LastPingWasGood;\r}\r\rvoid TreeServer::SetPingFlag()\r{\r    LastPingWasGood = true;\r}\r\rint TreeServer::GetUserCount()\r{\r    return UserCount;\r}\r\rvoid TreeServer::AddUserCount()\r{\r UserCount++;\r}\r\rvoid TreeServer::DelUserCount()\r{\r      UserCount--;\r}\r\rint TreeServer::GetOperCount()\r{\r       return OperCount;\r}\r\rTreeSocket* TreeServer::GetSocket()\r{\r     return Socket;\r}\r\rTreeServer* TreeServer::GetParent()\r{\r        return Parent;\r}\r\rvoid TreeServer::SetVersion(const std::string &Version)\r{\r    VersionString = Version;\r}\r\runsigned int TreeServer::ChildCount()\r{\r    return Children.size();\r}\r\rTreeServer* TreeServer::GetChild(unsigned int n)\r{\r  if (n < Children.size())\r       {\r              /* Make sure they  cant request\r                 * an out-of-range object. After\r                * all we know what these programmer\r            * types are like *grin*.\r               */\r            return Children[n];\r    }\r      else\r   {\r              return NULL;\r   }\r}\r\rvoid TreeServer::AddChild(TreeServer* Child)\r{\r    Children.push_back(Child);\r}\r\rbool TreeServer::DelChild(TreeServer* Child)\r{\r   for (std::vector<TreeServer*>::iterator a = Children.begin(); a < Children.end(); a++)\r {\r              if (*a == Child)\r               {\r                      Children.erase(a);\r                     return true;\r           }\r      }\r      return false;\r}\r\r/** Removes child nodes of this node, and of that node, etc etc.\r * This is used during netsplits to automatically tidy up the\r * server tree. It is slow, we don't use it for much else.\r */\rbool TreeServer::Tidy()\r{\r       bool stillchildren = true;\r     while (stillchildren)\r  {\r              stillchildren = false;\r         for (std::vector<TreeServer*>::iterator a = Children.begin(); a < Children.end(); a++)\r         {\r                      TreeServer* s = (TreeServer*)*a;\r                       s->Tidy();\r                     Children.erase(a);\r                     DELETE(s);\r                     stillchildren = true;\r                  break;\r         }\r      }\r      return true;\r}\r\rTreeServer::~TreeServer()\r{\r    /* We'd better tidy up after ourselves, eh? */\r this->DelHashEntry();\r}\r\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "configreader.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+#include "commands/cmd_whois.h"
+#include "commands/cmd_stats.h"
+#include "socket.h"
+#include "wildcard.h"
+#include "xline.h"
+#include "transport.h"
+
+#include "m_spanningtree/utils.h"
+#include "m_spanningtree/treeserver.h"
+
+/* $ModDep: m_spanningtree/utils.h m_spanningtree/treeserver.h */
+
+TreeServer::TreeServer(SpanningTreeUtilities* Util, InspIRCd* Instance) : ServerInstance(Instance), Utils(Util)
+{
+       Parent = NULL;
+       ServerName.clear();
+       ServerDesc.clear();
+       VersionString.clear();
+       UserCount = OperCount = 0;
+       rtt = LastPing = 0;
+       Hidden = false;
+       VersionString = ServerInstance->GetVersionString();
+}
+
+/** We use this constructor only to create the 'root' item, Utils->TreeRoot, which
+ * represents our own server. Therefore, it has no route, no parent, and
+ * no socket associated with it. Its version string is our own local version.
+ */
+TreeServer::TreeServer(SpanningTreeUtilities* Util, InspIRCd* Instance, std::string Name, std::string Desc) : ServerInstance(Instance), ServerName(Name.c_str()), ServerDesc(Desc), Utils(Util)
+{
+       Parent = NULL;
+       VersionString.clear();
+       UserCount = ServerInstance->UserCount();
+       OperCount = ServerInstance->OperCount();
+       VersionString = ServerInstance->GetVersionString();
+       Route = NULL;
+       Socket = NULL; /* Fix by brain */
+       rtt = LastPing = 0;
+       Hidden = false;
+       AddHashEntry();
+}
+
+/** When we create a new server, we call this constructor to initialize it.
+ * This constructor initializes the server's Route and Parent, and sets up
+ * its ping counters so that it will be pinged one minute from now.
+ */
+TreeServer::TreeServer(SpanningTreeUtilities* Util, InspIRCd* Instance, std::string Name, std::string Desc, TreeServer* Above, TreeSocket* Sock, bool Hide)
+       : ServerInstance(Instance), Parent(Above), ServerName(Name.c_str()), ServerDesc(Desc), Socket(Sock), Utils(Util), Hidden(Hide)
+{
+       VersionString.clear();
+       UserCount = OperCount = 0;
+       this->SetNextPingTime(time(NULL) + 60);
+       this->SetPingFlag();
+       rtt = LastPing = 0;
+       /* find the 'route' for this server (e.g. the one directly connected
+        * to the local server, which we can use to reach it)
+        *
+        * In the following example, consider we have just added a TreeServer
+        * class for server G on our network, of which we are server A.
+        * To route traffic to G (marked with a *) we must send the data to
+        * B (marked with a +) so this algorithm initializes the 'Route'
+        * value to point at whichever server traffic must be routed through
+        * to get here. If we were to try this algorithm with server B,
+        * the Route pointer would point at its own object ('this').
+        *
+        *            A
+        *           / \
+        *        + B   C
+        *         / \   \
+        *        D   E   F
+        *       /         \
+        *    * G           H
+        *
+        * We only run this algorithm when a server is created, as
+        * the routes remain constant while ever the server exists, and
+        * do not need to be re-calculated.
+        */
+
+       Route = Above;
+       if (Route == Utils->TreeRoot)
+       {
+               Route = this;
+       }
+       else
+       {
+               while (this->Route->GetParent() != Utils->TreeRoot)
+               {
+                       this->Route = Route->GetParent();
+               }
+       }
+
+       /* Because recursive code is slow and takes a lot of resources,
+        * we store two representations of the server tree. The first
+        * is a recursive structure where each server references its
+        * children and its parent, which is used for netbursts and
+        * netsplits to dump the whole dataset to the other server,
+        * and the second is used for very fast lookups when routing
+        * messages and is instead a hash_map, where each item can
+        * be referenced by its server name. The AddHashEntry()
+        * call below automatically inserts each TreeServer class
+        * into the hash_map as it is created. There is a similar
+        * maintainance call in the destructor to tidy up deleted
+        * servers.
+        */
+
+       this->AddHashEntry();
+}
+
+int TreeServer::QuitUsers(const std::string &reason)
+{
+       const char* reason_s = reason.c_str();
+       std::vector<userrec*> time_to_die;
+       for (user_hash::iterator n = ServerInstance->clientlist->begin(); n != ServerInstance->clientlist->end(); n++)
+       {
+               if (!strcmp(n->second->server, this->ServerName.c_str()))
+               {
+                       time_to_die.push_back(n->second);
+               }
+       }
+       for (std::vector<userrec*>::iterator n = time_to_die.begin(); n != time_to_die.end(); n++)
+       {
+               userrec* a = (userrec*)*n;
+               if (!IS_LOCAL(a))
+               {
+                       if (ServerInstance->Config->HideSplits)
+                               userrec::QuitUser(ServerInstance, a, "*.net *.split", reason_s);
+                       else
+                               userrec::QuitUser(ServerInstance, a, reason_s);
+
+                       if (this->Utils->quiet_bursts)
+                               ServerInstance->GlobalCulls.MakeSilent(a);
+               }
+       }
+       return time_to_die.size();
+}
+
+/** This method is used to add the structure to the
+ * hash_map for linear searches. It is only called
+ * by the constructors.
+ */
+void TreeServer::AddHashEntry()
+{
+       server_hash::iterator iter = Utils->serverlist.find(this->ServerName.c_str());
+       if (iter == Utils->serverlist.end())
+               Utils->serverlist[this->ServerName.c_str()] = this;
+}
+
+/** This method removes the reference to this object
+ * from the hash_map which is used for linear searches.
+ * It is only called by the default destructor.
+ */
+void TreeServer::DelHashEntry()
+{
+       server_hash::iterator iter = Utils->serverlist.find(this->ServerName.c_str());
+       if (iter != Utils->serverlist.end())
+               Utils->serverlist.erase(iter);
+}
+
+/** These accessors etc should be pretty self-
+ * explanitory.
+ */
+TreeServer* TreeServer::GetRoute()
+{
+       return Route;
+}
+
+std::string TreeServer::GetName()
+{
+       return ServerName.c_str();
+}
+
+std::string TreeServer::GetDesc()
+{
+       return ServerDesc;
+}
+
+std::string TreeServer::GetVersion()
+{
+       return VersionString;
+}
+
+void TreeServer::SetNextPingTime(time_t t)
+{
+       this->NextPing = t;
+       LastPingWasGood = false;
+}
+
+time_t TreeServer::NextPingTime()
+{
+       return NextPing;
+}
+
+bool TreeServer::AnsweredLastPing()
+{
+       return LastPingWasGood;
+}
+
+void TreeServer::SetPingFlag()
+{
+       LastPingWasGood = true;
+}
+
+int TreeServer::GetUserCount()
+{
+       return UserCount;
+}
+
+void TreeServer::AddUserCount()
+{
+       UserCount++;
+}
+
+void TreeServer::DelUserCount()
+{
+       UserCount--;
+}
+
+int TreeServer::GetOperCount()
+{
+       return OperCount;
+}
+
+TreeSocket* TreeServer::GetSocket()
+{
+       return Socket;
+}
+
+TreeServer* TreeServer::GetParent()
+{
+       return Parent;
+}
+
+void TreeServer::SetVersion(const std::string &Version)
+{
+       VersionString = Version;
+}
+
+unsigned int TreeServer::ChildCount()
+{
+       return Children.size();
+}
+
+TreeServer* TreeServer::GetChild(unsigned int n)
+{
+       if (n < Children.size())
+       {
+               /* Make sure they  cant request
+                * an out-of-range object. After
+                * all we know what these programmer
+                * types are like *grin*.
+                */
+               return Children[n];
+       }
+       else
+       {
+               return NULL;
+       }
+}
+
+void TreeServer::AddChild(TreeServer* Child)
+{
+       Children.push_back(Child);
+}
+
+bool TreeServer::DelChild(TreeServer* Child)
+{
+       for (std::vector<TreeServer*>::iterator a = Children.begin(); a < Children.end(); a++)
+       {
+               if (*a == Child)
+               {
+                       Children.erase(a);
+                       return true;
+               }
+       }
+       return false;
+}
+
+/** Removes child nodes of this node, and of that node, etc etc.
+ * This is used during netsplits to automatically tidy up the
+ * server tree. It is slow, we don't use it for much else.
+ */
+bool TreeServer::Tidy()
+{
+       bool stillchildren = true;
+       while (stillchildren)
+       {
+               stillchildren = false;
+               for (std::vector<TreeServer*>::iterator a = Children.begin(); a < Children.end(); a++)
+               {
+                       TreeServer* s = (TreeServer*)*a;
+                       s->Tidy();
+                       Children.erase(a);
+                       DELETE(s);
+                       stillchildren = true;
+                       break;
+               }
+       }
+       return true;
+}
+
+TreeServer::~TreeServer()
+{
+       /* We'd better tidy up after ourselves, eh? */
+       this->DelHashEntry();
+}
+
+
index e942c1acc2bf2357c1f267ba3276a4caaaa24f33..514d6bc07a04c37fb7a7679f72ac6296926ca682 100644 (file)
@@ -1 +1,186 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __TREESERVER_H__\r#define __TREESERVER_H__\r\r/** Each server in the tree is represented by one class of\r * type TreeServer. A locally connected TreeServer can\r * have a class of type TreeSocket associated with it, for\r * remote servers, the TreeSocket entry will be NULL.\r * Each server also maintains a pointer to its parent\r * (NULL if this server is ours, at the top of the tree)\r * and a pointer to its "Route" (see the comments in the\r * constructors below), and also a dynamic list of pointers\r * to its children which can be iterated recursively\r * if required. Creating or deleting objects of type\r i* TreeServer automatically maintains the hash_map of\r * TreeServer items, deleting and inserting them as they\r * are created and destroyed.\r */\rclass TreeServer : public classbase\r{\r       InspIRCd* ServerInstance;               /* Creator */\r  TreeServer* Parent;                     /* Parent entry */\r     TreeServer* Route;                      /* Route entry */\r      std::vector<TreeServer*> Children;      /* List of child objects */\r    irc::string ServerName;                 /* Server's name */\r    std::string ServerDesc;                 /* Server's description */\r     std::string VersionString;              /* Version string or empty string */\r   int UserCount;                          /* Not used in this version */\r int OperCount;                          /* Not used in this version */\r TreeSocket* Socket;                     /* For directly connected servers this points at the socket object */\r  time_t NextPing;                        /* After this time, the server should be PINGed*/\r      bool LastPingWasGood;                   /* True if the server responded to the last PING with a PONG */\r        SpanningTreeUtilities* Utils;           /* Utility class */\r\r public:\r\r bool Warned;                            /* True if we've warned opers about high latency on this server */\r\r    /** We don't use this constructor. Its a dummy, and won't cause any insertion\r   * of the TreeServer into the hash_map. See below for the two we DO use.\r        */\r    TreeServer(SpanningTreeUtilities* Util, InspIRCd* Instance);\r\r  /** We use this constructor only to create the 'root' item, Utils->TreeRoot, which\r      * represents our own server. Therefore, it has no route, no parent, and\r        * no socket associated with it. Its version string is our own local version.\r   */\r    TreeServer(SpanningTreeUtilities* Util, InspIRCd* Instance, std::string Name, std::string Desc);\r       \r       /** When we create a new server, we call this constructor to initialize it.\r     * This constructor initializes the server's Route and Parent, and sets up\r      * its ping counters so that it will be pinged one minute from now.\r     */\r    TreeServer(SpanningTreeUtilities* Util, InspIRCd* Instance, std::string Name, std::string Desc, TreeServer* Above, TreeSocket* Sock, bool Hide);\r\r      int QuitUsers(const std::string &reason);\r\r     /** This method is used to add the structure to the\r     * hash_map for linear searches. It is only called\r      * by the constructors.\r         */\r    void AddHashEntry();\r\r  /** This method removes the reference to this object\r    * from the hash_map which is used for linear searches.\r         * It is only called by the default destructor.\r         */\r    void DelHashEntry();\r\r  /** Get route.\r  * The 'route' is defined as the locally-\r       * connected server which can be used to reach this server.\r     */\r    TreeServer* GetRoute();\r\r       /** Get server name\r     */\r    std::string GetName();\r\r        /** Get server description (GECOS)\r      */\r    std::string GetDesc();\r\r        /** Get server version string\r   */\r    std::string GetVersion();\r\r     /** Set time we are next due to ping this server\r        */\r    void SetNextPingTime(time_t t);\r\r       /** Get the time we are next due to ping this server\r    */\r    time_t NextPingTime();\r\r        /** Time of last ping used to calculate this->rtt below\r         */\r    time_t LastPing;\r\r      /** Round trip time of last ping\r        */\r    time_t rtt;\r\r   /** True if this server is hidden\r       */\r    bool Hidden;\r\r  /** True if the server answered their last ping\r         */\r    bool AnsweredLastPing();\r\r      /** Set the server as responding to its last ping\r       */\r    void SetPingFlag();\r\r   /** Get the number of users on this server for MAP\r      */\r    int GetUserCount();\r\r   /** Increment the user counter\r  */\r    void AddUserCount();\r\r  /** Decrement the user counter\r  */\r    void DelUserCount();\r\r  /** Get the oper count for this server\r  */\r    int GetOperCount();\r\r   /** Get the TreeSocket pointer for local servers.\r       * For remote servers, this returns NULL.\r       */\r    TreeSocket* GetSocket();\r\r      /** Get the parent server.\r      * For the root node, this returns NULL.\r        */\r    TreeServer* GetParent();\r\r      /** Set the server version string\r       */\r    void SetVersion(const std::string &Version);\r\r  /** Return number of child servers\r      */\r    unsigned int ChildCount();\r\r    /** Return a child server indexed 0..n\r  */\r    TreeServer* GetChild(unsigned int n);\r\r /** Add a child server\r  */\r    void AddChild(TreeServer* Child);\r\r     /** Delete a child server, return false if it didn't exist.\r     */\r    bool DelChild(TreeServer* Child);\r\r     /** Removes child nodes of this node, and of that node, etc etc.\r        * This is used during netsplits to automatically tidy up the\r   * server tree. It is slow, we don't use it for much else.\r      */\r    bool Tidy();\r\r  /** Destructor\r  */\r    ~TreeServer();\r\r};\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __TREESERVER_H__
+#define __TREESERVER_H__
+
+/** Each server in the tree is represented by one class of
+ * type TreeServer. A locally connected TreeServer can
+ * have a class of type TreeSocket associated with it, for
+ * remote servers, the TreeSocket entry will be NULL.
+ * Each server also maintains a pointer to its parent
+ * (NULL if this server is ours, at the top of the tree)
+ * and a pointer to its "Route" (see the comments in the
+ * constructors below), and also a dynamic list of pointers
+ * to its children which can be iterated recursively
+ * if required. Creating or deleting objects of type
+ i* TreeServer automatically maintains the hash_map of
+ * TreeServer items, deleting and inserting them as they
+ * are created and destroyed.
+ */
+class TreeServer : public classbase
+{
+       InspIRCd* ServerInstance;               /* Creator */
+       TreeServer* Parent;                     /* Parent entry */
+       TreeServer* Route;                      /* Route entry */
+       std::vector<TreeServer*> Children;      /* List of child objects */
+       irc::string ServerName;                 /* Server's name */
+       std::string ServerDesc;                 /* Server's description */
+       std::string VersionString;              /* Version string or empty string */
+       int UserCount;                          /* Not used in this version */
+       int OperCount;                          /* Not used in this version */
+       TreeSocket* Socket;                     /* For directly connected servers this points at the socket object */
+       time_t NextPing;                        /* After this time, the server should be PINGed*/
+       bool LastPingWasGood;                   /* True if the server responded to the last PING with a PONG */
+       SpanningTreeUtilities* Utils;           /* Utility class */
+
+ public:
+
+       bool Warned;                            /* True if we've warned opers about high latency on this server */
+
+       /** We don't use this constructor. Its a dummy, and won't cause any insertion
+        * of the TreeServer into the hash_map. See below for the two we DO use.
+        */
+       TreeServer(SpanningTreeUtilities* Util, InspIRCd* Instance);
+
+       /** We use this constructor only to create the 'root' item, Utils->TreeRoot, which
+        * represents our own server. Therefore, it has no route, no parent, and
+        * no socket associated with it. Its version string is our own local version.
+        */
+       TreeServer(SpanningTreeUtilities* Util, InspIRCd* Instance, std::string Name, std::string Desc);
+       
+       /** When we create a new server, we call this constructor to initialize it.
+        * This constructor initializes the server's Route and Parent, and sets up
+        * its ping counters so that it will be pinged one minute from now.
+        */
+       TreeServer(SpanningTreeUtilities* Util, InspIRCd* Instance, std::string Name, std::string Desc, TreeServer* Above, TreeSocket* Sock, bool Hide);
+
+       int QuitUsers(const std::string &reason);
+
+       /** This method is used to add the structure to the
+        * hash_map for linear searches. It is only called
+        * by the constructors.
+        */
+       void AddHashEntry();
+
+       /** This method removes the reference to this object
+        * from the hash_map which is used for linear searches.
+        * It is only called by the default destructor.
+        */
+       void DelHashEntry();
+
+       /** Get route.
+        * The 'route' is defined as the locally-
+        * connected server which can be used to reach this server.
+        */
+       TreeServer* GetRoute();
+
+       /** Get server name
+        */
+       std::string GetName();
+
+       /** Get server description (GECOS)
+        */
+       std::string GetDesc();
+
+       /** Get server version string
+        */
+       std::string GetVersion();
+
+       /** Set time we are next due to ping this server
+        */
+       void SetNextPingTime(time_t t);
+
+       /** Get the time we are next due to ping this server
+        */
+       time_t NextPingTime();
+
+       /** Time of last ping used to calculate this->rtt below
+        */
+       time_t LastPing;
+
+       /** Round trip time of last ping
+        */
+       time_t rtt;
+
+       /** True if this server is hidden
+        */
+       bool Hidden;
+
+       /** True if the server answered their last ping
+        */
+       bool AnsweredLastPing();
+
+       /** Set the server as responding to its last ping
+        */
+       void SetPingFlag();
+
+       /** Get the number of users on this server for MAP
+        */
+       int GetUserCount();
+
+       /** Increment the user counter
+        */
+       void AddUserCount();
+
+       /** Decrement the user counter
+        */
+       void DelUserCount();
+
+       /** Get the oper count for this server
+        */
+       int GetOperCount();
+
+       /** Get the TreeSocket pointer for local servers.
+        * For remote servers, this returns NULL.
+        */
+       TreeSocket* GetSocket();
+
+       /** Get the parent server.
+        * For the root node, this returns NULL.
+        */
+       TreeServer* GetParent();
+
+       /** Set the server version string
+        */
+       void SetVersion(const std::string &Version);
+
+       /** Return number of child servers
+        */
+       unsigned int ChildCount();
+
+       /** Return a child server indexed 0..n
+        */
+       TreeServer* GetChild(unsigned int n);
+
+       /** Add a child server
+        */
+       void AddChild(TreeServer* Child);
+
+       /** Delete a child server, return false if it didn't exist.
+        */
+       bool DelChild(TreeServer* Child);
+
+       /** Removes child nodes of this node, and of that node, etc etc.
+        * This is used during netsplits to automatically tidy up the
+        * server tree. It is slow, we don't use it for much else.
+        */
+       bool Tidy();
+
+       /** Destructor
+        */
+       ~TreeServer();
+
+};
+
+#endif
index bd99c1480e315493bbf77a7a232ddf944c98ec9d..fae22638d6c8d4c030184e74f93fda7c0eebcd04 100644 (file)
@@ -1 +1,413 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __TREESOCKET_H__\r#define __TREESOCKET_H__\r\r#include "configreader.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r#include "commands/cmd_whois.h"\r#include "commands/cmd_stats.h"\r#include "socket.h"\r#include "inspircd.h"\r#include "wildcard.h"\r#include "xline.h"\r#include "transport.h"\r\r#include "m_spanningtree/utils.h"\r\r/*\r * The server list in InspIRCd is maintained as two structures\r * which hold the data in different ways. Most of the time, we\r * want to very quicky obtain three pieces of information:\r *\r * (1) The information on a server\r * (2) The information on the server we must send data through\r *     to actually REACH the server we're after\r * (3) Potentially, the child/parent objects of this server\r *\r * The InspIRCd spanning protocol provides easy access to these\r * by storing the data firstly in a recursive structure, where\r * each item references its parent item, and a dynamic list\r * of child items, and another structure which stores the items\r * hashed, linearly. This means that if we want to find a server\r * by name quickly, we can look it up in the hash, avoiding\r * any O(n) lookups. If however, during a split or sync, we want\r * to apply an operation to a server, and any of its child objects\r * we can resort to recursion to walk the tree structure.\r * Any socket can have one of five states at any one time.\r * The LISTENER state indicates a socket which is listening\r * for connections. It cannot receive data itself, only incoming\r * sockets.\r * The CONNECTING state indicates an outbound socket which is\r * waiting to be writeable.\r * The WAIT_AUTH_1 state indicates the socket is outbound and\r * has successfully connected, but has not yet sent and received\r * SERVER strings.\r * The WAIT_AUTH_2 state indicates that the socket is inbound\r * (allocated by a LISTENER) but has not yet sent and received\r * SERVER strings.\r * The CONNECTED state represents a fully authorized, fully\r * connected server.\r */\renum ServerState { LISTENER, CONNECTING, WAIT_AUTH_1, WAIT_AUTH_2, CONNECTED };\r\r/** Every SERVER connection inbound or outbound is represented by\r * an object of type TreeSocket.\r * TreeSockets, being inherited from InspSocket, can be tied into\r * the core socket engine, and we cn therefore receive activity events\r * for them, just like activex objects on speed. (yes really, that\r * is a technical term!) Each of these which relates to a locally\r * connected server is assocated with it, by hooking it onto a\r * TreeSocket class using its constructor. In this way, we can\r * maintain a list of servers, some of which are directly connected,\r * some of which are not.\r */\rclass TreeSocket : public InspSocket\r{\r     SpanningTreeUtilities* Utils;           /* Utility class */\r    std::string myhost;                     /* Canonical hostname */\r       std::string in_buffer;                  /* Input buffer */\r     ServerState LinkState;                  /* Link state */\r       std::string InboundServerName;          /* Server name sent to us by other side */\r     std::string InboundDescription;         /* Server description (GECOS) sent to us by the other side */\r  int num_lost_users;                     /* Users lost in split */\r      int num_lost_servers;                   /* Servers lost in split */\r    time_t NextPing;                        /* Time when we are due to ping this server */\r bool LastPingWasGood;                   /* Responded to last ping we sent? */\r  bool bursting;                          /* True if not finished bursting yet */\r        unsigned int keylength;                 /* Is this still used? */\r      std::string ModuleList;                 /* Module list of other server from CAPAB */\r   std::map<std::string,std::string> CapKeys;      /* CAPAB keys from other server */\r     Module* Hook;                           /* I/O hooking module that we're attached to for this socket */\r        std::string ourchallenge;               /* Challenge sent for challenge/response */\r    std::string theirchallenge;             /* Challenge recv for challenge/response */\r    std::string OutboundPass;               /* Outbound password */\r        bool sentcapab;                         /* Have sent CAPAB already */\r public:\r\r        /** Because most of the I/O gubbins are encapsulated within\r     * InspSocket, we just call the superclass constructor for\r      * most of the action, and append a few of our own values\r       * to it.\r       */\r    TreeSocket(SpanningTreeUtilities* Util, InspIRCd* SI, std::string host, int port, bool listening, unsigned long maxtime, Module* HookMod = NULL);\r\r     /** Because most of the I/O gubbins are encapsulated within\r     * InspSocket, we just call the superclass constructor for\r      * most of the action, and append a few of our own values\r       * to it.\r       */\r    TreeSocket(SpanningTreeUtilities* Util, InspIRCd* SI, std::string host, int port, bool listening, unsigned long maxtime, const std::string &ServerName, const std::string &bindto, Module* HookMod = NULL);\r\r   /** When a listening socket gives us a new file descriptor,\r     * we must associate it with a socket without creating a new\r    * connection. This constructor is used for this purpose.\r       */\r    TreeSocket(SpanningTreeUtilities* Util, InspIRCd* SI, int newfd, char* ip, Module* HookMod = NULL);\r\r   /** Get link state\r      */\r    ServerState GetLinkState();\r\r   /** Get challenge set in our CAPAB for challenge/response\r       */\r    const std::string& GetOurChallenge();\r\r /** Get challenge set in our CAPAB for challenge/response\r       */\r    void SetOurChallenge(const std::string &c);\r\r   /** Get challenge set in their CAPAB for challenge/response\r     */\r    const std::string& GetTheirChallenge();\r\r       /** Get challenge set in their CAPAB for challenge/response\r     */\r    void SetTheirChallenge(const std::string &c);\r\r /** Compare two passwords based on authentication scheme\r        */\r    bool ComparePass(const std::string &ours, const std::string &theirs);\r\r /** Return the module which we are hooking to for I/O encapsulation\r     */\r    Module* GetHook();\r\r    /** Destructor\r  */\r    ~TreeSocket();\r\r        /** Generate random string used for challenge-response auth\r     */\r    std::string RandString(unsigned int length);\r\r  /** Construct a password, optionally hashed with the other side's\r       * challenge string\r     */\r    std::string MakePass(const std::string &password, const std::string &challenge);\r\r      /** When an outbound connection finishes connecting, we receive\r         * this event, and must send our SERVER string to the other\r     * side. If the other side is happy, as outlined in the server\r  * to server docs on the inspircd.org site, the other side\r      * will then send back its own server string.\r   */\r    virtual bool OnConnected();\r\r   /** Handle socket error event\r   */\r    virtual void OnError(InspSocketError e);\r\r      /** Sends an error to the remote server, and displays it locally to show\r        * that it was sent.\r    */\r    void SendError(const std::string &errormessage);\r\r      /** Handle socket disconnect event\r      */\r    virtual int OnDisconnect();\r\r   /** Recursively send the server tree with distances as hops.\r    * This is used during network burst to inform the other server\r         * (and any of ITS servers too) of what servers we know about.\r  * If at any point any of these servers already exist on the other\r      * end, our connection may be terminated. The hopcounts given\r   * by this function are relative, this doesn't matter so long as\r        * they are all >1, as all the remote servers re-calculate them\r         * to be relative too, with themselves as hop 0.\r        */\r    void SendServers(TreeServer* Current, TreeServer* s, int hops);\r\r       /** Returns my capabilities as a string\r         */\r    std::string MyCapabilities();\r\r /** Send my capabilities to the remote side\r     */\r    void SendCapabilities();\r\r      /* Check a comma seperated list for an item */\r bool HasItem(const std::string &list, const std::string &item);\r\r       /* Isolate and return the elements that are different between two comma seperated lists */\r     std::string ListDifference(const std::string &one, const std::string &two);\r\r   bool Capab(const std::deque<std::string> &params);\r\r    /** This function forces this server to quit, removing this server\r      * and any users on it (and servers and users below that, etc etc).\r     * It's very slow and pretty clunky, but luckily unless your network\r    * is having a REAL bad hair day, this function shouldnt be called\r      * too many times a month ;-)\r   */\r    void SquitServer(std::string &from, TreeServer* Current);\r\r     /** This is a wrapper function for SquitServer above, which\r     * does some validation first and passes on the SQUIT to all\r    * other remaining servers.\r     */\r    void Squit(TreeServer* Current, const std::string &reason);\r\r   /** FMODE command - server mode with timestamp checks */\r       bool ForceMode(const std::string &source, std::deque<std::string> &params);\r\r   /** FTOPIC command */\r  bool ForceTopic(const std::string &source, std::deque<std::string> &params);\r\r  /** FJOIN, similar to TS6 SJOIN, but not quite. */\r     bool ForceJoin(const std::string &source, std::deque<std::string> &params);\r\r   /** NICK command */\r    bool IntroduceClient(const std::string &source, std::deque<std::string> &params);\r\r     /** Send one or more FJOINs for a channel of users.\r     * If the length of a single line is more than 480-NICKMAX\r      * in length, it is split over multiple lines.\r  */\r    void SendFJoins(TreeServer* Current, chanrec* c);\r\r     /** Send G, Q, Z and E lines */\r        void SendXLines(TreeServer* Current);\r\r /** Send channel modes and topics */\r   void SendChannelModes(TreeServer* Current);\r\r   /** send all users and their oper state/modes */\r       void SendUsers(TreeServer* Current);\r\r  /** This function is called when we want to send a netburst to a local\r  * server. There is a set order we must do this, because for example\r    * users require their servers to exist, and channels require their\r     * users to exist. You get the idea.\r    */\r    void DoBurst(TreeServer* s);\r\r  /** This function is called when we receive data from a remote\r  * server. We buffer the data in a std::string (it doesnt stay\r  * there for long), reading using InspSocket::Read() which can\r  * read up to 16 kilobytes in one operation.\r    *\r      * IF THIS FUNCTION RETURNS FALSE, THE CORE CLOSES AND DELETES\r  * THE SOCKET OBJECT FOR US.\r    */\r    virtual bool OnDataReady();\r\r   /** Send one or more complete lines down the socket\r     */\r    int WriteLine(std::string line);\r\r      /** Handle ERROR command */\r    bool Error(std::deque<std::string> &params);\r\r  /** remote MOTD. leet, huh? */\r bool Motd(const std::string &prefix, std::deque<std::string> &params);\r\r        /** remote ADMIN. leet, huh? */\r        bool Admin(const std::string &prefix, std::deque<std::string> &params);\r\r       /** Remote MODULES */\r  bool Modules(const std::string &prefix, std::deque<std::string> &params);\r\r     bool Stats(const std::string &prefix, std::deque<std::string> &params);\r\r       /** Because the core won't let users or even SERVERS set +o,\r    * we use the OPERTYPE command to do this.\r      */\r    bool OperType(const std::string &prefix, std::deque<std::string> &params);\r\r    /** Because Andy insists that services-compatible servers must\r  * implement SVSNICK and SVSJOIN, that's exactly what we do :p\r  */\r    bool ForceNick(const std::string &prefix, std::deque<std::string> &params);\r\r   bool OperQuit(const std::string &prefix, std::deque<std::string> &params);\r\r    /** SVSJOIN\r     */\r    bool ServiceJoin(const std::string &prefix, std::deque<std::string> &params);\r\r /** REHASH\r      */\r    bool RemoteRehash(const std::string &prefix, std::deque<std::string> &params);\r\r        /** KILL\r        */\r    bool RemoteKill(const std::string &prefix, std::deque<std::string> &params);\r\r  /** PONG\r        */\r    bool LocalPong(const std::string &prefix, std::deque<std::string> &params);\r\r   /** METADATA\r    */\r    bool MetaData(const std::string &prefix, std::deque<std::string> &params);\r\r    /** VERSION\r     */\r    bool ServerVersion(const std::string &prefix, std::deque<std::string> &params);\r\r       /** CHGHOST\r     */\r    bool ChangeHost(const std::string &prefix, std::deque<std::string> &params);\r\r  /** ADDLINE\r     */\r    bool AddLine(const std::string &prefix, std::deque<std::string> &params);\r\r     /** CHGNAME\r     */\r    bool ChangeName(const std::string &prefix, std::deque<std::string> &params);\r\r  /** WHOIS\r       */\r    bool Whois(const std::string &prefix, std::deque<std::string> &params);\r\r       /** PUSH\r        */\r    bool Push(const std::string &prefix, std::deque<std::string> &params);\r\r        /** SETTIME\r     */\r    bool HandleSetTime(const std::string &prefix, std::deque<std::string> &params);\r\r       /** TIME\r        */\r    bool Time(const std::string &prefix, std::deque<std::string> &params);\r\r        /** PING\r        */\r    bool LocalPing(const std::string &prefix, std::deque<std::string> &params);\r\r   /** Remove all modes from a channel, including statusmodes (+qaovh etc), simplemodes, parameter modes.\r  * This does not update the timestamp of the target channel, this must be done seperately.\r      */\r    bool RemoveStatus(const std::string &prefix, std::deque<std::string> &params);\r\r        /** <- (remote) <- SERVER\r       */\r    bool RemoteServer(const std::string &prefix, std::deque<std::string> &params);\r\r        /** (local) -> SERVER\r   */\r    bool Outbound_Reply_Server(std::deque<std::string> &params);\r\r  /** (local) <- SERVER\r   */\r    bool Inbound_Server(std::deque<std::string> &params);\r\r /** Handle netsplit\r     */\r    void Split(const std::string &line, std::deque<std::string> &n);\r\r      /** Process complete line from buffer\r   */\r    bool ProcessLine(std::string &line);\r\r  /** Get this server's name\r      */\r    virtual std::string GetName();\r\r        /** Handle socket timeout from connect()\r        */\r    virtual void OnTimeout();\r\r     /** Handle socket close event\r   */\r    virtual void OnClose();\r\r       /** Handle incoming connection event\r    */\r    virtual int OnIncomingConnection(int newsock, char* ip);\r};\r\r/* Used to validate the value lengths of multiple parameters for a command */\rstruct cmd_validation\r{\r     const char* item;\r      size_t param;\r  size_t length;\r};\r\r/* Used to validate the length values in CAPAB CAPABILITIES */\rstruct cap_validation\r{\r      const char* reason;\r    const char* key;\r       size_t size;\r};\r\r#endif\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __TREESOCKET_H__
+#define __TREESOCKET_H__
+
+#include "configreader.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+#include "commands/cmd_whois.h"
+#include "commands/cmd_stats.h"
+#include "socket.h"
+#include "inspircd.h"
+#include "wildcard.h"
+#include "xline.h"
+#include "transport.h"
+
+#include "m_spanningtree/utils.h"
+
+/*
+ * The server list in InspIRCd is maintained as two structures
+ * which hold the data in different ways. Most of the time, we
+ * want to very quicky obtain three pieces of information:
+ *
+ * (1) The information on a server
+ * (2) The information on the server we must send data through
+ *     to actually REACH the server we're after
+ * (3) Potentially, the child/parent objects of this server
+ *
+ * The InspIRCd spanning protocol provides easy access to these
+ * by storing the data firstly in a recursive structure, where
+ * each item references its parent item, and a dynamic list
+ * of child items, and another structure which stores the items
+ * hashed, linearly. This means that if we want to find a server
+ * by name quickly, we can look it up in the hash, avoiding
+ * any O(n) lookups. If however, during a split or sync, we want
+ * to apply an operation to a server, and any of its child objects
+ * we can resort to recursion to walk the tree structure.
+ * Any socket can have one of five states at any one time.
+ * The LISTENER state indicates a socket which is listening
+ * for connections. It cannot receive data itself, only incoming
+ * sockets.
+ * The CONNECTING state indicates an outbound socket which is
+ * waiting to be writeable.
+ * The WAIT_AUTH_1 state indicates the socket is outbound and
+ * has successfully connected, but has not yet sent and received
+ * SERVER strings.
+ * The WAIT_AUTH_2 state indicates that the socket is inbound
+ * (allocated by a LISTENER) but has not yet sent and received
+ * SERVER strings.
+ * The CONNECTED state represents a fully authorized, fully
+ * connected server.
+ */
+enum ServerState { LISTENER, CONNECTING, WAIT_AUTH_1, WAIT_AUTH_2, CONNECTED };
+
+/** Every SERVER connection inbound or outbound is represented by
+ * an object of type TreeSocket.
+ * TreeSockets, being inherited from InspSocket, can be tied into
+ * the core socket engine, and we cn therefore receive activity events
+ * for them, just like activex objects on speed. (yes really, that
+ * is a technical term!) Each of these which relates to a locally
+ * connected server is assocated with it, by hooking it onto a
+ * TreeSocket class using its constructor. In this way, we can
+ * maintain a list of servers, some of which are directly connected,
+ * some of which are not.
+ */
+class TreeSocket : public InspSocket
+{
+       SpanningTreeUtilities* Utils;           /* Utility class */
+       std::string myhost;                     /* Canonical hostname */
+       std::string in_buffer;                  /* Input buffer */
+       ServerState LinkState;                  /* Link state */
+       std::string InboundServerName;          /* Server name sent to us by other side */
+       std::string InboundDescription;         /* Server description (GECOS) sent to us by the other side */
+       int num_lost_users;                     /* Users lost in split */
+       int num_lost_servers;                   /* Servers lost in split */
+       time_t NextPing;                        /* Time when we are due to ping this server */
+       bool LastPingWasGood;                   /* Responded to last ping we sent? */
+       bool bursting;                          /* True if not finished bursting yet */
+       unsigned int keylength;                 /* Is this still used? */
+       std::string ModuleList;                 /* Module list of other server from CAPAB */
+       std::map<std::string,std::string> CapKeys;      /* CAPAB keys from other server */
+       Module* Hook;                           /* I/O hooking module that we're attached to for this socket */
+       std::string ourchallenge;               /* Challenge sent for challenge/response */
+       std::string theirchallenge;             /* Challenge recv for challenge/response */
+       std::string OutboundPass;               /* Outbound password */
+       bool sentcapab;                         /* Have sent CAPAB already */
+ public:
+
+       /** Because most of the I/O gubbins are encapsulated within
+        * InspSocket, we just call the superclass constructor for
+        * most of the action, and append a few of our own values
+        * to it.
+        */
+       TreeSocket(SpanningTreeUtilities* Util, InspIRCd* SI, std::string host, int port, bool listening, unsigned long maxtime, Module* HookMod = NULL);
+
+       /** Because most of the I/O gubbins are encapsulated within
+        * InspSocket, we just call the superclass constructor for
+        * most of the action, and append a few of our own values
+        * to it.
+        */
+       TreeSocket(SpanningTreeUtilities* Util, InspIRCd* SI, std::string host, int port, bool listening, unsigned long maxtime, const std::string &ServerName, const std::string &bindto, Module* HookMod = NULL);
+
+       /** When a listening socket gives us a new file descriptor,
+        * we must associate it with a socket without creating a new
+        * connection. This constructor is used for this purpose.
+        */
+       TreeSocket(SpanningTreeUtilities* Util, InspIRCd* SI, int newfd, char* ip, Module* HookMod = NULL);
+
+       /** Get link state
+        */
+       ServerState GetLinkState();
+
+       /** Get challenge set in our CAPAB for challenge/response
+        */
+       const std::string& GetOurChallenge();
+
+       /** Get challenge set in our CAPAB for challenge/response
+        */
+       void SetOurChallenge(const std::string &c);
+
+       /** Get challenge set in their CAPAB for challenge/response
+        */
+       const std::string& GetTheirChallenge();
+
+       /** Get challenge set in their CAPAB for challenge/response
+        */
+       void SetTheirChallenge(const std::string &c);
+
+       /** Compare two passwords based on authentication scheme
+        */
+       bool ComparePass(const std::string &ours, const std::string &theirs);
+
+       /** Return the module which we are hooking to for I/O encapsulation
+        */
+       Module* GetHook();
+
+       /** Destructor
+        */
+       ~TreeSocket();
+
+       /** Generate random string used for challenge-response auth
+        */
+       std::string RandString(unsigned int length);
+
+       /** Construct a password, optionally hashed with the other side's
+        * challenge string
+        */
+       std::string MakePass(const std::string &password, const std::string &challenge);
+
+       /** When an outbound connection finishes connecting, we receive
+        * this event, and must send our SERVER string to the other
+        * side. If the other side is happy, as outlined in the server
+        * to server docs on the inspircd.org site, the other side
+        * will then send back its own server string.
+        */
+       virtual bool OnConnected();
+
+       /** Handle socket error event
+        */
+       virtual void OnError(InspSocketError e);
+
+       /** Sends an error to the remote server, and displays it locally to show
+        * that it was sent.
+        */
+       void SendError(const std::string &errormessage);
+
+       /** Handle socket disconnect event
+        */
+       virtual int OnDisconnect();
+
+       /** Recursively send the server tree with distances as hops.
+        * This is used during network burst to inform the other server
+        * (and any of ITS servers too) of what servers we know about.
+        * If at any point any of these servers already exist on the other
+        * end, our connection may be terminated. The hopcounts given
+        * by this function are relative, this doesn't matter so long as
+        * they are all >1, as all the remote servers re-calculate them
+        * to be relative too, with themselves as hop 0.
+        */
+       void SendServers(TreeServer* Current, TreeServer* s, int hops);
+
+       /** Returns my capabilities as a string
+        */
+       std::string MyCapabilities();
+
+       /** Send my capabilities to the remote side
+        */
+       void SendCapabilities();
+
+       /* Check a comma seperated list for an item */
+       bool HasItem(const std::string &list, const std::string &item);
+
+       /* Isolate and return the elements that are different between two comma seperated lists */
+       std::string ListDifference(const std::string &one, const std::string &two);
+
+       bool Capab(const std::deque<std::string> &params);
+
+       /** This function forces this server to quit, removing this server
+        * and any users on it (and servers and users below that, etc etc).
+        * It's very slow and pretty clunky, but luckily unless your network
+        * is having a REAL bad hair day, this function shouldnt be called
+        * too many times a month ;-)
+        */
+       void SquitServer(std::string &from, TreeServer* Current);
+
+       /** This is a wrapper function for SquitServer above, which
+        * does some validation first and passes on the SQUIT to all
+        * other remaining servers.
+        */
+       void Squit(TreeServer* Current, const std::string &reason);
+
+       /** FMODE command - server mode with timestamp checks */
+       bool ForceMode(const std::string &source, std::deque<std::string> &params);
+
+       /** FTOPIC command */
+       bool ForceTopic(const std::string &source, std::deque<std::string> &params);
+
+       /** FJOIN, similar to TS6 SJOIN, but not quite. */
+       bool ForceJoin(const std::string &source, std::deque<std::string> &params);
+
+       /** NICK command */
+       bool IntroduceClient(const std::string &source, std::deque<std::string> &params);
+
+       /** Send one or more FJOINs for a channel of users.
+        * If the length of a single line is more than 480-NICKMAX
+        * in length, it is split over multiple lines.
+        */
+       void SendFJoins(TreeServer* Current, chanrec* c);
+
+       /** Send G, Q, Z and E lines */
+       void SendXLines(TreeServer* Current);
+
+       /** Send channel modes and topics */
+       void SendChannelModes(TreeServer* Current);
+
+       /** send all users and their oper state/modes */
+       void SendUsers(TreeServer* Current);
+
+       /** This function is called when we want to send a netburst to a local
+        * server. There is a set order we must do this, because for example
+        * users require their servers to exist, and channels require their
+        * users to exist. You get the idea.
+        */
+       void DoBurst(TreeServer* s);
+
+       /** This function is called when we receive data from a remote
+        * server. We buffer the data in a std::string (it doesnt stay
+        * there for long), reading using InspSocket::Read() which can
+        * read up to 16 kilobytes in one operation.
+        *
+        * IF THIS FUNCTION RETURNS FALSE, THE CORE CLOSES AND DELETES
+        * THE SOCKET OBJECT FOR US.
+        */
+       virtual bool OnDataReady();
+
+       /** Send one or more complete lines down the socket
+        */
+       int WriteLine(std::string line);
+
+       /** Handle ERROR command */
+       bool Error(std::deque<std::string> &params);
+
+       /** remote MOTD. leet, huh? */
+       bool Motd(const std::string &prefix, std::deque<std::string> &params);
+
+       /** remote ADMIN. leet, huh? */
+       bool Admin(const std::string &prefix, std::deque<std::string> &params);
+
+       /** Remote MODULES */
+       bool Modules(const std::string &prefix, std::deque<std::string> &params);
+
+       bool Stats(const std::string &prefix, std::deque<std::string> &params);
+
+       /** Because the core won't let users or even SERVERS set +o,
+        * we use the OPERTYPE command to do this.
+        */
+       bool OperType(const std::string &prefix, std::deque<std::string> &params);
+
+       /** Because Andy insists that services-compatible servers must
+        * implement SVSNICK and SVSJOIN, that's exactly what we do :p
+        */
+       bool ForceNick(const std::string &prefix, std::deque<std::string> &params);
+
+       bool OperQuit(const std::string &prefix, std::deque<std::string> &params);
+
+       /** SVSJOIN
+        */
+       bool ServiceJoin(const std::string &prefix, std::deque<std::string> &params);
+
+       /** REHASH
+        */
+       bool RemoteRehash(const std::string &prefix, std::deque<std::string> &params);
+
+       /** KILL
+        */
+       bool RemoteKill(const std::string &prefix, std::deque<std::string> &params);
+
+       /** PONG
+        */
+       bool LocalPong(const std::string &prefix, std::deque<std::string> &params);
+
+       /** METADATA
+        */
+       bool MetaData(const std::string &prefix, std::deque<std::string> &params);
+
+       /** VERSION
+        */
+       bool ServerVersion(const std::string &prefix, std::deque<std::string> &params);
+
+       /** CHGHOST
+        */
+       bool ChangeHost(const std::string &prefix, std::deque<std::string> &params);
+
+       /** ADDLINE
+        */
+       bool AddLine(const std::string &prefix, std::deque<std::string> &params);
+
+       /** CHGNAME
+        */
+       bool ChangeName(const std::string &prefix, std::deque<std::string> &params);
+
+       /** WHOIS
+        */
+       bool Whois(const std::string &prefix, std::deque<std::string> &params);
+
+       /** PUSH
+        */
+       bool Push(const std::string &prefix, std::deque<std::string> &params);
+
+       /** SETTIME
+        */
+       bool HandleSetTime(const std::string &prefix, std::deque<std::string> &params);
+
+       /** TIME
+        */
+       bool Time(const std::string &prefix, std::deque<std::string> &params);
+
+       /** PING
+        */
+       bool LocalPing(const std::string &prefix, std::deque<std::string> &params);
+
+       /** Remove all modes from a channel, including statusmodes (+qaovh etc), simplemodes, parameter modes.
+        * This does not update the timestamp of the target channel, this must be done seperately.
+        */
+       bool RemoveStatus(const std::string &prefix, std::deque<std::string> &params);
+
+       /** <- (remote) <- SERVER
+        */
+       bool RemoteServer(const std::string &prefix, std::deque<std::string> &params);
+
+       /** (local) -> SERVER
+        */
+       bool Outbound_Reply_Server(std::deque<std::string> &params);
+
+       /** (local) <- SERVER
+        */
+       bool Inbound_Server(std::deque<std::string> &params);
+
+       /** Handle netsplit
+        */
+       void Split(const std::string &line, std::deque<std::string> &n);
+
+       /** Process complete line from buffer
+        */
+       bool ProcessLine(std::string &line);
+
+       /** Get this server's name
+        */
+       virtual std::string GetName();
+
+       /** Handle socket timeout from connect()
+        */
+       virtual void OnTimeout();
+
+       /** Handle socket close event
+        */
+       virtual void OnClose();
+
+       /** Handle incoming connection event
+        */
+       virtual int OnIncomingConnection(int newsock, char* ip);
+};
+
+/* Used to validate the value lengths of multiple parameters for a command */
+struct cmd_validation
+{
+       const char* item;
+       size_t param;
+       size_t length;
+};
+
+/* Used to validate the length values in CAPAB CAPABILITIES */
+struct cap_validation
+{
+       const char* reason;
+       const char* key;
+       size_t size;
+};
+
+#endif
+
index ad2588cab7fa5903db9d2086f5d33c9024cd373a..a907bb440464872312e209c8a1979ecf5599790b 100644 (file)
@@ -1 +1,1273 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "configreader.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r#include "commands/cmd_whois.h"\r#include "commands/cmd_stats.h"\r#include "socket.h"\r#include "wildcard.h"\r#include "xline.h"\r#include "transport.h"\r#include "m_hash.h"\r#include "socketengine.h"\r\r#include "m_spanningtree/main.h"\r#include "m_spanningtree/utils.h"\r#include "m_spanningtree/treeserver.h"\r#include "m_spanningtree/link.h"\r#include "m_spanningtree/treesocket.h"\r#include "m_spanningtree/resolvers.h"\r#include "m_spanningtree/handshaketimer.h"\r\r/* $ModDep: m_spanningtree/timesynctimer.h m_spanningtree/resolvers.h m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/link.h m_spanningtree/treesocket.h m_hash.h */\r\r\r/** Because most of the I/O gubbins are encapsulated within\r * InspSocket, we just call the superclass constructor for\r * most of the action, and append a few of our own values\r * to it.\r */\rTreeSocket::TreeSocket(SpanningTreeUtilities* Util, InspIRCd* SI, std::string host, int port, bool listening, unsigned long maxtime, Module* HookMod)\r  : InspSocket(SI, host, port, listening, maxtime), Utils(Util), Hook(HookMod)\r{\r myhost = host;\r this->LinkState = LISTENER;\r    theirchallenge.clear();\r        ourchallenge.clear();\r  if (listening && Hook)\r         InspSocketHookRequest(this, (Module*)Utils->Creator, Hook).Send();\r}\r\rTreeSocket::TreeSocket(SpanningTreeUtilities* Util, InspIRCd* SI, std::string host, int port, bool listening, unsigned long maxtime, const std::string &ServerName, const std::string &bindto, Module* HookMod)\r  : InspSocket(SI, host, port, listening, maxtime, bindto), Utils(Util), Hook(HookMod)\r{\r myhost = ServerName;\r   theirchallenge.clear();\r        ourchallenge.clear();\r  this->LinkState = CONNECTING;\r  if (Hook)\r              InspSocketHookRequest(this, (Module*)Utils->Creator, Hook).Send();\r}\r\r/** When a listening socket gives us a new file descriptor,\r * we must associate it with a socket without creating a new\r * connection. This constructor is used for this purpose.\r */\rTreeSocket::TreeSocket(SpanningTreeUtilities* Util, InspIRCd* SI, int newfd, char* ip, Module* HookMod)\r   : InspSocket(SI, newfd, ip), Utils(Util), Hook(HookMod)\r{\r      this->LinkState = WAIT_AUTH_1;\r theirchallenge.clear();\r        ourchallenge.clear();\r  sentcapab = false;\r     /* If we have a transport module hooked to the parent, hook the same module to this\r     * socket, and set a timer waiting for handshake before we send CAPAB etc.\r      */\r    if (Hook)\r              InspSocketHookRequest(this, (Module*)Utils->Creator, Hook).Send();\r\r    Instance->Timers->AddTimer(new HandshakeTimer(Instance, this, &(Utils->LinkBlocks[0]), this->Utils, 1));\r}\r\rServerState TreeSocket::GetLinkState()\r{\r   return this->LinkState;\r}\r\rModule* TreeSocket::GetHook()\r{\r     return this->Hook;\r}\r\rTreeSocket::~TreeSocket()\r{\r      if (Hook)\r              InspSocketUnhookRequest(this, (Module*)Utils->Creator, Hook).Send();\r\r  Utils->DelBurstingServer(this);\r}\r\rconst std::string& TreeSocket::GetOurChallenge()\r{\r  return this->ourchallenge;\r}\r\rvoid TreeSocket::SetOurChallenge(const std::string &c)\r{\r this->ourchallenge = c;\r}\r\rconst std::string& TreeSocket::GetTheirChallenge()\r{\r        return this->theirchallenge;\r}\r\rvoid TreeSocket::SetTheirChallenge(const std::string &c)\r{\r     this->theirchallenge = c;\r}\r\rstd::string TreeSocket::MakePass(const std::string &password, const std::string &challenge)\r{\r     /* This is a simple (maybe a bit hacky?) HMAC algorithm, thanks to jilles for\r   * suggesting the use of HMAC to secure the password against various attacks.\r   *\r      * Note: If m_sha256.so is not loaded, we MUST fall back to plaintext with no\r   *       HMAC challenge/response.\r       */\r    Module* sha256 = Instance->FindModule("m_sha256.so");\r  if (Utils->ChallengeResponse && sha256 && !challenge.empty())\r  {\r              /* XXX: This is how HMAC is supposed to be done:\r                *\r              * sha256( (pass xor 0x5c) + sha256((pass xor 0x36) + m) )\r              *\r              * Note that we are encoding the hex hash, not the binary\r               * output of the hash which is slightly different to standard.\r          *\r              * Don't ask me why its always 0x5c and 0x36... it just is.\r             */\r            std::string hmac1, hmac2;\r\r             for (size_t n = 0; n < password.length(); n++)\r         {\r                      hmac1 += static_cast<char>(password[n] ^ 0x5C);\r                        hmac2 += static_cast<char>(password[n] ^ 0x36);\r                }\r\r             hmac2 += challenge;\r            HashResetRequest(Utils->Creator, sha256).Send();\r               hmac2 = HashSumRequest(Utils->Creator, sha256, hmac2).Send();\r\r         HashResetRequest(Utils->Creator, sha256).Send();\r               std::string hmac = hmac1 + hmac2;\r              hmac = HashSumRequest(Utils->Creator, sha256, hmac).Send();\r\r           return "HMAC-SHA256:"+ hmac;\r   }\r      else if (!challenge.empty() && !sha256)\r                Instance->Log(DEFAULT,"Not authenticating to server using SHA256/HMAC because we don't have m_sha256 loaded!");\r\r       return password;\r}\r\r/** When an outbound connection finishes connecting, we receive\r * this event, and must send our SERVER string to the other\r * side. If the other side is happy, as outlined in the server\r * to server docs on the inspircd.org site, the other side\r * will then send back its own server string.\r */\rbool TreeSocket::OnConnected()\r{\r   if (this->LinkState == CONNECTING)\r     {\r              /* we do not need to change state here. */\r             for (std::vector<Link>::iterator x = Utils->LinkBlocks.begin(); x < Utils->LinkBlocks.end(); x++)\r              {\r                      if (x->Name == this->myhost)\r                   {\r                              this->Instance->SNO->WriteToSnoMask('l',"Connection to \2"+myhost+"\2["+(x->HiddenFromStats ? "<hidden>" : this->GetIP())+"] started.");\r                               if (Hook)\r                              {\r                                      InspSocketHookRequest(this, (Module*)Utils->Creator, Hook).Send();\r                                     this->Instance->SNO->WriteToSnoMask('l',"Connection to \2"+myhost+"\2["+(x->HiddenFromStats ? "<hidden>" : this->GetIP())+"] using transport \2"+x->Hook+"\2");\r                                }\r                              this->OutboundPass = x->SendPass;\r                              sentcapab = false;\r\r                            /* found who we're supposed to be connecting to, send the neccessary gubbins. */\r                               if (this->GetHook())\r                                   Instance->Timers->AddTimer(new HandshakeTimer(Instance, this, &(*x), this->Utils, 1));\r                         else\r                                   this->SendCapabilities();\r\r                             return true;\r                   }\r              }\r      }\r      /* There is a (remote) chance that between the /CONNECT and the connection\r      * being accepted, some muppet has removed the <link> block and rehashed.\r       * If that happens the connection hangs here until it's closed. Unlikely\r        * and rather harmless.\r         */\r    this->Instance->SNO->WriteToSnoMask('l',"Connection to \2"+myhost+"\2 lost link tag(!)");\r      return true;\r}\r\rvoid TreeSocket::OnError(InspSocketError e)\r{\r  Link* MyLink;\r\r switch (e)\r     {\r              case I_ERR_CONNECT:\r                    this->Instance->SNO->WriteToSnoMask('l',"Connection failed: Connection to \002"+myhost+"\002 refused");\r                        MyLink = Utils->FindLink(myhost);\r                      if (MyLink)\r                            Utils->DoFailOver(MyLink);\r             break;\r         case I_ERR_SOCKET:\r                     this->Instance->SNO->WriteToSnoMask('l',"Connection failed: Could not create socket");\r         break;\r         case I_ERR_BIND:\r                       this->Instance->SNO->WriteToSnoMask('l',"Connection failed: Error binding socket to address or port");\r         break;\r         case I_ERR_WRITE:\r                      this->Instance->SNO->WriteToSnoMask('l',"Connection failed: I/O error on connection");\r         break;\r         case I_ERR_NOMOREFDS:\r                  this->Instance->SNO->WriteToSnoMask('l',"Connection failed: Operating system is out of file descriptors!");\r            break;\r         default:\r                       if ((errno) && (errno != EINPROGRESS) && (errno != EAGAIN))\r                    {\r                              std::string errstr = strerror(errno);\r                          this->Instance->SNO->WriteToSnoMask('l',"Connection to \002"+myhost+"\002 failed with OS error: " + errstr);\r                   }\r              break;\r }\r}\r\rint TreeSocket::OnDisconnect()\r{\r  /* For the same reason as above, we don't\r       * handle OnDisconnect()\r        */\r    return true;\r}\r\r/** Recursively send the server tree with distances as hops.\r * This is used during network burst to inform the other server\r * (and any of ITS servers too) of what servers we know about.\r * If at any point any of these servers already exist on the other\r * end, our connection may be terminated. The hopcounts given\r * by this function are relative, this doesn't matter so long as\r * they are all >1, as all the remote servers re-calculate them\r * to be relative too, with themselves as hop 0.\r */\rvoid TreeSocket::SendServers(TreeServer* Current, TreeServer* s, int hops)\r{\r        char command[1024];\r    for (unsigned int q = 0; q < Current->ChildCount(); q++)\r       {\r              TreeServer* recursive_server = Current->GetChild(q);\r           if (recursive_server != s)\r             {\r                      snprintf(command,1024,":%s SERVER %s * %d :%s",Current->GetName().c_str(),recursive_server->GetName().c_str(),hops,recursive_server->GetDesc().c_str());\r                       this->WriteLine(command);\r                      this->WriteLine(":"+recursive_server->GetName()+" VERSION :"+recursive_server->GetVersion());\r                  /* down to next level */\r                       this->SendServers(recursive_server, s, hops+1);\r                }\r      }\r}\r\rstd::string TreeSocket::MyCapabilities()\r{\r        std::vector<std::string> modlist;\r      std::string capabilities;\r      for (int i = 0; i <= this->Instance->GetModuleCount(); i++)\r    {\r              if (this->Instance->modules[i]->GetVersion().Flags & VF_COMMON)\r                        modlist.push_back(this->Instance->Config->module_names[i]);\r    }\r      sort(modlist.begin(),modlist.end());\r   for (unsigned int i = 0; i < modlist.size(); i++)\r      {\r              if (i)\r                 capabilities = capabilities + ",";\r             capabilities = capabilities + modlist[i];\r      }\r      return capabilities;\r}\r\rstd::string TreeSocket::RandString(unsigned int length)\r{\r      char* randombuf = new char[length+1];\r  std::string out;\r#ifdef WINDOWS\r        int fd = -1;\r#else\r     int fd = open("/dev/urandom", O_RDONLY, 0);\r#endif\r\r    if (fd >= 0)\r   {\r#ifndef WINDOWS\r              read(fd, randombuf, length);\r           close(fd);\r#endif\r      }\r      else\r   {\r              for (unsigned int i = 0; i < length; i++)\r                      randombuf[i] = rand();\r }\r\r     for (unsigned int i = 0; i < length; i++)\r      {\r              char randchar = static_cast<char>((randombuf[i] & 0x7F) | 0x21);\r               out += (randchar == '=' ? '_' : randchar);\r     }\r\r     delete[] randombuf;\r    return out;\r}\r\rvoid TreeSocket::SendCapabilities()\r{\r   if (sentcapab)\r         return;\r\r       sentcapab = true;\r      irc::commasepstream modulelist(MyCapabilities());\r      this->WriteLine("CAPAB START");\r\r       /* Send module names, split at 509 length */\r   std::string item = "*";\r        std::string line = "CAPAB MODULES ";\r   while ((item = modulelist.GetToken()) != "")\r   {\r              if (line.length() + item.length() + 1 > 509)\r           {\r                      this->WriteLine(line);\r                 line = "CAPAB MODULES ";\r               }\r\r             if (line != "CAPAB MODULES ")\r                  line.append(",");\r\r             line.append(item);\r     }\r      if (line != "CAPAB MODULES ")\r          this->WriteLine(line);\r\r        int ip6 = 0;\r   int ip6support = 0;\r#ifdef IPV6\r        ip6 = 1;\r#endif\r#ifdef SUPPORT_IP6LINKS\r        ip6support = 1;\r#endif\r std::string extra;\r     /* Do we have sha256 available? If so, we send a challenge */\r  if (Utils->ChallengeResponse && (Instance->FindModule("m_sha256.so")))\r {\r              this->SetOurChallenge(RandString(20));\r         extra = " CHALLENGE=" + this->GetOurChallenge();\r       }\r\r     this->WriteLine("CAPAB CAPABILITIES :NICKMAX="+ConvToStr(NICKMAX)+" HALFOP="+ConvToStr(this->Instance->Config->AllowHalfop)+" CHANMAX="+ConvToStr(CHANMAX)+" MAXMODES="+ConvToStr(MAXMODES)+" IDENTMAX="+ConvToStr(IDENTMAX)+" MAXQUIT="+ConvToStr(MAXQUIT)+" MAXTOPIC="+ConvToStr(MAXTOPIC)+" MAXKICK="+ConvToStr(MAXKICK)+" MAXGECOS="+ConvToStr(MAXGECOS)+" MAXAWAY="+ConvToStr(MAXAWAY)+" IP6NATIVE="+ConvToStr(ip6)+" IP6SUPPORT="+ConvToStr(ip6support)+" PROTOCOL="+ConvToStr(ProtocolVersion)+extra+" PREFIX="+Instance->Modes->BuildPrefixes()+" CHANMODES="+Instance->Modes->ChanModes());\r\r  this->WriteLine("CAPAB END");\r}\r\r/* Check a comma seperated list for an item */\rbool TreeSocket::HasItem(const std::string &list, const std::string &item)\r{\r   irc::commasepstream seplist(list);\r     std::string item2 = "*";\r       while ((item2 = seplist.GetToken()) != "")\r     {\r              if (item2 == item)\r                     return true;\r   }\r      return false;\r}\r\r/* Isolate and return the elements that are different between two comma seperated lists */\rstd::string TreeSocket::ListDifference(const std::string &one, const std::string &two)\r{\r   irc::commasepstream list_one(one);\r     std::string item = "*";\r        std::string result;\r    while ((item = list_one.GetToken()) != "")\r     {\r              if (!HasItem(two, item))\r               {\r                      result.append(" ");\r                    result.append(item);\r           }\r      }\r      return result;\r}\r\rvoid TreeSocket::SendError(const std::string &errormessage)\r{\r        /* Display the error locally as well as sending it remotely */\r this->WriteLine("ERROR :"+errormessage);\r       this->Instance->SNO->WriteToSnoMask('l',"Sent \2ERROR\2 to "+this->InboundServerName+": "+errormessage);\r       /* One last attempt to make sure the error reaches its target */\r       this->FlushWriteBuffer();\r}\r\rbool TreeSocket::Capab(const std::deque<std::string> &params)\r{\r   if (params.size() < 1)\r {\r              this->SendError("Invalid number of parameters for CAPAB - Mismatched version");\r                return false;\r  }\r      if (params[0] == "START")\r      {\r              this->ModuleList.clear();\r              this->CapKeys.clear();\r }\r      else if (params[0] == "END")\r   {\r              std::string reason;\r            int ip6support = 0;\r#ifdef SUPPORT_IP6LINKS\r            ip6support = 1;\r#endif\r         /* Compare ModuleList and check CapKeys...\r              * Maybe this could be tidier? -- Brain\r                 */\r            if ((this->ModuleList != this->MyCapabilities()) && (this->ModuleList.length()))\r               {\r                      std::string diff = ListDifference(this->ModuleList, this->MyCapabilities());\r                   if (!diff.length())\r                    {\r                              diff = "your server:" + ListDifference(this->MyCapabilities(), this->ModuleList);\r                      }\r                      else\r                   {\r                              diff = "this server:" + diff;\r                  }\r                      if (diff.length() == 12)\r                               reason = "Module list in CAPAB is not alphabetically ordered, cannot compare lists.";\r                  else\r                           reason = "Modules loaded on these servers are not correctly matched, these modules are not loaded on " + diff;\r         }\r\r             cap_validation valid_capab[] = { \r                      {"Maximum nickname lengths differ or remote nickname length not specified", "NICKMAX", NICKMAX},\r                       {"Maximum ident lengths differ or remote ident length not specified", "IDENTMAX", IDENTMAX},\r                   {"Maximum channel lengths differ or remote channel length not specified", "CHANMAX", CHANMAX},\r                 {"Maximum modes per line differ or remote modes per line not specified", "MAXMODES", MAXMODES},\r                        {"Maximum quit lengths differ or remote quit length not specified", "MAXQUIT", MAXQUIT},\r                       {"Maximum topic lengths differ or remote topic length not specified", "MAXTOPIC", MAXTOPIC},\r                   {"Maximum kick lengths differ or remote kick length not specified", "MAXKICK", MAXKICK},\r                       {"Maximum GECOS (fullname) lengths differ or remote GECOS length not specified", "MAXGECOS", MAXGECOS},\r                        {"Maximum awaymessage lengths differ or remote awaymessage length not specified", "MAXAWAY", MAXAWAY},\r                 {"", "", 0}\r            };\r\r            if (((this->CapKeys.find("IP6SUPPORT") == this->CapKeys.end()) && (ip6support)) || ((this->CapKeys.find("IP6SUPPORT") != this->CapKeys.end()) && (this->CapKeys.find("IP6SUPPORT")->second != ConvToStr(ip6support))))\r                 reason = "We don't both support linking to IPV6 servers";\r              if (((this->CapKeys.find("IP6NATIVE") != this->CapKeys.end()) && (this->CapKeys.find("IP6NATIVE")->second == "1")) && (!ip6support))\r                   reason = "The remote server is IPV6 native, and we don't support linking to IPV6 servers";\r             if (((this->CapKeys.find("PROTOCOL") == this->CapKeys.end()) || ((this->CapKeys.find("PROTOCOL") != this->CapKeys.end()) && (this->CapKeys.find("PROTOCOL")->second != ConvToStr(ProtocolVersion)))))\r          {\r                      if (this->CapKeys.find("PROTOCOL") != this->CapKeys.end())\r                             reason = "Mismatched protocol versions "+this->CapKeys.find("PROTOCOL")->second+" and "+ConvToStr(ProtocolVersion);\r                    else\r                           reason = "Protocol version not specified";\r             }\r\r             if(this->CapKeys.find("PREFIX") != this->CapKeys.end() && this->CapKeys.find("PREFIX")->second != this->Instance->Modes->BuildPrefixes())\r                      reason = "One or more of the prefixes on the remote server are invalid on this server.";\r\r              if (((this->CapKeys.find("HALFOP") == this->CapKeys.end()) && (Instance->Config->AllowHalfop)) || ((this->CapKeys.find("HALFOP") != this->CapKeys.end()) && (this->CapKeys.find("HALFOP")->second != ConvToStr(Instance->Config->AllowHalfop))))\r                       reason = "We don't both have halfop support enabled/disabled identically";\r\r            for (int x = 0; valid_capab[x].size; ++x)\r              {\r                      if (((this->CapKeys.find(valid_capab[x].key) == this->CapKeys.end()) || ((this->CapKeys.find(valid_capab[x].key) != this->CapKeys.end()) &&\r                                             (this->CapKeys.find(valid_capab[x].key)->second != ConvToStr(valid_capab[x].size)))))\r                         reason = valid_capab[x].reason;\r                }\r      \r               /* Challenge response, store their challenge for our password */\r               std::map<std::string,std::string>::iterator n = this->CapKeys.find("CHALLENGE");\r               if (Utils->ChallengeResponse && (n != this->CapKeys.end()) && (Instance->FindModule("m_sha256.so")))\r           {\r                      /* Challenge-response is on now */\r                     this->SetTheirChallenge(n->second);\r                    if (!this->GetTheirChallenge().empty() && (this->LinkState == CONNECTING))\r                     {\r                              this->WriteLine(std::string("SERVER ")+this->Instance->Config->ServerName+" "+this->MakePass(OutboundPass, this->GetTheirChallenge())+" 0 :"+this->Instance->Config->ServerDesc);\r                      }\r              }\r              else\r           {\r                      /* They didnt specify a challenge or we don't have m_sha256.so, we use plaintext */\r                    if (this->LinkState == CONNECTING)\r                             this->WriteLine(std::string("SERVER ")+this->Instance->Config->ServerName+" "+OutboundPass+" 0 :"+this->Instance->Config->ServerDesc);\r         }\r\r             if (reason.length())\r           {\r                      this->SendError("CAPAB negotiation failed: "+reason);\r                  return false;\r          }\r      }\r      else if ((params[0] == "MODULES") && (params.size() == 2))\r     {\r              if (!this->ModuleList.length())\r                {\r                      this->ModuleList.append(params[1]);\r            }\r              else\r           {\r                      this->ModuleList.append(",");\r                  this->ModuleList.append(params[1]);\r            }\r      }\r\r     else if ((params[0] == "CAPABILITIES") && (params.size() == 2))\r        {\r              irc::tokenstream capabs(params[1]);\r            std::string item;\r              bool more = true;\r              while ((more = capabs.GetToken(item)))\r         {\r                      /* Process each key/value pair */\r                      std::string::size_type equals = item.rfind('=');\r                       if (equals != std::string::npos)\r                       {\r                              std::string var = item.substr(0, equals);\r                              std::string value = item.substr(equals+1, item.length());\r                              CapKeys[var] = value;\r                  }\r              }\r      }\r      return true;\r}\r\r/** This function forces this server to quit, removing this server\r * and any users on it (and servers and users below that, etc etc).\r * It's very slow and pretty clunky, but luckily unless your network\r * is having a REAL bad hair day, this function shouldnt be called\r * too many times a month ;-)\r */\rvoid TreeSocket::SquitServer(std::string &from, TreeServer* Current)\r{\r        /* recursively squit the servers attached to 'Current'.\r         * We're going backwards so we don't remove users\r       * while we still need them ;)\r  */\r    for (unsigned int q = 0; q < Current->ChildCount(); q++)\r       {\r              TreeServer* recursive_server = Current->GetChild(q);\r           this->SquitServer(from,recursive_server);\r      }\r      /* Now we've whacked the kids, whack self */\r   num_lost_servers++;\r    num_lost_users += Current->QuitUsers(from);\r}\r\r/** This is a wrapper function for SquitServer above, which\r * does some validation first and passes on the SQUIT to all\r * other remaining servers.\r */\rvoid TreeSocket::Squit(TreeServer* Current, const std::string &reason)\r{\r       if ((Current) && (Current != Utils->TreeRoot))\r {\r              Event rmode((char*)Current->GetName().c_str(), (Module*)Utils->Creator, "lost_server");\r                rmode.Send(Instance);\r\r         std::deque<std::string> params;\r                params.push_back(Current->GetName());\r          params.push_back(":"+reason);\r          Utils->DoOneToAllButSender(Current->GetParent()->GetName(),"SQUIT",params,Current->GetName());\r         if (Current->GetParent() == Utils->TreeRoot)\r           {\r                      this->Instance->SNO->WriteToSnoMask('l',"Server \002"+Current->GetName()+"\002 split: "+reason);\r               }\r              else\r           {\r                      this->Instance->SNO->WriteToSnoMask('l',"Server \002"+Current->GetName()+"\002 split from server \002"+Current->GetParent()->GetName()+"\002 with reason: "+reason);\r           }\r              num_lost_servers = 0;\r          num_lost_users = 0;\r            std::string from = Current->GetParent()->GetName()+" "+Current->GetName();\r             SquitServer(from, Current);\r            Current->Tidy();\r               Current->GetParent()->DelChild(Current);\r               DELETE(Current);\r               this->Instance->SNO->WriteToSnoMask('l',"Netsplit complete, lost \002%d\002 users on \002%d\002 servers.", num_lost_users, num_lost_servers);\r  }\r      else\r           Instance->Log(DEFAULT,"Squit from unknown server");\r}\r\r/** FMODE command - server mode with timestamp checks */\rbool TreeSocket::ForceMode(const std::string &source, std::deque<std::string> &params)\r{\r       /* Chances are this is a 1.0 FMODE without TS */\r       if (params.size() < 3)\r {\r              /* No modes were in the command, probably a channel with no modes set on it */\r         return true;\r   }\r\r     bool smode = false;\r    std::string sourceserv;\r        /* Are we dealing with an FMODE from a user, or from a server? */\r      userrec* who = this->Instance->FindNick(source);\r       if (who)\r       {\r              /* FMODE from a user, set sourceserv to the users server name */\r               sourceserv = who->server;\r      }\r      else\r   {\r              /* FMODE from a server, create a fake user to receive mode feedback */\r         who = new userrec(this->Instance);\r             who->SetFd(FD_MAGIC_NUMBER);\r           smode = true;      /* Setting this flag tells us we should free the userrec later */\r           sourceserv = source;    /* Set sourceserv to the actual source string */\r       }\r      const char* modelist[64];\r      time_t TS = 0;\r int n = 0;\r     memset(&modelist,0,sizeof(modelist));\r  for (unsigned int q = 0; (q < params.size()) && (q < 64); q++)\r {\r              if (q == 1)\r            {\r                      /* The timestamp is in this position.\r                   * We don't want to pass that up to the\r                         * server->client protocol!\r                     */\r                    TS = atoi(params[q].c_str());\r          }\r              else\r           {\r                      /* Everything else is fine to append to the modelist */\r                        modelist[n++] = params[q].c_str();\r             }\r\r     }\r      /* Extract the TS value of the object, either userrec or chanrec */\r    userrec* dst = this->Instance->FindNick(params[0]);\r    chanrec* chan = NULL;\r  time_t ourTS = 0;\r      if (dst)\r       {\r              ourTS = dst->age;\r      }\r      else\r   {\r              chan = this->Instance->FindChan(params[0]);\r            if (chan)\r              {\r                      ourTS = chan->age;\r             }\r              else\r                   /* Oops, channel doesnt exist! */\r                      return true;\r   }\r\r     if (!TS)\r       {\r              Instance->Log(DEFAULT,"*** BUG? *** TS of 0 sent to FMODE. Are some services authors smoking craq, or is it 1970 again?. Dropped.");\r           Instance->SNO->WriteToSnoMask('d', "WARNING: The server %s is sending FMODE with a TS of zero. Total craq. Mode was dropped.", sourceserv.c_str());\r            return true;\r   }\r\r     /* TS is equal or less: Merge the mode changes into ours and pass on.\r   */\r    if (TS <= ourTS)\r       {\r              if ((TS < ourTS) && (!dst))\r                    Instance->Log(DEFAULT,"*** BUG *** Channel TS sent in FMODE to %s is %lu which is not equal to %lu!", params[0].c_str(), TS, ourTS);\r\r          if (smode)\r             {\r                      this->Instance->SendMode(modelist, n, who);\r            }\r              else\r           {\r                      this->Instance->CallCommandHandler("MODE", modelist, n, who);\r          }\r              /* HOT POTATO! PASS IT ON! */\r          Utils->DoOneToAllButSender(source,"FMODE",params,sourceserv);\r  }\r      /* If the TS is greater than ours, we drop the mode and dont pass it anywhere.\r  */\r\r   if (smode)\r             DELETE(who);\r\r  return true;\r}\r\r/** FTOPIC command */\rbool TreeSocket::ForceTopic(const std::string &source, std::deque<std::string> &params)\r{\r        if (params.size() != 4)\r                return true;\r   time_t ts = atoi(params[1].c_str());\r   std::string nsource = source;\r  chanrec* c = this->Instance->FindChan(params[0]);\r      if (c)\r {\r              if ((ts >= c->topicset) || (!*c->topic))\r               {\r                      std::string oldtopic = c->topic;\r                       strlcpy(c->topic,params[3].c_str(),MAXTOPIC);\r                  strlcpy(c->setby,params[2].c_str(),127);\r                       c->topicset = ts;\r                      /* if the topic text is the same as the current topic,\r                  * dont bother to send the TOPIC command out, just silently\r                     * update the set time and set nick.\r                    */\r                    if (oldtopic != params[3])\r                     {\r                              userrec* user = this->Instance->FindNick(source);\r                              if (!user)\r                             {\r                                      c->WriteChannelWithServ(Instance->Config->ServerName, "TOPIC %s :%s", c->name, c->topic);\r                              }\r                              else\r                           {\r                                      c->WriteChannel(user, "TOPIC %s :%s", c->name, c->topic);\r                                      nsource = user->server;\r                                }\r                              /* all done, send it on its way */\r                             params[3] = ":" + params[3];\r                           Utils->DoOneToAllButSender(source,"FTOPIC",params,nsource);\r                    }\r              }\r\r     }\r      return true;\r}\r\r/** FJOIN, similar to TS6 SJOIN, but not quite. */\rbool TreeSocket::ForceJoin(const std::string &source, std::deque<std::string> &params)\r{\r    /* 1.1 FJOIN works as follows:\r  *\r      * Each FJOIN is sent along with a timestamp, and the side with the lowest\r      * timestamp 'wins'. From this point on we will refer to this side as the\r       * winner. The side with the higher timestamp loses, from this point on we\r      * will call this side the loser or losing side. This should be familiar to\r     * anyone who's dealt with dreamforge or TS6 before.\r    *\r      * When two sides of a split heal and this occurs, the following things\r         * will happen:\r         *\r      * If the timestamps are exactly equal, both sides merge their privilages\r       * and users, as in InspIRCd 1.0 and ircd2.8. The channels have not been\r        * re-created during a split, this is safe to do.\r       *\r      * If the timestamps are NOT equal, the losing side removes all of its\r  * modes from the channel, before introducing new users into the channel\r        * which are listed in the FJOIN command's parameters. The losing side then\r     * LOWERS its timestamp value of the channel to match that of the winning\r       * side, and the modes of the users of the winning side are merged in with\r      * the losing side.\r     *\r      * The winning side on the other hand will ignore all user modes from the\r       * losing side, so only its own modes get applied. Life is simple for those\r     * who succeed at internets. :-)\r        *\r      * NOTE: Unlike TS6 and dreamforge and other protocols which have SJOIN,\r        * FJOIN does not contain the simple-modes such as +iklmnsp. Why not,\r   * you ask? Well, quite simply because we don't need to. They'll be sent\r        * after the FJOIN by FMODE, and FMODE is timestamped, so in the event\r  * the losing side sends any modes for the channel which shouldnt win,\r  * they wont as their timestamp will be too high :-)\r    */\r\r   if (params.size() < 3)\r         return true;\r\r  irc::modestacker modestack(true);                               /* Modes to apply from the users in the user list */\r   userrec* who = NULL;                                            /* User we are currently checking */\r   std::string channel = params[0];                                /* Channel name, as a string */\r        time_t TS = atoi(params[1].c_str());                            /* Timestamp given to us for remote side */\r    irc::tokenstream users(params[2]);                              /* Users from the user list */\r bool apply_other_sides_modes = true;                            /* True if we are accepting the other side's modes */\r  chanrec* chan = this->Instance->FindChan(channel);              /* The channel we're sending joins to */\r       time_t ourTS = chan ? chan->age : Instance->Time(true)+600;     /* The TS of our side of the link */\r   bool created = !chan;                                           /* True if the channel doesnt exist here yet */\r        std::string item;                                               /* One item in the list of nicks */\r\r   params[2] = ":" + params[2];\r   Utils->DoOneToAllButSender(source,"FJOIN",params,source);\r\r        if (!TS)\r    {\r              Instance->Log(DEFAULT,"*** BUG? *** TS of 0 sent to FJOIN. Are some services authors smoking craq, or is it 1970 again?. Dropped.");\r           Instance->SNO->WriteToSnoMask('d', "WARNING: The server %s is sending FJOIN with a TS of zero. Total craq. Command was dropped.", source.c_str());\r             return true;\r   }\r\r     /* If our TS is less than theirs, we dont accept their modes */\r        if (ourTS < TS)\r                apply_other_sides_modes = false;\r\r      /* Our TS greater than theirs, clear all our modes from the channel, accept theirs. */\r if (ourTS > TS)\r        {\r              std::deque<std::string> param_list;\r            if (Utils->AnnounceTSChange && chan)\r                   chan->WriteChannelWithServ(Instance->Config->ServerName, "NOTICE %s :TS for %s changed from %lu to %lu", chan->name, chan->name, ourTS, TS);\r           ourTS = TS;\r            if (!created)\r          {\r                      chan->age = TS;\r                        param_list.push_back(channel);\r                 this->RemoveStatus(Instance->Config->ServerName, param_list);\r          }\r      }\r\r     /* Now, process every 'prefixes,nick' pair */\r  while (users.GetToken(item))\r   {\r              const char* usr = item.c_str();\r                if (usr && *usr)\r               {\r                      const char* permissions = usr;\r                 /* Iterate through all the prefix values, convert them from prefixes to mode letters */\r                        std::string modes;\r                     while ((*permissions) && (*permissions != ','))\r                        {\r                              ModeHandler* mh = Instance->Modes->FindPrefix(*permissions);\r                           if (mh)\r                                        modes = modes + mh->GetModeChar();\r                             else\r                           {\r                                      this->SendError(std::string("Invalid prefix '")+(*permissions)+"' in FJOIN");\r                                  return false;\r                          }\r                              usr++;\r                         permissions++;\r                 }\r                      /* Advance past the comma, to the nick */\r                      usr++;\r                 \r                       /* Check the user actually exists */\r                   who = this->Instance->FindNick(usr);\r                   if (who)\r                       {\r                              /* Check that the user's 'direction' is correct */\r                             TreeServer* route_back_again = Utils->BestRouteTo(who->server);\r                                if ((!route_back_again) || (route_back_again->GetSocket() != this))\r                                    continue;\r\r                             /* Add any permissions this user had to the mode stack */\r                              for (std::string::iterator x = modes.begin(); x != modes.end(); ++x)\r                                   modestack.Push(*x, who->nick);\r\r                                chanrec::JoinUser(this->Instance, who, channel.c_str(), true, "", TS);\r                 }\r                      else\r                   {\r                              Instance->Log(SPARSE,"Warning! Invalid user %s in FJOIN to channel %s IGNORED", usr, channel.c_str());\r                         continue;\r                      }\r              }\r      }\r\r     /* Flush mode stacker if we lost the FJOIN or had equal TS */\r  if (apply_other_sides_modes)\r   {\r              std::deque<std::string> stackresult;\r           const char* mode_junk[MAXMODES+2];\r             userrec* n = new userrec(Instance);\r            n->SetFd(FD_MAGIC_NUMBER);\r             mode_junk[0] = channel.c_str();\r\r               while (modestack.GetStackedLine(stackresult))\r          {\r                      for (size_t j = 0; j < stackresult.size(); j++)\r                        {\r                              mode_junk[j+1] = stackresult[j].c_str();\r                       }\r                      Instance->SendMode(mode_junk, stackresult.size() + 1, n);\r              }\r\r             delete n;\r      }\r\r     return true;\r}\r\r/** NICK command */\rbool TreeSocket::IntroduceClient(const std::string &source, std::deque<std::string> &params)\r{\r     /** Do we have enough parameters:\r       * NICK age nick host dhost ident +modes ip :gecos\r      */\r    if (params.size() != 8)\r        {\r              this->WriteLine(std::string(":")+this->Instance->Config->ServerName+" KILL "+params[1]+" :Invalid client introduction ("+params[1]+"?)");\r              return true;\r   }\r\r     time_t age = ConvToInt(params[0]);\r     const char* tempnick = params[1].c_str();\r\r     cmd_validation valid[] = { {"Nickname", 1, NICKMAX}, {"Hostname", 2, 64}, {"Displayed hostname", 3, 64}, {"Ident", 4, IDENTMAX}, {"GECOS", 7, MAXGECOS}, {"", 0, 0} };\r\r        TreeServer* remoteserver = Utils->FindServer(source);\r  if (!remoteserver)\r     {\r              this->WriteLine(std::string(":")+this->Instance->Config->ServerName+" KILL "+params[1]+" :Invalid client introduction (Unknown server "+source+")");\r           return true;\r   }\r\r     /* Check parameters for validity before introducing the client, discovered by dmb */\r   if (!age)\r      {\r              this->WriteLine(std::string(":")+this->Instance->Config->ServerName+" KILL "+params[1]+" :Invalid client introduction (Invalid TS?)");\r         return true;\r   }\r      for (size_t x = 0; valid[x].length; ++x)\r       {\r              if (params[valid[x].param].length() > valid[x].length)\r         {\r                      this->WriteLine(std::string(":")+this->Instance->Config->ServerName+" KILL "+params[1]+" :Invalid client introduction (" + valid[x].item + " > " + ConvToStr(valid[x].length) + ")");\r                  return true;\r           }\r      }\r\r     /** Our client looks ok, lets introduce it now\r  */\r    Instance->Log(DEBUG,"New remote client %s",tempnick);\r  user_hash::iterator iter = this->Instance->clientlist->find(tempnick);\r\r        if (iter != this->Instance->clientlist->end())\r {\r              /* nick collision */\r           this->WriteLine(std::string(":")+this->Instance->Config->ServerName+" KILL "+tempnick+" :Nickname collision");\r         userrec::QuitUser(this->Instance, iter->second, "Nickname collision");\r         return true;\r   }\r\r     userrec* _new = new userrec(this->Instance);\r   (*(this->Instance->clientlist))[tempnick] = _new;\r      _new->SetFd(FD_MAGIC_NUMBER);\r  strlcpy(_new->nick, tempnick,NICKMAX-1);\r       strlcpy(_new->host, params[2].c_str(),64);\r     strlcpy(_new->dhost, params[3].c_str(),64);\r    _new->server = this->Instance->FindServerNamePtr(source.c_str());\r      strlcpy(_new->ident, params[4].c_str(),IDENTMAX);\r      strlcpy(_new->fullname, params[7].c_str(),MAXGECOS);\r   _new->registered = REG_ALL;\r    _new->signon = age;\r\r   /* we need to remove the + from the modestring, so we can do our stuff */\r      std::string::size_type pos_after_plus = params[5].find_first_not_of('+');\r      if (pos_after_plus != std::string::npos)\r       params[5] = params[5].substr(pos_after_plus);\r\r for (std::string::iterator v = params[5].begin(); v != params[5].end(); v++)\r   {\r              _new->modes[(*v)-65] = 1;\r              /* For each mode thats set, increase counter */\r                ModeHandler* mh = Instance->Modes->FindMode(*v, MODETYPE_USER);\r                if (mh)\r                        mh->ChangeCount(1);\r    }\r\r     /* now we've done with modes processing, put the + back for remote servers */\r  params[5] = "+" + params[5];\r\r#ifdef SUPPORT_IP6LINKS\r  if (params[6].find_first_of(":") != std::string::npos)\r         _new->SetSockAddr(AF_INET6, params[6].c_str(), 0);\r     else\r#endif\r            _new->SetSockAddr(AF_INET, params[6].c_str(), 0);\r\r     Instance->AddGlobalClone(_new);\r\r       bool dosend = !(((this->Utils->quiet_bursts) && (this->bursting || Utils->FindRemoteBurstServer(remoteserver))) || (this->Instance->SilentULine(_new->server)));\r       \r       if (dosend)\r            this->Instance->SNO->WriteToSnoMask('C',"Client connecting at %s: %s!%s@%s [%s] [%s]",_new->server,_new->nick,_new->ident,_new->host, _new->GetIPString(), _new->fullname);\r\r   params[7] = ":" + params[7];\r   Utils->DoOneToAllButSender(source,"NICK", params, source);\r\r    // Increment the Source Servers User Count..\r   TreeServer* SourceServer = Utils->FindServer(source);\r  if (SourceServer)\r      {\r              SourceServer->AddUserCount();\r  }\r\r     FOREACH_MOD_I(Instance,I_OnPostConnect,OnPostConnect(_new));\r\r  return true;\r}\r\r/** Send one or more FJOINs for a channel of users.\r * If the length of a single line is more than 480-NICKMAX\r * in length, it is split over multiple lines.\r */\rvoid TreeSocket::SendFJoins(TreeServer* Current, chanrec* c)\r{\r       std::string buffer;\r    char list[MAXBUF];\r     std::string individual_halfops = std::string(":")+this->Instance->Config->ServerName+" FMODE "+c->name+" "+ConvToStr(c->age);\r\r size_t dlen, curlen;\r   dlen = curlen = snprintf(list,MAXBUF,":%s FJOIN %s %lu",this->Instance->Config->ServerName,c->name,(unsigned long)c->age);\r     int numusers = 0;\r      char* ptr = list + dlen;\r\r      CUList *ulist = c->GetUsers();\r std::string modes;\r     std::string params;\r\r   for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)\r      {\r              // The first parameter gets a : before it\r              size_t ptrlen = snprintf(ptr, MAXBUF, " %s%s,%s", !numusers ? ":" : "", c->GetAllPrefixChars(i->first), i->first->nick);\r\r              curlen += ptrlen;\r              ptr += ptrlen;\r\r                numusers++;\r\r           if (curlen > (480-NICKMAX))\r            {\r                      buffer.append(list).append("\r\n");\r                    dlen = curlen = snprintf(list,MAXBUF,":%s FJOIN %s %lu",this->Instance->Config->ServerName,c->name,(unsigned long)c->age);\r                     ptr = list + dlen;\r                     ptrlen = 0;\r                    numusers = 0;\r          }\r      }\r\r     if (numusers)\r          buffer.append(list).append("\r\n");\r\r   buffer.append(":").append(this->Instance->Config->ServerName).append(" FMODE ").append(c->name).append(" ").append(ConvToStr(c->age)).append(" +").append(c->ChanModes(true)).append("\r\n");\r\r int linesize = 1;\r      for (BanList::iterator b = c->bans.begin(); b != c->bans.end(); b++)\r   {\r              int size = strlen(b->data) + 2;\r                int currsize = linesize + size;\r                if (currsize <= 350)\r           {\r                      modes.append("b");\r                     params.append(" ").append(b->data);\r                    linesize += size; \r             }\r              if ((params.length() >= MAXMODES) || (currsize > 350))\r         {\r                      /* Wrap at MAXMODES */\r                 buffer.append(":").append(this->Instance->Config->ServerName).append(" FMODE ").append(c->name).append(" ").append(ConvToStr(c->age)).append(" +").append(modes).append(params).append("\r\n");\r                        modes.clear();\r                 params.clear();\r                        linesize = 1;\r          }\r      }\r\r     /* Only send these if there are any */\r if (!modes.empty())\r            buffer.append(":").append(this->Instance->Config->ServerName).append(" FMODE ").append(c->name).append(" ").append(ConvToStr(c->age)).append(" +").append(modes).append(params);\r\r      this->WriteLine(buffer);\r}\r\r/** Send G, Q, Z and E lines */\rvoid TreeSocket::SendXLines(TreeServer* Current)\r{\r char data[MAXBUF];\r     std::string buffer;\r    std::string n = this->Instance->Config->ServerName;\r    const char* sn = n.c_str();\r    /* Yes, these arent too nice looking, but they get the job done */\r     for (std::vector<ZLine*>::iterator i = Instance->XLines->zlines.begin(); i != Instance->XLines->zlines.end(); i++)\r     {\r              snprintf(data,MAXBUF,":%s ADDLINE Z %s %s %lu %lu :%s\r\n",sn,(*i)->ipaddr,(*i)->source,(unsigned long)(*i)->set_time,(unsigned long)(*i)->duration,(*i)->reason);\r             buffer.append(data);\r   }\r      for (std::vector<QLine*>::iterator i = Instance->XLines->qlines.begin(); i != Instance->XLines->qlines.end(); i++)\r     {\r              snprintf(data,MAXBUF,":%s ADDLINE Q %s %s %lu %lu :%s\r\n",sn,(*i)->nick,(*i)->source,(unsigned long)(*i)->set_time,(unsigned long)(*i)->duration,(*i)->reason);\r               buffer.append(data);\r   }\r      for (std::vector<GLine*>::iterator i = Instance->XLines->glines.begin(); i != Instance->XLines->glines.end(); i++)\r     {\r              snprintf(data,MAXBUF,":%s ADDLINE G %s@%s %s %lu %lu :%s\r\n",sn,(*i)->identmask,(*i)->hostmask,(*i)->source,(unsigned long)(*i)->set_time,(unsigned long)(*i)->duration,(*i)->reason);\r                buffer.append(data);\r   }\r      for (std::vector<ELine*>::iterator i = Instance->XLines->elines.begin(); i != Instance->XLines->elines.end(); i++)\r     {\r              snprintf(data,MAXBUF,":%s ADDLINE E %s@%s %s %lu %lu :%s\r\n",sn,(*i)->identmask,(*i)->hostmask,(*i)->source,(unsigned long)(*i)->set_time,(unsigned long)(*i)->duration,(*i)->reason);\r                buffer.append(data);\r   }\r      for (std::vector<ZLine*>::iterator i = Instance->XLines->pzlines.begin(); i != Instance->XLines->pzlines.end(); i++)\r   {\r              snprintf(data,MAXBUF,":%s ADDLINE Z %s %s %lu %lu :%s\r\n",sn,(*i)->ipaddr,(*i)->source,(unsigned long)(*i)->set_time,(unsigned long)(*i)->duration,(*i)->reason);\r             buffer.append(data);\r   }\r      for (std::vector<QLine*>::iterator i = Instance->XLines->pqlines.begin(); i != Instance->XLines->pqlines.end(); i++)\r   {\r              snprintf(data,MAXBUF,":%s ADDLINE Q %s %s %lu %lu :%s\r\n",sn,(*i)->nick,(*i)->source,(unsigned long)(*i)->set_time,(unsigned long)(*i)->duration,(*i)->reason);\r               buffer.append(data);\r   }\r      for (std::vector<GLine*>::iterator i = Instance->XLines->pglines.begin(); i != Instance->XLines->pglines.end(); i++)\r   {\r              snprintf(data,MAXBUF,":%s ADDLINE G %s@%s %s %lu %lu :%s\r\n",sn,(*i)->identmask,(*i)->hostmask,(*i)->source,(unsigned long)(*i)->set_time,(unsigned long)(*i)->duration,(*i)->reason);\r                buffer.append(data);\r   }\r      for (std::vector<ELine*>::iterator i = Instance->XLines->pelines.begin(); i != Instance->XLines->pelines.end(); i++)\r   {\r              snprintf(data,MAXBUF,":%s ADDLINE E %s@%s %s %lu %lu :%s\r\n",sn,(*i)->identmask,(*i)->hostmask,(*i)->source,(unsigned long)(*i)->set_time,(unsigned long)(*i)->duration,(*i)->reason);\r                buffer.append(data);\r   }\r\r     if (!buffer.empty())\r           this->WriteLine(buffer);\r}\r\r/** Send channel modes and topics */\rvoid TreeSocket::SendChannelModes(TreeServer* Current)\r{\r      char data[MAXBUF];\r     std::deque<std::string> list;\r  std::string n = this->Instance->Config->ServerName;\r    const char* sn = n.c_str();\r    Instance->Log(DEBUG,"Sending channels and modes, %d to send", this->Instance->chanlist->size());\r       for (chan_hash::iterator c = this->Instance->chanlist->begin(); c != this->Instance->chanlist->end(); c++)\r     {\r              SendFJoins(Current, c->second);\r                if (*c->second->topic)\r         {\r                      snprintf(data,MAXBUF,":%s FTOPIC %s %lu %s :%s",sn,c->second->name,(unsigned long)c->second->topicset,c->second->setby,c->second->topic);\r                      this->WriteLine(data);\r         }\r              FOREACH_MOD_I(this->Instance,I_OnSyncChannel,OnSyncChannel(c->second,(Module*)Utils->Creator,(void*)this));\r            list.clear();\r          c->second->GetExtList(list);\r           for (unsigned int j = 0; j < list.size(); j++)\r         {\r                      FOREACH_MOD_I(this->Instance,I_OnSyncChannelMetaData,OnSyncChannelMetaData(c->second,(Module*)Utils->Creator,(void*)this,list[j]));\r            }\r      }\r}\r\r/** send all users and their oper state/modes */\rvoid TreeSocket::SendUsers(TreeServer* Current)\r{\r        char data[MAXBUF];\r     std::deque<std::string> list;\r  std::string dataline;\r  for (user_hash::iterator u = this->Instance->clientlist->begin(); u != this->Instance->clientlist->end(); u++)\r {\r              if (u->second->registered == REG_ALL)\r          {\r                      snprintf(data,MAXBUF,":%s NICK %lu %s %s %s %s +%s %s :%s",u->second->server,(unsigned long)u->second->age,u->second->nick,u->second->host,u->second->dhost,u->second->ident,u->second->FormatModes(),u->second->GetIPString(),u->second->fullname);\r                   this->WriteLine(data);\r                 if (*u->second->oper)\r                  {\r                              snprintf(data,MAXBUF,":%s OPERTYPE %s", u->second->nick, u->second->oper);\r                             this->WriteLine(data);\r                 }\r                      if (*u->second->awaymsg)\r                       {\r                              snprintf(data,MAXBUF,":%s AWAY :%s", u->second->nick, u->second->awaymsg);\r                             this->WriteLine(data);\r                 }\r              }\r      }\r      for (user_hash::iterator u = this->Instance->clientlist->begin(); u != this->Instance->clientlist->end(); u++)\r {\r              FOREACH_MOD_I(this->Instance,I_OnSyncUser,OnSyncUser(u->second,(Module*)Utils->Creator,(void*)this));\r          list.clear();\r          u->second->GetExtList(list);\r           for (unsigned int j = 0; j < list.size(); j++)\r         {\r                      FOREACH_MOD_I(this->Instance,I_OnSyncUserMetaData,OnSyncUserMetaData(u->second,(Module*)Utils->Creator,(void*)this,list[j]));\r          }\r      }\r}\r\r/** This function is called when we want to send a netburst to a local\r * server. There is a set order we must do this, because for example\r * users require their servers to exist, and channels require their\r * users to exist. You get the idea.\r */\rvoid TreeSocket::DoBurst(TreeServer* s)\r{\r        std::string name = s->GetName();\r       std::string burst = "BURST "+ConvToStr(Instance->Time(true));\r  std::string endburst = "ENDBURST";\r     this->Instance->SNO->WriteToSnoMask('l',"Bursting to \2%s\2 (Authentication: %s).", name.c_str(), this->GetTheirChallenge().empty() ? "plaintext password" : "SHA256-HMAC challenge-response");\r        this->WriteLine(burst);\r        /* send our version string */\r  this->WriteLine(std::string(":")+this->Instance->Config->ServerName+" VERSION :"+this->Instance->GetVersionString());\r  /* Send server tree */\r this->SendServers(Utils->TreeRoot,s,1);\r        /* Send users and their oper status */\r this->SendUsers(s);\r    /* Send everything else (channel modes, xlines etc) */\r this->SendChannelModes(s);\r     this->SendXLines(s);\r   FOREACH_MOD_I(this->Instance,I_OnSyncOtherMetaData,OnSyncOtherMetaData((Module*)Utils->Creator,(void*)this));\r  this->WriteLine(endburst);\r     this->Instance->SNO->WriteToSnoMask('l',"Finished bursting to \2"+name+"\2.");\r}\r\r/** This function is called when we receive data from a remote\r * server. We buffer the data in a std::string (it doesnt stay\r * there for long), reading using InspSocket::Read() which can\r * read up to 16 kilobytes in one operation.\r *\r * IF THIS FUNCTION RETURNS FALSE, THE CORE CLOSES AND DELETES\r * THE SOCKET OBJECT FOR US.\r */\rbool TreeSocket::OnDataReady()\r{\r        char* data = this->Read();\r     /* Check that the data read is a valid pointer and it has some content */\r      if (data && *data)\r     {\r              this->in_buffer.append(data);\r          /* While there is at least one new line in the buffer,\r          * do something useful (we hope!) with it.\r              */\r            while (in_buffer.find("\n") != std::string::npos)\r              {\r                      std::string ret = in_buffer.substr(0,in_buffer.find("\n")-1);\r                  in_buffer = in_buffer.substr(in_buffer.find("\n")+1,in_buffer.length()-in_buffer.find("\n"));\r                  /* Use rfind here not find, as theres more\r                      * chance of the \r being near the end of the\r                   * string, not the start.\r                       */\r                    if (ret.find("\r") != std::string::npos)\r                               ret = in_buffer.substr(0,in_buffer.find("\r")-1);\r                      /* Process this one, abort if it\r                        * didnt return true.\r                   */\r                    if (!this->ProcessLine(ret))\r                   {\r                              return false;\r                  }\r              }\r              return true;\r   }\r      /* EAGAIN returns an empty but non-NULL string, so this\r         * evaluates to TRUE for EAGAIN but to FALSE for EOF.\r   */\r    return (data && !*data);\r}\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "configreader.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+#include "commands/cmd_whois.h"
+#include "commands/cmd_stats.h"
+#include "socket.h"
+#include "wildcard.h"
+#include "xline.h"
+#include "transport.h"
+#include "m_hash.h"
+#include "socketengine.h"
+
+#include "m_spanningtree/main.h"
+#include "m_spanningtree/utils.h"
+#include "m_spanningtree/treeserver.h"
+#include "m_spanningtree/link.h"
+#include "m_spanningtree/treesocket.h"
+#include "m_spanningtree/resolvers.h"
+#include "m_spanningtree/handshaketimer.h"
+
+/* $ModDep: m_spanningtree/timesynctimer.h m_spanningtree/resolvers.h m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/link.h m_spanningtree/treesocket.h m_hash.h */
+
+
+/** Because most of the I/O gubbins are encapsulated within
+ * InspSocket, we just call the superclass constructor for
+ * most of the action, and append a few of our own values
+ * to it.
+ */
+TreeSocket::TreeSocket(SpanningTreeUtilities* Util, InspIRCd* SI, std::string host, int port, bool listening, unsigned long maxtime, Module* HookMod)
+       : InspSocket(SI, host, port, listening, maxtime), Utils(Util), Hook(HookMod)
+{
+       myhost = host;
+       this->LinkState = LISTENER;
+       theirchallenge.clear();
+       ourchallenge.clear();
+       if (listening && Hook)
+               InspSocketHookRequest(this, (Module*)Utils->Creator, Hook).Send();
+}
+
+TreeSocket::TreeSocket(SpanningTreeUtilities* Util, InspIRCd* SI, std::string host, int port, bool listening, unsigned long maxtime, const std::string &ServerName, const std::string &bindto, Module* HookMod)
+       : InspSocket(SI, host, port, listening, maxtime, bindto), Utils(Util), Hook(HookMod)
+{
+       myhost = ServerName;
+       theirchallenge.clear();
+       ourchallenge.clear();
+       this->LinkState = CONNECTING;
+       if (Hook)
+               InspSocketHookRequest(this, (Module*)Utils->Creator, Hook).Send();
+}
+
+/** When a listening socket gives us a new file descriptor,
+ * we must associate it with a socket without creating a new
+ * connection. This constructor is used for this purpose.
+ */
+TreeSocket::TreeSocket(SpanningTreeUtilities* Util, InspIRCd* SI, int newfd, char* ip, Module* HookMod)
+       : InspSocket(SI, newfd, ip), Utils(Util), Hook(HookMod)
+{
+       this->LinkState = WAIT_AUTH_1;
+       theirchallenge.clear();
+       ourchallenge.clear();
+       sentcapab = false;
+       /* If we have a transport module hooked to the parent, hook the same module to this
+        * socket, and set a timer waiting for handshake before we send CAPAB etc.
+        */
+       if (Hook)
+               InspSocketHookRequest(this, (Module*)Utils->Creator, Hook).Send();
+
+       Instance->Timers->AddTimer(new HandshakeTimer(Instance, this, &(Utils->LinkBlocks[0]), this->Utils, 1));
+}
+
+ServerState TreeSocket::GetLinkState()
+{
+       return this->LinkState;
+}
+
+Module* TreeSocket::GetHook()
+{
+       return this->Hook;
+}
+
+TreeSocket::~TreeSocket()
+{
+       if (Hook)
+               InspSocketUnhookRequest(this, (Module*)Utils->Creator, Hook).Send();
+
+       Utils->DelBurstingServer(this);
+}
+
+const std::string& TreeSocket::GetOurChallenge()
+{
+       return this->ourchallenge;
+}
+
+void TreeSocket::SetOurChallenge(const std::string &c)
+{
+       this->ourchallenge = c;
+}
+
+const std::string& TreeSocket::GetTheirChallenge()
+{
+       return this->theirchallenge;
+}
+
+void TreeSocket::SetTheirChallenge(const std::string &c)
+{
+       this->theirchallenge = c;
+}
+
+std::string TreeSocket::MakePass(const std::string &password, const std::string &challenge)
+{
+       /* This is a simple (maybe a bit hacky?) HMAC algorithm, thanks to jilles for
+        * suggesting the use of HMAC to secure the password against various attacks.
+        *
+        * Note: If m_sha256.so is not loaded, we MUST fall back to plaintext with no
+        *       HMAC challenge/response.
+        */
+       Module* sha256 = Instance->FindModule("m_sha256.so");
+       if (Utils->ChallengeResponse && sha256 && !challenge.empty())
+       {
+               /* XXX: This is how HMAC is supposed to be done:
+                *
+                * sha256( (pass xor 0x5c) + sha256((pass xor 0x36) + m) )
+                *
+                * Note that we are encoding the hex hash, not the binary
+                * output of the hash which is slightly different to standard.
+                *
+                * Don't ask me why its always 0x5c and 0x36... it just is.
+                */
+               std::string hmac1, hmac2;
+
+               for (size_t n = 0; n < password.length(); n++)
+               {
+                       hmac1 += static_cast<char>(password[n] ^ 0x5C);
+                       hmac2 += static_cast<char>(password[n] ^ 0x36);
+               }
+
+               hmac2 += challenge;
+               HashResetRequest(Utils->Creator, sha256).Send();
+               hmac2 = HashSumRequest(Utils->Creator, sha256, hmac2).Send();
+
+               HashResetRequest(Utils->Creator, sha256).Send();
+               std::string hmac = hmac1 + hmac2;
+               hmac = HashSumRequest(Utils->Creator, sha256, hmac).Send();
+
+               return "HMAC-SHA256:"+ hmac;
+       }
+       else if (!challenge.empty() && !sha256)
+               Instance->Log(DEFAULT,"Not authenticating to server using SHA256/HMAC because we don't have m_sha256 loaded!");
+
+       return password;
+}
+
+/** When an outbound connection finishes connecting, we receive
+ * this event, and must send our SERVER string to the other
+ * side. If the other side is happy, as outlined in the server
+ * to server docs on the inspircd.org site, the other side
+ * will then send back its own server string.
+ */
+bool TreeSocket::OnConnected()
+{
+       if (this->LinkState == CONNECTING)
+       {
+               /* we do not need to change state here. */
+               for (std::vector<Link>::iterator x = Utils->LinkBlocks.begin(); x < Utils->LinkBlocks.end(); x++)
+               {
+                       if (x->Name == this->myhost)
+                       {
+                               this->Instance->SNO->WriteToSnoMask('l',"Connection to \2"+myhost+"\2["+(x->HiddenFromStats ? "<hidden>" : this->GetIP())+"] started.");
+                               if (Hook)
+                               {
+                                       InspSocketHookRequest(this, (Module*)Utils->Creator, Hook).Send();
+                                       this->Instance->SNO->WriteToSnoMask('l',"Connection to \2"+myhost+"\2["+(x->HiddenFromStats ? "<hidden>" : this->GetIP())+"] using transport \2"+x->Hook+"\2");
+                               }
+                               this->OutboundPass = x->SendPass;
+                               sentcapab = false;
+
+                               /* found who we're supposed to be connecting to, send the neccessary gubbins. */
+                               if (this->GetHook())
+                                       Instance->Timers->AddTimer(new HandshakeTimer(Instance, this, &(*x), this->Utils, 1));
+                               else
+                                       this->SendCapabilities();
+
+                               return true;
+                       }
+               }
+       }
+       /* There is a (remote) chance that between the /CONNECT and the connection
+        * being accepted, some muppet has removed the <link> block and rehashed.
+        * If that happens the connection hangs here until it's closed. Unlikely
+        * and rather harmless.
+        */
+       this->Instance->SNO->WriteToSnoMask('l',"Connection to \2"+myhost+"\2 lost link tag(!)");
+       return true;
+}
+
+void TreeSocket::OnError(InspSocketError e)
+{
+       Link* MyLink;
+
+       switch (e)
+       {
+               case I_ERR_CONNECT:
+                       this->Instance->SNO->WriteToSnoMask('l',"Connection failed: Connection to \002"+myhost+"\002 refused");
+                       MyLink = Utils->FindLink(myhost);
+                       if (MyLink)
+                               Utils->DoFailOver(MyLink);
+               break;
+               case I_ERR_SOCKET:
+                       this->Instance->SNO->WriteToSnoMask('l',"Connection failed: Could not create socket");
+               break;
+               case I_ERR_BIND:
+                       this->Instance->SNO->WriteToSnoMask('l',"Connection failed: Error binding socket to address or port");
+               break;
+               case I_ERR_WRITE:
+                       this->Instance->SNO->WriteToSnoMask('l',"Connection failed: I/O error on connection");
+               break;
+               case I_ERR_NOMOREFDS:
+                       this->Instance->SNO->WriteToSnoMask('l',"Connection failed: Operating system is out of file descriptors!");
+               break;
+               default:
+                       if ((errno) && (errno != EINPROGRESS) && (errno != EAGAIN))
+                       {
+                               std::string errstr = strerror(errno);
+                               this->Instance->SNO->WriteToSnoMask('l',"Connection to \002"+myhost+"\002 failed with OS error: " + errstr);
+                       }
+               break;
+       }
+}
+
+int TreeSocket::OnDisconnect()
+{
+       /* For the same reason as above, we don't
+        * handle OnDisconnect()
+        */
+       return true;
+}
+
+/** Recursively send the server tree with distances as hops.
+ * This is used during network burst to inform the other server
+ * (and any of ITS servers too) of what servers we know about.
+ * If at any point any of these servers already exist on the other
+ * end, our connection may be terminated. The hopcounts given
+ * by this function are relative, this doesn't matter so long as
+ * they are all >1, as all the remote servers re-calculate them
+ * to be relative too, with themselves as hop 0.
+ */
+void TreeSocket::SendServers(TreeServer* Current, TreeServer* s, int hops)
+{
+       char command[1024];
+       for (unsigned int q = 0; q < Current->ChildCount(); q++)
+       {
+               TreeServer* recursive_server = Current->GetChild(q);
+               if (recursive_server != s)
+               {
+                       snprintf(command,1024,":%s SERVER %s * %d :%s",Current->GetName().c_str(),recursive_server->GetName().c_str(),hops,recursive_server->GetDesc().c_str());
+                       this->WriteLine(command);
+                       this->WriteLine(":"+recursive_server->GetName()+" VERSION :"+recursive_server->GetVersion());
+                       /* down to next level */
+                       this->SendServers(recursive_server, s, hops+1);
+               }
+       }
+}
+
+std::string TreeSocket::MyCapabilities()
+{
+       std::vector<std::string> modlist;
+       std::string capabilities;
+       for (int i = 0; i <= this->Instance->GetModuleCount(); i++)
+       {
+               if (this->Instance->modules[i]->GetVersion().Flags & VF_COMMON)
+                       modlist.push_back(this->Instance->Config->module_names[i]);
+       }
+       sort(modlist.begin(),modlist.end());
+       for (unsigned int i = 0; i < modlist.size(); i++)
+       {
+               if (i)
+                       capabilities = capabilities + ",";
+               capabilities = capabilities + modlist[i];
+       }
+       return capabilities;
+}
+
+std::string TreeSocket::RandString(unsigned int length)
+{
+       char* randombuf = new char[length+1];
+       std::string out;
+#ifdef WINDOWS
+       int fd = -1;
+#else
+       int fd = open("/dev/urandom", O_RDONLY, 0);
+#endif
+
+       if (fd >= 0)
+       {
+#ifndef WINDOWS
+               read(fd, randombuf, length);
+               close(fd);
+#endif
+       }
+       else
+       {
+               for (unsigned int i = 0; i < length; i++)
+                       randombuf[i] = rand();
+       }
+
+       for (unsigned int i = 0; i < length; i++)
+       {
+               char randchar = static_cast<char>((randombuf[i] & 0x7F) | 0x21);
+               out += (randchar == '=' ? '_' : randchar);
+       }
+
+       delete[] randombuf;
+       return out;
+}
+
+void TreeSocket::SendCapabilities()
+{
+       if (sentcapab)
+               return;
+
+       sentcapab = true;
+       irc::commasepstream modulelist(MyCapabilities());
+       this->WriteLine("CAPAB START");
+
+       /* Send module names, split at 509 length */
+       std::string item = "*";
+       std::string line = "CAPAB MODULES ";
+       while ((item = modulelist.GetToken()) != "")
+       {
+               if (line.length() + item.length() + 1 > 509)
+               {
+                       this->WriteLine(line);
+                       line = "CAPAB MODULES ";
+               }
+
+               if (line != "CAPAB MODULES ")
+                       line.append(",");
+
+               line.append(item);
+       }
+       if (line != "CAPAB MODULES ")
+               this->WriteLine(line);
+
+       int ip6 = 0;
+       int ip6support = 0;
+#ifdef IPV6
+       ip6 = 1;
+#endif
+#ifdef SUPPORT_IP6LINKS
+       ip6support = 1;
+#endif
+       std::string extra;
+       /* Do we have sha256 available? If so, we send a challenge */
+       if (Utils->ChallengeResponse && (Instance->FindModule("m_sha256.so")))
+       {
+               this->SetOurChallenge(RandString(20));
+               extra = " CHALLENGE=" + this->GetOurChallenge();
+       }
+
+       this->WriteLine("CAPAB CAPABILITIES :NICKMAX="+ConvToStr(NICKMAX)+" HALFOP="+ConvToStr(this->Instance->Config->AllowHalfop)+" CHANMAX="+ConvToStr(CHANMAX)+" MAXMODES="+ConvToStr(MAXMODES)+" IDENTMAX="+ConvToStr(IDENTMAX)+" MAXQUIT="+ConvToStr(MAXQUIT)+" MAXTOPIC="+ConvToStr(MAXTOPIC)+" MAXKICK="+ConvToStr(MAXKICK)+" MAXGECOS="+ConvToStr(MAXGECOS)+" MAXAWAY="+ConvToStr(MAXAWAY)+" IP6NATIVE="+ConvToStr(ip6)+" IP6SUPPORT="+ConvToStr(ip6support)+" PROTOCOL="+ConvToStr(ProtocolVersion)+extra+" PREFIX="+Instance->Modes->BuildPrefixes()+" CHANMODES="+Instance->Modes->ChanModes());
+
+       this->WriteLine("CAPAB END");
+}
+
+/* Check a comma seperated list for an item */
+bool TreeSocket::HasItem(const std::string &list, const std::string &item)
+{
+       irc::commasepstream seplist(list);
+       std::string item2 = "*";
+       while ((item2 = seplist.GetToken()) != "")
+       {
+               if (item2 == item)
+                       return true;
+       }
+       return false;
+}
+
+/* Isolate and return the elements that are different between two comma seperated lists */
+std::string TreeSocket::ListDifference(const std::string &one, const std::string &two)
+{
+       irc::commasepstream list_one(one);
+       std::string item = "*";
+       std::string result;
+       while ((item = list_one.GetToken()) != "")
+       {
+               if (!HasItem(two, item))
+               {
+                       result.append(" ");
+                       result.append(item);
+               }
+       }
+       return result;
+}
+
+void TreeSocket::SendError(const std::string &errormessage)
+{
+       /* Display the error locally as well as sending it remotely */
+       this->WriteLine("ERROR :"+errormessage);
+       this->Instance->SNO->WriteToSnoMask('l',"Sent \2ERROR\2 to "+this->InboundServerName+": "+errormessage);
+       /* One last attempt to make sure the error reaches its target */
+       this->FlushWriteBuffer();
+}
+
+bool TreeSocket::Capab(const std::deque<std::string> &params)
+{
+       if (params.size() < 1)
+       {
+               this->SendError("Invalid number of parameters for CAPAB - Mismatched version");
+               return false;
+       }
+       if (params[0] == "START")
+       {
+               this->ModuleList.clear();
+               this->CapKeys.clear();
+       }
+       else if (params[0] == "END")
+       {
+               std::string reason;
+               int ip6support = 0;
+#ifdef SUPPORT_IP6LINKS
+               ip6support = 1;
+#endif
+               /* Compare ModuleList and check CapKeys...
+                * Maybe this could be tidier? -- Brain
+                */
+               if ((this->ModuleList != this->MyCapabilities()) && (this->ModuleList.length()))
+               {
+                       std::string diff = ListDifference(this->ModuleList, this->MyCapabilities());
+                       if (!diff.length())
+                       {
+                               diff = "your server:" + ListDifference(this->MyCapabilities(), this->ModuleList);
+                       }
+                       else
+                       {
+                               diff = "this server:" + diff;
+                       }
+                       if (diff.length() == 12)
+                               reason = "Module list in CAPAB is not alphabetically ordered, cannot compare lists.";
+                       else
+                               reason = "Modules loaded on these servers are not correctly matched, these modules are not loaded on " + diff;
+               }
+
+               cap_validation valid_capab[] = { 
+                       {"Maximum nickname lengths differ or remote nickname length not specified", "NICKMAX", NICKMAX},
+                       {"Maximum ident lengths differ or remote ident length not specified", "IDENTMAX", IDENTMAX},
+                       {"Maximum channel lengths differ or remote channel length not specified", "CHANMAX", CHANMAX},
+                       {"Maximum modes per line differ or remote modes per line not specified", "MAXMODES", MAXMODES},
+                       {"Maximum quit lengths differ or remote quit length not specified", "MAXQUIT", MAXQUIT},
+                       {"Maximum topic lengths differ or remote topic length not specified", "MAXTOPIC", MAXTOPIC},
+                       {"Maximum kick lengths differ or remote kick length not specified", "MAXKICK", MAXKICK},
+                       {"Maximum GECOS (fullname) lengths differ or remote GECOS length not specified", "MAXGECOS", MAXGECOS},
+                       {"Maximum awaymessage lengths differ or remote awaymessage length not specified", "MAXAWAY", MAXAWAY},
+                       {"", "", 0}
+               };
+
+               if (((this->CapKeys.find("IP6SUPPORT") == this->CapKeys.end()) && (ip6support)) || ((this->CapKeys.find("IP6SUPPORT") != this->CapKeys.end()) && (this->CapKeys.find("IP6SUPPORT")->second != ConvToStr(ip6support))))
+                       reason = "We don't both support linking to IPV6 servers";
+               if (((this->CapKeys.find("IP6NATIVE") != this->CapKeys.end()) && (this->CapKeys.find("IP6NATIVE")->second == "1")) && (!ip6support))
+                       reason = "The remote server is IPV6 native, and we don't support linking to IPV6 servers";
+               if (((this->CapKeys.find("PROTOCOL") == this->CapKeys.end()) || ((this->CapKeys.find("PROTOCOL") != this->CapKeys.end()) && (this->CapKeys.find("PROTOCOL")->second != ConvToStr(ProtocolVersion)))))
+               {
+                       if (this->CapKeys.find("PROTOCOL") != this->CapKeys.end())
+                               reason = "Mismatched protocol versions "+this->CapKeys.find("PROTOCOL")->second+" and "+ConvToStr(ProtocolVersion);
+                       else
+                               reason = "Protocol version not specified";
+               }
+
+               if(this->CapKeys.find("PREFIX") != this->CapKeys.end() && this->CapKeys.find("PREFIX")->second != this->Instance->Modes->BuildPrefixes())
+                       reason = "One or more of the prefixes on the remote server are invalid on this server.";
+
+               if (((this->CapKeys.find("HALFOP") == this->CapKeys.end()) && (Instance->Config->AllowHalfop)) || ((this->CapKeys.find("HALFOP") != this->CapKeys.end()) && (this->CapKeys.find("HALFOP")->second != ConvToStr(Instance->Config->AllowHalfop))))
+                       reason = "We don't both have halfop support enabled/disabled identically";
+
+               for (int x = 0; valid_capab[x].size; ++x)
+               {
+                       if (((this->CapKeys.find(valid_capab[x].key) == this->CapKeys.end()) || ((this->CapKeys.find(valid_capab[x].key) != this->CapKeys.end()) &&
+                                                (this->CapKeys.find(valid_capab[x].key)->second != ConvToStr(valid_capab[x].size)))))
+                               reason = valid_capab[x].reason;
+               }
+       
+               /* Challenge response, store their challenge for our password */
+               std::map<std::string,std::string>::iterator n = this->CapKeys.find("CHALLENGE");
+               if (Utils->ChallengeResponse && (n != this->CapKeys.end()) && (Instance->FindModule("m_sha256.so")))
+               {
+                       /* Challenge-response is on now */
+                       this->SetTheirChallenge(n->second);
+                       if (!this->GetTheirChallenge().empty() && (this->LinkState == CONNECTING))
+                       {
+                               this->WriteLine(std::string("SERVER ")+this->Instance->Config->ServerName+" "+this->MakePass(OutboundPass, this->GetTheirChallenge())+" 0 :"+this->Instance->Config->ServerDesc);
+                       }
+               }
+               else
+               {
+                       /* They didnt specify a challenge or we don't have m_sha256.so, we use plaintext */
+                       if (this->LinkState == CONNECTING)
+                               this->WriteLine(std::string("SERVER ")+this->Instance->Config->ServerName+" "+OutboundPass+" 0 :"+this->Instance->Config->ServerDesc);
+               }
+
+               if (reason.length())
+               {
+                       this->SendError("CAPAB negotiation failed: "+reason);
+                       return false;
+               }
+       }
+       else if ((params[0] == "MODULES") && (params.size() == 2))
+       {
+               if (!this->ModuleList.length())
+               {
+                       this->ModuleList.append(params[1]);
+               }
+               else
+               {
+                       this->ModuleList.append(",");
+                       this->ModuleList.append(params[1]);
+               }
+       }
+
+       else if ((params[0] == "CAPABILITIES") && (params.size() == 2))
+       {
+               irc::tokenstream capabs(params[1]);
+               std::string item;
+               bool more = true;
+               while ((more = capabs.GetToken(item)))
+               {
+                       /* Process each key/value pair */
+                       std::string::size_type equals = item.rfind('=');
+                       if (equals != std::string::npos)
+                       {
+                               std::string var = item.substr(0, equals);
+                               std::string value = item.substr(equals+1, item.length());
+                               CapKeys[var] = value;
+                       }
+               }
+       }
+       return true;
+}
+
+/** This function forces this server to quit, removing this server
+ * and any users on it (and servers and users below that, etc etc).
+ * It's very slow and pretty clunky, but luckily unless your network
+ * is having a REAL bad hair day, this function shouldnt be called
+ * too many times a month ;-)
+ */
+void TreeSocket::SquitServer(std::string &from, TreeServer* Current)
+{
+       /* recursively squit the servers attached to 'Current'.
+        * We're going backwards so we don't remove users
+        * while we still need them ;)
+        */
+       for (unsigned int q = 0; q < Current->ChildCount(); q++)
+       {
+               TreeServer* recursive_server = Current->GetChild(q);
+               this->SquitServer(from,recursive_server);
+       }
+       /* Now we've whacked the kids, whack self */
+       num_lost_servers++;
+       num_lost_users += Current->QuitUsers(from);
+}
+
+/** This is a wrapper function for SquitServer above, which
+ * does some validation first and passes on the SQUIT to all
+ * other remaining servers.
+ */
+void TreeSocket::Squit(TreeServer* Current, const std::string &reason)
+{
+       if ((Current) && (Current != Utils->TreeRoot))
+       {
+               Event rmode((char*)Current->GetName().c_str(), (Module*)Utils->Creator, "lost_server");
+               rmode.Send(Instance);
+
+               std::deque<std::string> params;
+               params.push_back(Current->GetName());
+               params.push_back(":"+reason);
+               Utils->DoOneToAllButSender(Current->GetParent()->GetName(),"SQUIT",params,Current->GetName());
+               if (Current->GetParent() == Utils->TreeRoot)
+               {
+                       this->Instance->SNO->WriteToSnoMask('l',"Server \002"+Current->GetName()+"\002 split: "+reason);
+               }
+               else
+               {
+                       this->Instance->SNO->WriteToSnoMask('l',"Server \002"+Current->GetName()+"\002 split from server \002"+Current->GetParent()->GetName()+"\002 with reason: "+reason);
+               }
+               num_lost_servers = 0;
+               num_lost_users = 0;
+               std::string from = Current->GetParent()->GetName()+" "+Current->GetName();
+               SquitServer(from, Current);
+               Current->Tidy();
+               Current->GetParent()->DelChild(Current);
+               DELETE(Current);
+               this->Instance->SNO->WriteToSnoMask('l',"Netsplit complete, lost \002%d\002 users on \002%d\002 servers.", num_lost_users, num_lost_servers);
+       }
+       else
+               Instance->Log(DEFAULT,"Squit from unknown server");
+}
+
+/** FMODE command - server mode with timestamp checks */
+bool TreeSocket::ForceMode(const std::string &source, std::deque<std::string> &params)
+{
+       /* Chances are this is a 1.0 FMODE without TS */
+       if (params.size() < 3)
+       {
+               /* No modes were in the command, probably a channel with no modes set on it */
+               return true;
+       }
+
+       bool smode = false;
+       std::string sourceserv;
+       /* Are we dealing with an FMODE from a user, or from a server? */
+       userrec* who = this->Instance->FindNick(source);
+       if (who)
+       {
+               /* FMODE from a user, set sourceserv to the users server name */
+               sourceserv = who->server;
+       }
+       else
+       {
+               /* FMODE from a server, create a fake user to receive mode feedback */
+               who = new userrec(this->Instance);
+               who->SetFd(FD_MAGIC_NUMBER);
+               smode = true;      /* Setting this flag tells us we should free the userrec later */
+               sourceserv = source;    /* Set sourceserv to the actual source string */
+       }
+       const char* modelist[64];
+       time_t TS = 0;
+       int n = 0;
+       memset(&modelist,0,sizeof(modelist));
+       for (unsigned int q = 0; (q < params.size()) && (q < 64); q++)
+       {
+               if (q == 1)
+               {
+                       /* The timestamp is in this position.
+                        * We don't want to pass that up to the
+                        * server->client protocol!
+                        */
+                       TS = atoi(params[q].c_str());
+               }
+               else
+               {
+                       /* Everything else is fine to append to the modelist */
+                       modelist[n++] = params[q].c_str();
+               }
+
+       }
+       /* Extract the TS value of the object, either userrec or chanrec */
+       userrec* dst = this->Instance->FindNick(params[0]);
+       chanrec* chan = NULL;
+       time_t ourTS = 0;
+       if (dst)
+       {
+               ourTS = dst->age;
+       }
+       else
+       {
+               chan = this->Instance->FindChan(params[0]);
+               if (chan)
+               {
+                       ourTS = chan->age;
+               }
+               else
+                       /* Oops, channel doesnt exist! */
+                       return true;
+       }
+
+       if (!TS)
+       {
+               Instance->Log(DEFAULT,"*** BUG? *** TS of 0 sent to FMODE. Are some services authors smoking craq, or is it 1970 again?. Dropped.");
+               Instance->SNO->WriteToSnoMask('d', "WARNING: The server %s is sending FMODE with a TS of zero. Total craq. Mode was dropped.", sourceserv.c_str());
+               return true;
+       }
+
+       /* TS is equal or less: Merge the mode changes into ours and pass on.
+        */
+       if (TS <= ourTS)
+       {
+               if ((TS < ourTS) && (!dst))
+                       Instance->Log(DEFAULT,"*** BUG *** Channel TS sent in FMODE to %s is %lu which is not equal to %lu!", params[0].c_str(), TS, ourTS);
+
+               if (smode)
+               {
+                       this->Instance->SendMode(modelist, n, who);
+               }
+               else
+               {
+                       this->Instance->CallCommandHandler("MODE", modelist, n, who);
+               }
+               /* HOT POTATO! PASS IT ON! */
+               Utils->DoOneToAllButSender(source,"FMODE",params,sourceserv);
+       }
+       /* If the TS is greater than ours, we drop the mode and dont pass it anywhere.
+        */
+
+       if (smode)
+               DELETE(who);
+
+       return true;
+}
+
+/** FTOPIC command */
+bool TreeSocket::ForceTopic(const std::string &source, std::deque<std::string> &params)
+{
+       if (params.size() != 4)
+               return true;
+       time_t ts = atoi(params[1].c_str());
+       std::string nsource = source;
+       chanrec* c = this->Instance->FindChan(params[0]);
+       if (c)
+       {
+               if ((ts >= c->topicset) || (!*c->topic))
+               {
+                       std::string oldtopic = c->topic;
+                       strlcpy(c->topic,params[3].c_str(),MAXTOPIC);
+                       strlcpy(c->setby,params[2].c_str(),127);
+                       c->topicset = ts;
+                       /* if the topic text is the same as the current topic,
+                        * dont bother to send the TOPIC command out, just silently
+                        * update the set time and set nick.
+                        */
+                       if (oldtopic != params[3])
+                       {
+                               userrec* user = this->Instance->FindNick(source);
+                               if (!user)
+                               {
+                                       c->WriteChannelWithServ(Instance->Config->ServerName, "TOPIC %s :%s", c->name, c->topic);
+                               }
+                               else
+                               {
+                                       c->WriteChannel(user, "TOPIC %s :%s", c->name, c->topic);
+                                       nsource = user->server;
+                               }
+                               /* all done, send it on its way */
+                               params[3] = ":" + params[3];
+                               Utils->DoOneToAllButSender(source,"FTOPIC",params,nsource);
+                       }
+               }
+
+       }
+       return true;
+}
+
+/** FJOIN, similar to TS6 SJOIN, but not quite. */
+bool TreeSocket::ForceJoin(const std::string &source, std::deque<std::string> &params)
+{
+       /* 1.1 FJOIN works as follows:
+        *
+        * Each FJOIN is sent along with a timestamp, and the side with the lowest
+        * timestamp 'wins'. From this point on we will refer to this side as the
+        * winner. The side with the higher timestamp loses, from this point on we
+        * will call this side the loser or losing side. This should be familiar to
+        * anyone who's dealt with dreamforge or TS6 before.
+        *
+        * When two sides of a split heal and this occurs, the following things
+        * will happen:
+        *
+        * If the timestamps are exactly equal, both sides merge their privilages
+        * and users, as in InspIRCd 1.0 and ircd2.8. The channels have not been
+        * re-created during a split, this is safe to do.
+        *
+        * If the timestamps are NOT equal, the losing side removes all of its
+        * modes from the channel, before introducing new users into the channel
+        * which are listed in the FJOIN command's parameters. The losing side then
+        * LOWERS its timestamp value of the channel to match that of the winning
+        * side, and the modes of the users of the winning side are merged in with
+        * the losing side.
+        *
+        * The winning side on the other hand will ignore all user modes from the
+        * losing side, so only its own modes get applied. Life is simple for those
+        * who succeed at internets. :-)
+        *
+        * NOTE: Unlike TS6 and dreamforge and other protocols which have SJOIN,
+        * FJOIN does not contain the simple-modes such as +iklmnsp. Why not,
+        * you ask? Well, quite simply because we don't need to. They'll be sent
+        * after the FJOIN by FMODE, and FMODE is timestamped, so in the event
+        * the losing side sends any modes for the channel which shouldnt win,
+        * they wont as their timestamp will be too high :-)
+        */
+
+       if (params.size() < 3)
+               return true;
+
+       irc::modestacker modestack(true);                               /* Modes to apply from the users in the user list */
+       userrec* who = NULL;                                            /* User we are currently checking */
+       std::string channel = params[0];                                /* Channel name, as a string */
+       time_t TS = atoi(params[1].c_str());                            /* Timestamp given to us for remote side */
+       irc::tokenstream users(params[2]);                              /* Users from the user list */
+       bool apply_other_sides_modes = true;                            /* True if we are accepting the other side's modes */
+       chanrec* chan = this->Instance->FindChan(channel);              /* The channel we're sending joins to */
+       time_t ourTS = chan ? chan->age : Instance->Time(true)+600;     /* The TS of our side of the link */
+       bool created = !chan;                                           /* True if the channel doesnt exist here yet */
+       std::string item;                                               /* One item in the list of nicks */
+
+       params[2] = ":" + params[2];
+       Utils->DoOneToAllButSender(source,"FJOIN",params,source);
+
+        if (!TS)
+       {
+               Instance->Log(DEFAULT,"*** BUG? *** TS of 0 sent to FJOIN. Are some services authors smoking craq, or is it 1970 again?. Dropped.");
+               Instance->SNO->WriteToSnoMask('d', "WARNING: The server %s is sending FJOIN with a TS of zero. Total craq. Command was dropped.", source.c_str());
+               return true;
+       }
+
+       /* If our TS is less than theirs, we dont accept their modes */
+       if (ourTS < TS)
+               apply_other_sides_modes = false;
+
+       /* Our TS greater than theirs, clear all our modes from the channel, accept theirs. */
+       if (ourTS > TS)
+       {
+               std::deque<std::string> param_list;
+               if (Utils->AnnounceTSChange && chan)
+                       chan->WriteChannelWithServ(Instance->Config->ServerName, "NOTICE %s :TS for %s changed from %lu to %lu", chan->name, chan->name, ourTS, TS);
+               ourTS = TS;
+               if (!created)
+               {
+                       chan->age = TS;
+                       param_list.push_back(channel);
+                       this->RemoveStatus(Instance->Config->ServerName, param_list);
+               }
+       }
+
+       /* Now, process every 'prefixes,nick' pair */
+       while (users.GetToken(item))
+       {
+               const char* usr = item.c_str();
+               if (usr && *usr)
+               {
+                       const char* permissions = usr;
+                       /* Iterate through all the prefix values, convert them from prefixes to mode letters */
+                       std::string modes;
+                       while ((*permissions) && (*permissions != ','))
+                       {
+                               ModeHandler* mh = Instance->Modes->FindPrefix(*permissions);
+                               if (mh)
+                                       modes = modes + mh->GetModeChar();
+                               else
+                               {
+                                       this->SendError(std::string("Invalid prefix '")+(*permissions)+"' in FJOIN");
+                                       return false;
+                               }
+                               usr++;
+                               permissions++;
+                       }
+                       /* Advance past the comma, to the nick */
+                       usr++;
+                       
+                       /* Check the user actually exists */
+                       who = this->Instance->FindNick(usr);
+                       if (who)
+                       {
+                               /* Check that the user's 'direction' is correct */
+                               TreeServer* route_back_again = Utils->BestRouteTo(who->server);
+                               if ((!route_back_again) || (route_back_again->GetSocket() != this))
+                                       continue;
+
+                               /* Add any permissions this user had to the mode stack */
+                               for (std::string::iterator x = modes.begin(); x != modes.end(); ++x)
+                                       modestack.Push(*x, who->nick);
+
+                               chanrec::JoinUser(this->Instance, who, channel.c_str(), true, "", TS);
+                       }
+                       else
+                       {
+                               Instance->Log(SPARSE,"Warning! Invalid user %s in FJOIN to channel %s IGNORED", usr, channel.c_str());
+                               continue;
+                       }
+               }
+       }
+
+       /* Flush mode stacker if we lost the FJOIN or had equal TS */
+       if (apply_other_sides_modes)
+       {
+               std::deque<std::string> stackresult;
+               const char* mode_junk[MAXMODES+2];
+               userrec* n = new userrec(Instance);
+               n->SetFd(FD_MAGIC_NUMBER);
+               mode_junk[0] = channel.c_str();
+
+               while (modestack.GetStackedLine(stackresult))
+               {
+                       for (size_t j = 0; j < stackresult.size(); j++)
+                       {
+                               mode_junk[j+1] = stackresult[j].c_str();
+                       }
+                       Instance->SendMode(mode_junk, stackresult.size() + 1, n);
+               }
+
+               delete n;
+       }
+
+       return true;
+}
+
+/** NICK command */
+bool TreeSocket::IntroduceClient(const std::string &source, std::deque<std::string> &params)
+{
+       /** Do we have enough parameters:
+        * NICK age nick host dhost ident +modes ip :gecos
+        */
+       if (params.size() != 8)
+       {
+               this->WriteLine(std::string(":")+this->Instance->Config->ServerName+" KILL "+params[1]+" :Invalid client introduction ("+params[1]+"?)");
+               return true;
+       }
+
+       time_t age = ConvToInt(params[0]);
+       const char* tempnick = params[1].c_str();
+
+       cmd_validation valid[] = { {"Nickname", 1, NICKMAX}, {"Hostname", 2, 64}, {"Displayed hostname", 3, 64}, {"Ident", 4, IDENTMAX}, {"GECOS", 7, MAXGECOS}, {"", 0, 0} };
+
+       TreeServer* remoteserver = Utils->FindServer(source);
+       if (!remoteserver)
+       {
+               this->WriteLine(std::string(":")+this->Instance->Config->ServerName+" KILL "+params[1]+" :Invalid client introduction (Unknown server "+source+")");
+               return true;
+       }
+
+       /* Check parameters for validity before introducing the client, discovered by dmb */
+       if (!age)
+       {
+               this->WriteLine(std::string(":")+this->Instance->Config->ServerName+" KILL "+params[1]+" :Invalid client introduction (Invalid TS?)");
+               return true;
+       }
+       for (size_t x = 0; valid[x].length; ++x)
+       {
+               if (params[valid[x].param].length() > valid[x].length)
+               {
+                       this->WriteLine(std::string(":")+this->Instance->Config->ServerName+" KILL "+params[1]+" :Invalid client introduction (" + valid[x].item + " > " + ConvToStr(valid[x].length) + ")");
+                       return true;
+               }
+       }
+
+       /** Our client looks ok, lets introduce it now
+        */
+       Instance->Log(DEBUG,"New remote client %s",tempnick);
+       user_hash::iterator iter = this->Instance->clientlist->find(tempnick);
+
+       if (iter != this->Instance->clientlist->end())
+       {
+               /* nick collision */
+               this->WriteLine(std::string(":")+this->Instance->Config->ServerName+" KILL "+tempnick+" :Nickname collision");
+               userrec::QuitUser(this->Instance, iter->second, "Nickname collision");
+               return true;
+       }
+
+       userrec* _new = new userrec(this->Instance);
+       (*(this->Instance->clientlist))[tempnick] = _new;
+       _new->SetFd(FD_MAGIC_NUMBER);
+       strlcpy(_new->nick, tempnick,NICKMAX-1);
+       strlcpy(_new->host, params[2].c_str(),64);
+       strlcpy(_new->dhost, params[3].c_str(),64);
+       _new->server = this->Instance->FindServerNamePtr(source.c_str());
+       strlcpy(_new->ident, params[4].c_str(),IDENTMAX);
+       strlcpy(_new->fullname, params[7].c_str(),MAXGECOS);
+       _new->registered = REG_ALL;
+       _new->signon = age;
+
+       /* we need to remove the + from the modestring, so we can do our stuff */
+       std::string::size_type pos_after_plus = params[5].find_first_not_of('+');
+       if (pos_after_plus != std::string::npos)
+       params[5] = params[5].substr(pos_after_plus);
+
+       for (std::string::iterator v = params[5].begin(); v != params[5].end(); v++)
+       {
+               _new->modes[(*v)-65] = 1;
+               /* For each mode thats set, increase counter */
+               ModeHandler* mh = Instance->Modes->FindMode(*v, MODETYPE_USER);
+               if (mh)
+                       mh->ChangeCount(1);
+       }
+
+       /* now we've done with modes processing, put the + back for remote servers */
+       params[5] = "+" + params[5];
+
+#ifdef SUPPORT_IP6LINKS
+       if (params[6].find_first_of(":") != std::string::npos)
+               _new->SetSockAddr(AF_INET6, params[6].c_str(), 0);
+       else
+#endif
+               _new->SetSockAddr(AF_INET, params[6].c_str(), 0);
+
+       Instance->AddGlobalClone(_new);
+
+       bool dosend = !(((this->Utils->quiet_bursts) && (this->bursting || Utils->FindRemoteBurstServer(remoteserver))) || (this->Instance->SilentULine(_new->server)));
+       
+       if (dosend)
+               this->Instance->SNO->WriteToSnoMask('C',"Client connecting at %s: %s!%s@%s [%s] [%s]",_new->server,_new->nick,_new->ident,_new->host, _new->GetIPString(), _new->fullname);
+
+       params[7] = ":" + params[7];
+       Utils->DoOneToAllButSender(source,"NICK", params, source);
+
+       // Increment the Source Servers User Count..
+       TreeServer* SourceServer = Utils->FindServer(source);
+       if (SourceServer)
+       {
+               SourceServer->AddUserCount();
+       }
+
+       FOREACH_MOD_I(Instance,I_OnPostConnect,OnPostConnect(_new));
+
+       return true;
+}
+
+/** Send one or more FJOINs for a channel of users.
+ * If the length of a single line is more than 480-NICKMAX
+ * in length, it is split over multiple lines.
+ */
+void TreeSocket::SendFJoins(TreeServer* Current, chanrec* c)
+{
+       std::string buffer;
+       char list[MAXBUF];
+       std::string individual_halfops = std::string(":")+this->Instance->Config->ServerName+" FMODE "+c->name+" "+ConvToStr(c->age);
+
+       size_t dlen, curlen;
+       dlen = curlen = snprintf(list,MAXBUF,":%s FJOIN %s %lu",this->Instance->Config->ServerName,c->name,(unsigned long)c->age);
+       int numusers = 0;
+       char* ptr = list + dlen;
+
+       CUList *ulist = c->GetUsers();
+       std::string modes;
+       std::string params;
+
+       for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
+       {
+               // The first parameter gets a : before it
+               size_t ptrlen = snprintf(ptr, MAXBUF, " %s%s,%s", !numusers ? ":" : "", c->GetAllPrefixChars(i->first), i->first->nick);
+
+               curlen += ptrlen;
+               ptr += ptrlen;
+
+               numusers++;
+
+               if (curlen > (480-NICKMAX))
+               {
+                       buffer.append(list).append("\r\n");
+                       dlen = curlen = snprintf(list,MAXBUF,":%s FJOIN %s %lu",this->Instance->Config->ServerName,c->name,(unsigned long)c->age);
+                       ptr = list + dlen;
+                       ptrlen = 0;
+                       numusers = 0;
+               }
+       }
+
+       if (numusers)
+               buffer.append(list).append("\r\n");
+
+       buffer.append(":").append(this->Instance->Config->ServerName).append(" FMODE ").append(c->name).append(" ").append(ConvToStr(c->age)).append(" +").append(c->ChanModes(true)).append("\r\n");
+
+       int linesize = 1;
+       for (BanList::iterator b = c->bans.begin(); b != c->bans.end(); b++)
+       {
+               int size = strlen(b->data) + 2;
+               int currsize = linesize + size;
+               if (currsize <= 350)
+               {
+                       modes.append("b");
+                       params.append(" ").append(b->data);
+                       linesize += size; 
+               }
+               if ((params.length() >= MAXMODES) || (currsize > 350))
+               {
+                       /* Wrap at MAXMODES */
+                       buffer.append(":").append(this->Instance->Config->ServerName).append(" FMODE ").append(c->name).append(" ").append(ConvToStr(c->age)).append(" +").append(modes).append(params).append("\r\n");
+                       modes.clear();
+                       params.clear();
+                       linesize = 1;
+               }
+       }
+
+       /* Only send these if there are any */
+       if (!modes.empty())
+               buffer.append(":").append(this->Instance->Config->ServerName).append(" FMODE ").append(c->name).append(" ").append(ConvToStr(c->age)).append(" +").append(modes).append(params);
+
+       this->WriteLine(buffer);
+}
+
+/** Send G, Q, Z and E lines */
+void TreeSocket::SendXLines(TreeServer* Current)
+{
+       char data[MAXBUF];
+       std::string buffer;
+       std::string n = this->Instance->Config->ServerName;
+       const char* sn = n.c_str();
+       /* Yes, these arent too nice looking, but they get the job done */
+       for (std::vector<ZLine*>::iterator i = Instance->XLines->zlines.begin(); i != Instance->XLines->zlines.end(); i++)
+       {
+               snprintf(data,MAXBUF,":%s ADDLINE Z %s %s %lu %lu :%s\r\n",sn,(*i)->ipaddr,(*i)->source,(unsigned long)(*i)->set_time,(unsigned long)(*i)->duration,(*i)->reason);
+               buffer.append(data);
+       }
+       for (std::vector<QLine*>::iterator i = Instance->XLines->qlines.begin(); i != Instance->XLines->qlines.end(); i++)
+       {
+               snprintf(data,MAXBUF,":%s ADDLINE Q %s %s %lu %lu :%s\r\n",sn,(*i)->nick,(*i)->source,(unsigned long)(*i)->set_time,(unsigned long)(*i)->duration,(*i)->reason);
+               buffer.append(data);
+       }
+       for (std::vector<GLine*>::iterator i = Instance->XLines->glines.begin(); i != Instance->XLines->glines.end(); i++)
+       {
+               snprintf(data,MAXBUF,":%s ADDLINE G %s@%s %s %lu %lu :%s\r\n",sn,(*i)->identmask,(*i)->hostmask,(*i)->source,(unsigned long)(*i)->set_time,(unsigned long)(*i)->duration,(*i)->reason);
+               buffer.append(data);
+       }
+       for (std::vector<ELine*>::iterator i = Instance->XLines->elines.begin(); i != Instance->XLines->elines.end(); i++)
+       {
+               snprintf(data,MAXBUF,":%s ADDLINE E %s@%s %s %lu %lu :%s\r\n",sn,(*i)->identmask,(*i)->hostmask,(*i)->source,(unsigned long)(*i)->set_time,(unsigned long)(*i)->duration,(*i)->reason);
+               buffer.append(data);
+       }
+       for (std::vector<ZLine*>::iterator i = Instance->XLines->pzlines.begin(); i != Instance->XLines->pzlines.end(); i++)
+       {
+               snprintf(data,MAXBUF,":%s ADDLINE Z %s %s %lu %lu :%s\r\n",sn,(*i)->ipaddr,(*i)->source,(unsigned long)(*i)->set_time,(unsigned long)(*i)->duration,(*i)->reason);
+               buffer.append(data);
+       }
+       for (std::vector<QLine*>::iterator i = Instance->XLines->pqlines.begin(); i != Instance->XLines->pqlines.end(); i++)
+       {
+               snprintf(data,MAXBUF,":%s ADDLINE Q %s %s %lu %lu :%s\r\n",sn,(*i)->nick,(*i)->source,(unsigned long)(*i)->set_time,(unsigned long)(*i)->duration,(*i)->reason);
+               buffer.append(data);
+       }
+       for (std::vector<GLine*>::iterator i = Instance->XLines->pglines.begin(); i != Instance->XLines->pglines.end(); i++)
+       {
+               snprintf(data,MAXBUF,":%s ADDLINE G %s@%s %s %lu %lu :%s\r\n",sn,(*i)->identmask,(*i)->hostmask,(*i)->source,(unsigned long)(*i)->set_time,(unsigned long)(*i)->duration,(*i)->reason);
+               buffer.append(data);
+       }
+       for (std::vector<ELine*>::iterator i = Instance->XLines->pelines.begin(); i != Instance->XLines->pelines.end(); i++)
+       {
+               snprintf(data,MAXBUF,":%s ADDLINE E %s@%s %s %lu %lu :%s\r\n",sn,(*i)->identmask,(*i)->hostmask,(*i)->source,(unsigned long)(*i)->set_time,(unsigned long)(*i)->duration,(*i)->reason);
+               buffer.append(data);
+       }
+
+       if (!buffer.empty())
+               this->WriteLine(buffer);
+}
+
+/** Send channel modes and topics */
+void TreeSocket::SendChannelModes(TreeServer* Current)
+{
+       char data[MAXBUF];
+       std::deque<std::string> list;
+       std::string n = this->Instance->Config->ServerName;
+       const char* sn = n.c_str();
+       Instance->Log(DEBUG,"Sending channels and modes, %d to send", this->Instance->chanlist->size());
+       for (chan_hash::iterator c = this->Instance->chanlist->begin(); c != this->Instance->chanlist->end(); c++)
+       {
+               SendFJoins(Current, c->second);
+               if (*c->second->topic)
+               {
+                       snprintf(data,MAXBUF,":%s FTOPIC %s %lu %s :%s",sn,c->second->name,(unsigned long)c->second->topicset,c->second->setby,c->second->topic);
+                       this->WriteLine(data);
+               }
+               FOREACH_MOD_I(this->Instance,I_OnSyncChannel,OnSyncChannel(c->second,(Module*)Utils->Creator,(void*)this));
+               list.clear();
+               c->second->GetExtList(list);
+               for (unsigned int j = 0; j < list.size(); j++)
+               {
+                       FOREACH_MOD_I(this->Instance,I_OnSyncChannelMetaData,OnSyncChannelMetaData(c->second,(Module*)Utils->Creator,(void*)this,list[j]));
+               }
+       }
+}
+
+/** send all users and their oper state/modes */
+void TreeSocket::SendUsers(TreeServer* Current)
+{
+       char data[MAXBUF];
+       std::deque<std::string> list;
+       std::string dataline;
+       for (user_hash::iterator u = this->Instance->clientlist->begin(); u != this->Instance->clientlist->end(); u++)
+       {
+               if (u->second->registered == REG_ALL)
+               {
+                       snprintf(data,MAXBUF,":%s NICK %lu %s %s %s %s +%s %s :%s",u->second->server,(unsigned long)u->second->age,u->second->nick,u->second->host,u->second->dhost,u->second->ident,u->second->FormatModes(),u->second->GetIPString(),u->second->fullname);
+                       this->WriteLine(data);
+                       if (*u->second->oper)
+                       {
+                               snprintf(data,MAXBUF,":%s OPERTYPE %s", u->second->nick, u->second->oper);
+                               this->WriteLine(data);
+                       }
+                       if (*u->second->awaymsg)
+                       {
+                               snprintf(data,MAXBUF,":%s AWAY :%s", u->second->nick, u->second->awaymsg);
+                               this->WriteLine(data);
+                       }
+               }
+       }
+       for (user_hash::iterator u = this->Instance->clientlist->begin(); u != this->Instance->clientlist->end(); u++)
+       {
+               FOREACH_MOD_I(this->Instance,I_OnSyncUser,OnSyncUser(u->second,(Module*)Utils->Creator,(void*)this));
+               list.clear();
+               u->second->GetExtList(list);
+               for (unsigned int j = 0; j < list.size(); j++)
+               {
+                       FOREACH_MOD_I(this->Instance,I_OnSyncUserMetaData,OnSyncUserMetaData(u->second,(Module*)Utils->Creator,(void*)this,list[j]));
+               }
+       }
+}
+
+/** This function is called when we want to send a netburst to a local
+ * server. There is a set order we must do this, because for example
+ * users require their servers to exist, and channels require their
+ * users to exist. You get the idea.
+ */
+void TreeSocket::DoBurst(TreeServer* s)
+{
+       std::string name = s->GetName();
+       std::string burst = "BURST "+ConvToStr(Instance->Time(true));
+       std::string endburst = "ENDBURST";
+       this->Instance->SNO->WriteToSnoMask('l',"Bursting to \2%s\2 (Authentication: %s).", name.c_str(), this->GetTheirChallenge().empty() ? "plaintext password" : "SHA256-HMAC challenge-response");
+       this->WriteLine(burst);
+       /* send our version string */
+       this->WriteLine(std::string(":")+this->Instance->Config->ServerName+" VERSION :"+this->Instance->GetVersionString());
+       /* Send server tree */
+       this->SendServers(Utils->TreeRoot,s,1);
+       /* Send users and their oper status */
+       this->SendUsers(s);
+       /* Send everything else (channel modes, xlines etc) */
+       this->SendChannelModes(s);
+       this->SendXLines(s);
+       FOREACH_MOD_I(this->Instance,I_OnSyncOtherMetaData,OnSyncOtherMetaData((Module*)Utils->Creator,(void*)this));
+       this->WriteLine(endburst);
+       this->Instance->SNO->WriteToSnoMask('l',"Finished bursting to \2"+name+"\2.");
+}
+
+/** This function is called when we receive data from a remote
+ * server. We buffer the data in a std::string (it doesnt stay
+ * there for long), reading using InspSocket::Read() which can
+ * read up to 16 kilobytes in one operation.
+ *
+ * IF THIS FUNCTION RETURNS FALSE, THE CORE CLOSES AND DELETES
+ * THE SOCKET OBJECT FOR US.
+ */
+bool TreeSocket::OnDataReady()
+{
+       char* data = this->Read();
+       /* Check that the data read is a valid pointer and it has some content */
+       if (data && *data)
+       {
+               this->in_buffer.append(data);
+               /* While there is at least one new line in the buffer,
+                * do something useful (we hope!) with it.
+                */
+               while (in_buffer.find("\n") != std::string::npos)
+               {
+                       std::string ret = in_buffer.substr(0,in_buffer.find("\n")-1);
+                       in_buffer = in_buffer.substr(in_buffer.find("\n")+1,in_buffer.length()-in_buffer.find("\n"));
+                       /* Use rfind here not find, as theres more
+                        * chance of the \r being near the end of the
+                        * string, not the start.
+                        */
+                       if (ret.find("\r") != std::string::npos)
+                               ret = in_buffer.substr(0,in_buffer.find("\r")-1);
+                       /* Process this one, abort if it
+                        * didnt return true.
+                        */
+                       if (!this->ProcessLine(ret))
+                       {
+                               return false;
+                       }
+               }
+               return true;
+       }
+       /* EAGAIN returns an empty but non-NULL string, so this
+        * evaluates to TRUE for EAGAIN but to FALSE for EOF.
+        */
+       return (data && !*data);
+}
+
index d383e2394b6b73df13703dbe63717a394f284d28..f518151e9a3b7bf9f5ebd64e3fe46e8f4ad39d6e 100644 (file)
@@ -1 +1,1554 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "configreader.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r#include "commands/cmd_whois.h"\r#include "commands/cmd_stats.h"\r#include "socket.h"\r#include "wildcard.h"\r#include "xline.h"\r#include "transport.h"\r#include "socketengine.h"\r\r#include "m_spanningtree/main.h"\r#include "m_spanningtree/utils.h"\r#include "m_spanningtree/treeserver.h"\r#include "m_spanningtree/link.h"\r#include "m_spanningtree/treesocket.h"\r#include "m_spanningtree/resolvers.h"\r#include "m_spanningtree/handshaketimer.h"\r\r/* $ModDep: m_spanningtree/timesynctimer.h m_spanningtree/resolvers.h m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/link.h m_spanningtree/treesocket.h */\r\rstatic std::map<std::string, std::string> warned;       /* Server names that have had protocol violation warnings displayed for them */\r\rint TreeSocket::WriteLine(std::string line)\r{\r      Instance->Log(DEBUG, "S[%d] -> %s", this->GetFd(), line.c_str());\r      line.append("\r\n");\r   return this->Write(line);\r}\r\r\r/* Handle ERROR command */\rbool TreeSocket::Error(std::deque<std::string> &params)\r{\r     if (params.size() < 1)\r         return false;\r  this->Instance->SNO->WriteToSnoMask('l',"ERROR from %s: %s",(!InboundServerName.empty() ? InboundServerName.c_str() : myhost.c_str()),params[0].c_str());\r      /* we will return false to cause the socket to close. */\r       return false;\r}\r\rbool TreeSocket::Modules(const std::string &prefix, std::deque<std::string> &params)\r{\r        if (params.empty())\r            return true;\r\r  if (!this->Instance->MatchText(this->Instance->Config->ServerName, params[0]))\r {\r              /* Pass it on, not for us */\r           Utils->DoOneToOne(prefix, "MODULES", params, params[0]);\r               return true;\r   }\r\r     char strbuf[MAXBUF];\r   std::deque<std::string> par;\r   par.push_back(prefix);\r par.push_back("");\r\r    userrec* source = this->Instance->FindNick(prefix);\r    if (!source)\r           return true;\r\r  for (unsigned int i = 0; i < Instance->Config->module_names.size(); i++)\r       {\r              Version V = Instance->modules[i]->GetVersion();\r                char modulename[MAXBUF];\r               char flagstate[MAXBUF];\r                *flagstate = 0;\r                if (V.Flags & VF_STATIC)\r                       strlcat(flagstate,", static",MAXBUF);\r          if (V.Flags & VF_VENDOR)\r                       strlcat(flagstate,", vendor",MAXBUF);\r          if (V.Flags & VF_COMMON)\r                       strlcat(flagstate,", common",MAXBUF);\r          if (V.Flags & VF_SERVICEPROVIDER)\r                      strlcat(flagstate,", service provider",MAXBUF);\r                if (!flagstate[0])\r                     strcpy(flagstate,"  <no flags>");\r              strlcpy(modulename,Instance->Config->module_names[i].c_str(),256);\r             if (*source->oper)\r             {\r                      snprintf(strbuf, MAXBUF, "::%s 900 %s :0x%08lx %d.%d.%d.%d %s (%s)",Instance->Config->ServerName,source->nick,(long unsigned int)Instance->modules[i],V.Major,V.Minor,V.Revision,V.Build,ServerConfig::CleanFilename(modulename),flagstate+2);\r         }\r              else\r           {\r                      snprintf(strbuf, MAXBUF, "::%s 900 %s :%s",Instance->Config->ServerName,source->nick,ServerConfig::CleanFilename(modulename));\r         }\r              par[1] = strbuf;\r               Utils->DoOneToOne(Instance->Config->ServerName, "PUSH", par, source->server);\r  }\r      snprintf(strbuf, MAXBUF, "::%s 901 %s :End of MODULES list", Instance->Config->ServerName, source->nick);\r      par[1] = strbuf;\r       Utils->DoOneToOne(Instance->Config->ServerName, "PUSH", par, source->server);\r  return true;\r}\r\r/** remote MOTD. leet, huh? */\rbool TreeSocket::Motd(const std::string &prefix, std::deque<std::string> &params)\r{\r     if (params.size() > 0)\r {\r              if (this->Instance->MatchText(this->Instance->Config->ServerName, params[0]))\r          {\r                      /* It's for our server */\r                      string_list results;\r                   userrec* source = this->Instance->FindNick(prefix);\r\r                   if (source)\r                    {\r                              std::deque<std::string> par;\r                           par.push_back(prefix);\r                         par.push_back("");\r\r                            if (!Instance->Config->MOTD.size())\r                            {\r                                      par[1] = std::string("::")+Instance->Config->ServerName+" 422 "+source->nick+" :Message of the day file is missing.";\r                                  Utils->DoOneToOne(this->Instance->Config->ServerName, "PUSH",par, source->server);\r                                     return true;\r                           }\r\r                             par[1] = std::string("::")+Instance->Config->ServerName+" 375 "+source->nick+" :"+Instance->Config->ServerName+" message of the day";\r                          Utils->DoOneToOne(this->Instance->Config->ServerName, "PUSH",par, source->server);\r\r                            for (unsigned int i = 0; i < Instance->Config->MOTD.size(); i++)\r                               {\r                                      par[1] = std::string("::")+Instance->Config->ServerName+" 372 "+source->nick+" :- "+Instance->Config->MOTD[i];\r                                 Utils->DoOneToOne(this->Instance->Config->ServerName, "PUSH",par, source->server);\r                             }\r\r                             par[1] = std::string("::")+Instance->Config->ServerName+" 376 "+source->nick+" End of message of the day.";\r                            Utils->DoOneToOne(this->Instance->Config->ServerName, "PUSH",par, source->server);\r                     }\r              }\r              else\r           {\r                      /* Pass it on */\r                       userrec* source = this->Instance->FindNick(prefix);\r                    if (source)\r                            Utils->DoOneToOne(prefix, "MOTD", params, params[0]);\r          }\r      }\r      return true;\r}\r\r/** remote ADMIN. leet, huh? */\rbool TreeSocket::Admin(const std::string &prefix, std::deque<std::string> &params)\r{\r   if (params.size() > 0)\r {\r              if (this->Instance->MatchText(this->Instance->Config->ServerName, params[0]))\r          {\r                      /* It's for our server */\r                      string_list results;\r                   userrec* source = this->Instance->FindNick(prefix);\r                    if (source)\r                    {\r                              std::deque<std::string> par;\r                           par.push_back(prefix);\r                         par.push_back("");\r                             par[1] = std::string("::")+Instance->Config->ServerName+" 256 "+source->nick+" :Administrative info for "+Instance->Config->ServerName;\r                                Utils->DoOneToOne(this->Instance->Config->ServerName, "PUSH",par, source->server);\r                             par[1] = std::string("::")+Instance->Config->ServerName+" 257 "+source->nick+" :Name     - "+Instance->Config->AdminName;\r                              Utils->DoOneToOne(this->Instance->Config->ServerName, "PUSH",par, source->server);\r                             par[1] = std::string("::")+Instance->Config->ServerName+" 258 "+source->nick+" :Nickname - "+Instance->Config->AdminNick;\r                              Utils->DoOneToOne(this->Instance->Config->ServerName, "PUSH",par, source->server);\r                             par[1] = std::string("::")+Instance->Config->ServerName+" 258 "+source->nick+" :E-Mail   - "+Instance->Config->AdminEmail;\r                             Utils->DoOneToOne(this->Instance->Config->ServerName, "PUSH",par, source->server);\r                     }\r              }\r              else\r           {\r                      /* Pass it on */\r                       userrec* source = this->Instance->FindNick(prefix);\r                    if (source)\r                            Utils->DoOneToOne(prefix, "ADMIN", params, params[0]);\r         }\r      }\r      return true;\r}\r\rbool TreeSocket::Stats(const std::string &prefix, std::deque<std::string> &params)\r{\r   /* Get the reply to a STATS query if it matches this servername,\r        * and send it back as a load of PUSH queries\r   */\r    if (params.size() > 1)\r {\r              if (this->Instance->MatchText(this->Instance->Config->ServerName, params[1]))\r          {\r                      /* It's for our server */\r                      string_list results;\r                   userrec* source = this->Instance->FindNick(prefix);\r                    if (source)\r                    {\r                              std::deque<std::string> par;\r                           par.push_back(prefix);\r                         par.push_back("");\r                             DoStats(this->Instance, *(params[0].c_str()), source, results);\r                                for (size_t i = 0; i < results.size(); i++)\r                            {\r                                      par[1] = "::" + results[i];\r                                    Utils->DoOneToOne(this->Instance->Config->ServerName, "PUSH",par, source->server);\r                             }\r                      }\r              }\r              else\r           {\r                      /* Pass it on */\r                       userrec* source = this->Instance->FindNick(prefix);\r                    if (source)\r                            Utils->DoOneToOne(prefix, "STATS", params, params[1]);\r         }\r      }\r      return true;\r}\r\r\r/** Because the core won't let users or even SERVERS set +o,\r * we use the OPERTYPE command to do this.\r */\rbool TreeSocket::OperType(const std::string &prefix, std::deque<std::string> &params)\r{\r   if (params.size() != 1)\r                return true;\r   std::string opertype = params[0];\r      userrec* u = this->Instance->FindNick(prefix);\r if (u)\r {\r              u->modes[UM_OPERATOR] = 1;\r             this->Instance->all_opers.push_back(u);\r                strlcpy(u->oper,opertype.c_str(),NICKMAX-1);\r           Utils->DoOneToAllButSender(u->nick,"OPERTYPE",params,u->server);\r               this->Instance->SNO->WriteToSnoMask('o',"From %s: User %s (%s@%s) is now an IRC operator of type %s",u->server, u->nick,u->ident,u->host,irc::Spacify(opertype.c_str()));\r      }\r      return true;\r}\r\r/** Because Andy insists that services-compatible servers must\r * implement SVSNICK and SVSJOIN, that's exactly what we do :p\r */\rbool TreeSocket::ForceNick(const std::string &prefix, std::deque<std::string> &params)\r{\r     if (params.size() < 3)\r         return true;\r\r  userrec* u = this->Instance->FindNick(params[0]);\r\r     if (u)\r {\r              Utils->DoOneToAllButSender(prefix,"SVSNICK",params,prefix);\r            if (IS_LOCAL(u))\r               {\r                      std::deque<std::string> par;\r                   par.push_back(params[1]);\r                      if (!u->ForceNickChange(params[1].c_str()))\r                    {\r                              userrec::QuitUser(this->Instance, u, "Nickname collision");\r                            return true;\r                   }\r                      u->age = atoi(params[2].c_str());\r              }\r      }\r      return true;\r}\r\rbool TreeSocket::OperQuit(const std::string &prefix, std::deque<std::string> &params)\r{\r        if (params.size() < 1)\r         return true;\r\r  userrec* u = this->Instance->FindNick(prefix);\r\r        if (u)\r {\r              u->SetOperQuit(params[0]);\r             params[0] = ":" + params[0];\r           Utils->DoOneToAllButSender(prefix,"OPERQUIT",params,prefix);\r   }\r      return true;\r}\r\rbool TreeSocket::ServiceJoin(const std::string &prefix, std::deque<std::string> &params)\r{\r     if (params.size() < 2)\r         return true;\r\r  userrec* u = this->Instance->FindNick(params[0]);\r\r     if (u)\r {\r              /* only join if it's local, otherwise just pass it on! */\r              if (IS_LOCAL(u))\r                       chanrec::JoinUser(this->Instance, u, params[1].c_str(), false, "", Instance->Time());\r          Utils->DoOneToAllButSender(prefix,"SVSJOIN",params,prefix);\r    }\r      return true;\r}\r\rbool TreeSocket::RemoteRehash(const std::string &prefix, std::deque<std::string> &params)\r{\r    if (params.size() < 1)\r         return false;\r\r std::string servermask = params[0];\r\r   if (this->Instance->MatchText(this->Instance->Config->ServerName,servermask))\r  {\r              this->Instance->SNO->WriteToSnoMask('l',"Remote rehash initiated by \002"+prefix+"\002.");\r             this->Instance->RehashServer();\r                Utils->ReadConfiguration(false);\r               InitializeDisabledCommands(Instance->Config->DisabledCommands, Instance);\r      }\r      Utils->DoOneToAllButSender(prefix,"REHASH",params,prefix);\r     return true;\r}\r\rbool TreeSocket::RemoteKill(const std::string &prefix, std::deque<std::string> &params)\r{        \r      if (params.size() != 2)\r                return true;\r\r  userrec* who = this->Instance->FindNick(params[0]);\r\r   if (who)\r       {\r              /* Prepend kill source, if we don't have one */          \r              if (*(params[1].c_str()) != '[')\r               {\r                      params[1] = "[" + prefix + "] Killed (" + params[1] +")";\r              }\r              std::string reason = params[1];\r                params[1] = ":" + params[1];\r           Utils->DoOneToAllButSender(prefix,"KILL",params,prefix);\r               // NOTE: This is safe with kill hiding on, as RemoteKill is only reached if we have a server prefix.\r           // in short this is not executed for USERS.\r            who->Write(":%s KILL %s :%s (%s)", prefix.c_str(), who->nick, prefix.c_str(), reason.c_str());\r         userrec::QuitUser(this->Instance,who,reason);\r  }\r      return true;\r}\r\rbool TreeSocket::LocalPong(const std::string &prefix, std::deque<std::string> &params)\r{\r       if (params.size() < 1)\r         return true;\r\r  if (params.size() == 1)\r        {\r              TreeServer* ServerSource = Utils->FindServer(prefix);\r          if (ServerSource)\r              {\r                      ServerSource->SetPingFlag();\r                   ServerSource->rtt = Instance->Time() - ServerSource->LastPing;\r         }\r      }\r      else\r   {\r              std::string forwardto = params[1];\r             if (forwardto == this->Instance->Config->ServerName)\r           {\r                      /*\r                      * this is a PONG for us\r                        * if the prefix is a user, check theyre local, and if they are,\r                        * dump the PONG reply back to their fd. If its a server, do nowt.\r                      * Services might want to send these s->s, but we dont need to yet.\r                     */\r                    userrec* u = this->Instance->FindNick(prefix);\r                 if (u)\r                 {\r                              u->WriteServ("PONG %s %s",params[0].c_str(),params[1].c_str());\r                        }\r              }\r              else\r           {\r                      // not for us, pass it on :)\r                   Utils->DoOneToOne(prefix,"PONG",params,forwardto);\r             }\r      }\r\r     return true;\r}\r\rbool TreeSocket::MetaData(const std::string &prefix, std::deque<std::string> &params)\r{\r        if (params.size() < 2)\r         return true;\r   else if (params.size() < 3)\r            params.push_back("");\r  TreeServer* ServerSource = Utils->FindServer(prefix);\r  if (ServerSource)\r      {\r              Utils->SetRemoteBursting(ServerSource, false);\r\r                if (params[0] == "*")\r          {\r                      FOREACH_MOD_I(this->Instance,I_OnDecodeMetaData,OnDecodeMetaData(TYPE_OTHER,NULL,params[1],params[2]));\r                }\r              else if (*(params[0].c_str()) == '#')\r          {\r                      chanrec* c = this->Instance->FindChan(params[0]);\r                      if (c)\r                 {\r                              FOREACH_MOD_I(this->Instance,I_OnDecodeMetaData,OnDecodeMetaData(TYPE_CHANNEL,c,params[1],params[2]));\r                 }\r              }\r              else if (*(params[0].c_str()) != '#')\r          {\r                      userrec* u = this->Instance->FindNick(params[0]);\r                      if (u)\r                 {\r                              FOREACH_MOD_I(this->Instance,I_OnDecodeMetaData,OnDecodeMetaData(TYPE_USER,u,params[1],params[2]));\r                    }\r              }\r      }\r\r     params[2] = ":" + params[2];\r   Utils->DoOneToAllButSender(prefix,"METADATA",params,prefix);\r   return true;\r}\r\rbool TreeSocket::ServerVersion(const std::string &prefix, std::deque<std::string> &params)\r{\r   if (params.size() < 1)\r         return true;\r\r  TreeServer* ServerSource = Utils->FindServer(prefix);\r\r if (ServerSource)\r      {\r              ServerSource->SetVersion(params[0]);\r   }\r      params[0] = ":" + params[0];\r   Utils->DoOneToAllButSender(prefix,"VERSION",params,prefix);\r    return true;\r}\r\rbool TreeSocket::ChangeHost(const std::string &prefix, std::deque<std::string> &params)\r{\r      if (params.size() < 1)\r         return true;\r   userrec* u = this->Instance->FindNick(prefix);\r\r        if (u)\r {\r              u->ChangeDisplayedHost(params[0].c_str());\r             Utils->DoOneToAllButSender(prefix,"FHOST",params,u->server);\r   }\r      return true;\r}\r\rbool TreeSocket::AddLine(const std::string &prefix, std::deque<std::string> &params)\r{\r if (params.size() < 6)\r         return true;\r   bool propogate = false;\r        if (!this->bursting)\r           Utils->lines_to_apply = 0;\r     switch (*(params[0].c_str()))\r  {\r              case 'Z':\r                      propogate = Instance->XLines->add_zline(atoi(params[4].c_str()), params[2].c_str(), params[5].c_str(), params[1].c_str());\r                     Instance->XLines->zline_set_creation_time(params[1].c_str(), atoi(params[3].c_str()));\r                 if (propogate)\r                         Utils->lines_to_apply |= APPLY_ZLINES;\r         break;\r         case 'Q':\r                      propogate = Instance->XLines->add_qline(atoi(params[4].c_str()), params[2].c_str(), params[5].c_str(), params[1].c_str());\r                     Instance->XLines->qline_set_creation_time(params[1].c_str(), atoi(params[3].c_str()));\r                 if (propogate)\r                         Utils->lines_to_apply |= APPLY_QLINES;\r         break;\r         case 'E':\r                      propogate = Instance->XLines->add_eline(atoi(params[4].c_str()), params[2].c_str(), params[5].c_str(), params[1].c_str());\r                     Instance->XLines->eline_set_creation_time(params[1].c_str(), atoi(params[3].c_str()));\r         break;\r         case 'G':\r                      propogate = Instance->XLines->add_gline(atoi(params[4].c_str()), params[2].c_str(), params[5].c_str(), params[1].c_str());\r                     Instance->XLines->gline_set_creation_time(params[1].c_str(), atoi(params[3].c_str()));\r                 if (propogate)\r                         Utils->lines_to_apply |= APPLY_GLINES;\r         break;\r         case 'K':\r                      propogate = Instance->XLines->add_kline(atoi(params[4].c_str()), params[2].c_str(), params[5].c_str(), params[1].c_str());\r                     if (propogate)\r                         Utils->lines_to_apply |= APPLY_KLINES;\r         break;\r         default:\r                       /* Just in case... */\r                  this->Instance->SNO->WriteToSnoMask('x',"\2WARNING\2: Invalid xline type '"+params[0]+"' sent by server "+prefix+", ignored!");\r                        propogate = false;\r             break;\r }\r      /* Send it on its way */\r       if (propogate)\r {\r              if (atoi(params[4].c_str()))\r           {\r                      time_t c_requires_crap = ConvToInt(params[4]) + Instance->Time();\r                      this->Instance->SNO->WriteToSnoMask('x',"%s Added %cLINE on %s to expire on %s (%s).",prefix.c_str(),*(params[0].c_str()),params[1].c_str(),Instance->TimeString(c_requires_crap).c_str(),params[5].c_str());\r          }\r              else\r           {\r                      this->Instance->SNO->WriteToSnoMask('x',"%s Added permenant %cLINE on %s (%s).",prefix.c_str(),*(params[0].c_str()),params[1].c_str(),params[5].c_str());\r              }\r              params[5] = ":" + params[5];\r           Utils->DoOneToAllButSender(prefix,"ADDLINE",params,prefix);\r    }\r      if (!this->bursting)\r   {\r              Instance->XLines->apply_lines(Utils->lines_to_apply);\r          Utils->lines_to_apply = 0;\r     }\r      return true;\r}\r\rbool TreeSocket::ChangeName(const std::string &prefix, std::deque<std::string> &params)\r{\r      if (params.size() < 1)\r         return true;\r   userrec* u = this->Instance->FindNick(prefix);\r if (u)\r {\r              u->ChangeName(params[0].c_str());\r              params[0] = ":" + params[0];\r           Utils->DoOneToAllButSender(prefix,"FNAME",params,u->server);\r   }\r      return true;\r}\r\rbool TreeSocket::Whois(const std::string &prefix, std::deque<std::string> &params)\r{\r   if (params.size() < 1)\r         return true;\r   userrec* u = this->Instance->FindNick(prefix);\r if (u)\r {\r              // an incoming request\r         if (params.size() == 1)\r                {\r                      userrec* x = this->Instance->FindNick(params[0]);\r                      if ((x) && (IS_LOCAL(x)))\r                      {\r                              userrec* x = this->Instance->FindNick(params[0]);\r                              char signon[MAXBUF];\r                           char idle[MAXBUF];\r                             snprintf(signon, MAXBUF, "%lu", (unsigned long)x->signon);\r                             snprintf(idle, MAXBUF, "%lu", (unsigned long)abs((x->idle_lastmsg) - Instance->Time(true)));\r                           std::deque<std::string> par;\r                           par.push_back(prefix);\r                         par.push_back(signon);\r                         par.push_back(idle);\r                           // ours, we're done, pass it BACK\r                              Utils->DoOneToOne(params[0], "IDLE", par, u->server);\r                  }\r                      else\r                   {\r                              // not ours pass it on\r                         if (x)\r                                 Utils->DoOneToOne(prefix, "IDLE", params, x->server);\r                  }\r              }\r              else if (params.size() == 3)\r           {\r                      std::string who_did_the_whois = params[0];\r                     userrec* who_to_send_to = this->Instance->FindNick(who_did_the_whois);\r                 if ((who_to_send_to) && (IS_LOCAL(who_to_send_to)))\r                    {\r                              // an incoming reply to a whois we sent out\r                            std::string nick_whoised = prefix;\r                             unsigned long signon = atoi(params[1].c_str());\r                                unsigned long idle = atoi(params[2].c_str());\r                          if ((who_to_send_to) && (IS_LOCAL(who_to_send_to)))\r                            {\r                                      do_whois(this->Instance, who_to_send_to, u, signon, idle, nick_whoised.c_str());\r                               }\r                      }\r                      else\r                   {\r                              // not ours, pass it on\r                                if (who_to_send_to)\r                                    Utils->DoOneToOne(prefix, "IDLE", params, who_to_send_to->server);\r                     }\r              }\r      }\r      return true;\r}\r\rbool TreeSocket::Push(const std::string &prefix, std::deque<std::string> &params)\r{\r    if (params.size() < 2)\r         return true;\r   userrec* u = this->Instance->FindNick(params[0]);\r      if (!u)\r                return true;\r   if (IS_LOCAL(u))\r       {\r              u->Write(params[1]);\r   }\r      else\r   {\r              // continue the raw onwards\r            params[1] = ":" + params[1];\r           Utils->DoOneToOne(prefix,"PUSH",params,u->server);\r     }\r      return true;\r}\r\rbool TreeSocket::HandleSetTime(const std::string &prefix, std::deque<std::string> &params)\r{\r   if (!params.size() || !Utils->EnableTimeSync)\r          return true;\r\r  bool force = false;\r\r   if ((params.size() == 2) && (params[1] == "FORCE"))\r            force = true;\r\r time_t them = atoi(params[0].c_str());\r time_t us = Instance->Time(false);\r\r    time_t diff = them - us;\r\r      Utils->DoOneToAllButSender(prefix, "TIMESET", params, prefix);\r\r        if (force || (them != us))\r     {\r              time_t old = Instance->SetTimeDelta(diff);\r             Instance->Log(DEBUG, "TS (diff %d) from %s applied (old delta was %d)", diff, prefix.c_str(), old);\r    }\r\r     return true;\r}\r\rbool TreeSocket::Time(const std::string &prefix, std::deque<std::string> &params)\r{\r    // :source.server TIME remote.server sendernick\r        // :remote.server TIME source.server sendernick TS\r     if (params.size() == 2)\r        {\r              // someone querying our time?\r          if (this->Instance->Config->ServerName == params[0])\r           {\r                      userrec* u = this->Instance->FindNick(params[1]);\r                      if (u)\r                 {\r                              params.push_back(ConvToStr(Instance->Time(false)));\r                            params[0] = prefix;\r                            Utils->DoOneToOne(this->Instance->Config->ServerName,"TIME",params,params[0]);\r                 }\r              }\r              else\r           {\r                      // not us, pass it on\r                  userrec* u = this->Instance->FindNick(params[1]);\r                      if (u)\r                         Utils->DoOneToOne(prefix,"TIME",params,params[0]);\r             }\r      }\r      else if (params.size() == 3)\r   {\r              // a response to a previous TIME\r               userrec* u = this->Instance->FindNick(params[1]);\r              if ((u) && (IS_LOCAL(u)))\r              {\r                      time_t rawtime = atol(params[2].c_str());\r                      struct tm * timeinfo;\r                  timeinfo = localtime(&rawtime);\r                        char tms[26];\r                  snprintf(tms,26,"%s",asctime(timeinfo));\r                       tms[24] = 0;\r                   u->WriteServ("391 %s %s :%s",u->nick,prefix.c_str(),tms);\r              }\r              else\r           {\r                      if (u)\r                         Utils->DoOneToOne(prefix,"TIME",params,u->server);\r             }\r      }\r      return true;\r}\r\rbool TreeSocket::LocalPing(const std::string &prefix, std::deque<std::string> &params)\r{\r       if (params.size() < 1)\r         return true;\r   if (params.size() == 1)\r        {\r              std::string stufftobounce = params[0];\r         this->WriteLine(std::string(":")+this->Instance->Config->ServerName+" PONG "+stufftobounce);\r           return true;\r   }\r      else\r   {\r              std::string forwardto = params[1];\r             if (forwardto == this->Instance->Config->ServerName)\r           {\r                      // this is a ping for us, send back PONG to the requesting server\r                      params[1] = params[0];\r                 params[0] = forwardto;\r                 Utils->DoOneToOne(forwardto,"PONG",params,params[1]);\r          }\r              else\r           {\r                      // not for us, pass it on :)\r                   Utils->DoOneToOne(prefix,"PING",params,forwardto);\r             }\r              return true;\r   }\r}\r\r/** TODO: This creates a total mess of output and needs to really use irc::modestacker.\r */\rbool TreeSocket::RemoveStatus(const std::string &prefix, std::deque<std::string> &params)\r{\r   if (params.size() < 1)\r         return true;\r   chanrec* c = Instance->FindChan(params[0]);\r    if (c)\r {\r              for (char modeletter = 'A'; modeletter <= 'z'; modeletter++)\r           {\r                      ModeHandler* mh = Instance->Modes->FindMode(modeletter, MODETYPE_CHANNEL);\r                     if (mh)\r                                mh->RemoveMode(c);\r             }\r      }\r      return true;\r}\r\rbool TreeSocket::RemoteServer(const std::string &prefix, std::deque<std::string> &params)\r{\r    if (params.size() < 4)\r         return false;\r  std::string servername = params[0];\r    std::string password = params[1];\r      // hopcount is not used for a remote server, we calculate this ourselves\r       std::string description = params[3];\r   TreeServer* ParentOfThis = Utils->FindServer(prefix);\r  if (!ParentOfThis)\r     {\r              this->SendError("Protocol error - Introduced remote server from unknown server "+prefix);\r              return false;\r  }\r      TreeServer* CheckDupe = Utils->FindServer(servername);\r if (CheckDupe)\r {\r              this->SendError("Server "+servername+" already exists!");\r              this->Instance->SNO->WriteToSnoMask('l',"Server \2"+servername+"\2 being introduced from \2" + prefix + "\2 denied, already exists. Closing link with " + prefix);\r             return false;\r  }\r      Link* lnk = Utils->FindLink(servername);\r       TreeServer* Node = new TreeServer(this->Utils,this->Instance,servername,description,ParentOfThis,NULL, lnk ? lnk->Hidden : false);\r     ParentOfThis->AddChild(Node);\r  params[3] = ":" + params[3];\r   Utils->SetRemoteBursting(Node, true);\r  Utils->DoOneToAllButSender(prefix,"SERVER",params,prefix);\r     this->Instance->SNO->WriteToSnoMask('l',"Server \002"+prefix+"\002 introduced server \002"+servername+"\002 ("+description+")");\r       return true;\r}\r\rbool TreeSocket::ComparePass(const std::string &ours, const std::string &theirs)\r{\r     if ((!strncmp(ours.c_str(), "HMAC-SHA256:", 12)) || (!strncmp(theirs.c_str(), "HMAC-SHA256:", 12)))\r    {\r              /* One or both of us specified hmac sha256, but we don't have sha256 module loaded!\r             * We can't allow this password as valid.\r               */\r            if (!Instance->FindModule("m_sha256.so") || !Utils->ChallengeResponse)\r                         return false;\r          else\r                   /* Straight string compare of hashes */\r                        return ours == theirs;\r }\r      else\r           /* Straight string compare of plaintext */\r             return ours == theirs;\r}\r\rbool TreeSocket::Outbound_Reply_Server(std::deque<std::string> &params)\r{\r    if (params.size() < 4)\r         return false;\r\r irc::string servername = params[0].c_str();\r    std::string sname = params[0];\r std::string password = params[1];\r      std::string description = params[3];\r   int hops = atoi(params[2].c_str());\r\r   this->InboundServerName = sname;\r       this->InboundDescription = description;\r\r       if (!sentcapab)\r                this->SendCapabilities();\r\r     if (hops)\r      {\r              this->SendError("Server too far away for authentication");\r             this->Instance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, server is too far away for authentication");\r             return false;\r  }\r\r     for (std::vector<Link>::iterator x = Utils->LinkBlocks.begin(); x < Utils->LinkBlocks.end(); x++)\r      {\r              if ((x->Name == servername) && ((ComparePass(this->MakePass(x->RecvPass,this->GetOurChallenge()),password)) || (x->RecvPass == password && (this->GetTheirChallenge().empty()))))\r              {\r                      TreeServer* CheckDupe = Utils->FindServer(sname);\r                      if (CheckDupe)\r                 {\r                              this->SendError("Server "+sname+" already exists on server "+CheckDupe->GetParent()->GetName()+"!");\r                           this->Instance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, already exists on server "+CheckDupe->GetParent()->GetName());\r                           return false;\r                  }\r                      // Begin the sync here. this kickstarts the\r                    // other side, waiting in WAIT_AUTH_2 state,\r                   // into starting their burst, as it shows\r                      // that we're happy.\r                   this->LinkState = CONNECTED;\r                   // we should add the details of this server now\r                        // to the servers tree, as a child of the root\r                 // node.\r                       TreeServer* Node = new TreeServer(this->Utils,this->Instance,sname,description,Utils->TreeRoot,this,x->Hidden);\r                        Utils->TreeRoot->AddChild(Node);\r                       params[3] = ":" + params[3];\r                   Utils->DoOneToAllButSender(Utils->TreeRoot->GetName(),"SERVER",params,sname);\r                  this->bursting = true;\r                 this->DoBurst(Node);\r                   return true;\r           }\r      }\r      this->SendError("Invalid credentials");\r        this->Instance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, invalid link credentials");\r      return false;\r}\r\rbool TreeSocket::Inbound_Server(std::deque<std::string> &params)\r{\r    if (params.size() < 4)\r         return false;\r  irc::string servername = params[0].c_str();\r    std::string sname = params[0];\r std::string password = params[1];\r      std::string description = params[3];\r   int hops = atoi(params[2].c_str());\r\r   this->InboundServerName = sname;\r       this->InboundDescription = description;\r\r       if (!sentcapab)\r                this->SendCapabilities();\r\r     if (hops)\r      {\r              this->SendError("Server too far away for authentication");\r             this->Instance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, server is too far away for authentication");\r             return false;\r  }\r\r     for (std::vector<Link>::iterator x = Utils->LinkBlocks.begin(); x < Utils->LinkBlocks.end(); x++)\r      {\r              if ((x->Name == servername) && ((ComparePass(this->MakePass(x->RecvPass,this->GetOurChallenge()),password) || x->RecvPass == password && (this->GetTheirChallenge().empty()))))\r                {\r                      /* First check for instances of the server that are waiting between the inbound and outbound SERVER command */\r                 TreeSocket* CheckDupeSocket = Utils->FindBurstingServer(sname);\r                        if (CheckDupeSocket)\r                   {\r                              /* If we find one, we abort the link to prevent a race condition */\r                            this->SendError("Negotiation collision");\r                              this->Instance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, already exists in a negotiating state.");\r                                CheckDupeSocket->SendError("Negotiation collision");\r                           Instance->SE->DelFd(CheckDupeSocket);\r                          CheckDupeSocket->Close();\r                              delete CheckDupeSocket;\r                                return false;\r                  }\r                      /* Now check for fully initialized instances of the server */\r                  TreeServer* CheckDupe = Utils->FindServer(sname);\r                      if (CheckDupe)\r                 {\r                              this->SendError("Server "+sname+" already exists on server "+CheckDupe->GetParent()->GetName()+"!");\r                           this->Instance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, already exists on server "+CheckDupe->GetParent()->GetName());\r                           return false;\r                  }\r                      this->Instance->SNO->WriteToSnoMask('l',"Verified incoming server connection from \002"+sname+"\002["+(x->HiddenFromStats ? "<hidden>" : this->GetIP())+"] ("+description+")");\r                        if (this->Hook)\r                        {\r                              std::string name = InspSocketNameRequest((Module*)Utils->Creator, this->Hook).Send();\r                          this->Instance->SNO->WriteToSnoMask('l',"Connection from \2"+sname+"\2["+(x->HiddenFromStats ? "<hidden>" : this->GetIP())+"] using transport \2"+name+"\2");\r                  }\r\r                     Utils->AddBurstingServer(sname,this);\r\r                 // this is good. Send our details: Our server name and description and hopcount of 0,\r                  // along with the sendpass from this block.\r                    this->WriteLine(std::string("SERVER ")+this->Instance->Config->ServerName+" "+this->MakePass(x->SendPass, this->GetTheirChallenge())+" 0 :"+this->Instance->Config->ServerDesc);\r                       // move to the next state, we are now waiting for THEM.\r                        this->LinkState = WAIT_AUTH_2;\r                 return true;\r           }\r      }\r      this->SendError("Invalid credentials");\r        this->Instance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, invalid link credentials");\r      return false;\r}\r\rvoid TreeSocket::Split(const std::string &line, std::deque<std::string> &n)\r{\r n.clear();\r     irc::tokenstream tokens(line);\r std::string param;\r     while (tokens.GetToken(param))\r {\r              if (!param.empty())\r                    n.push_back(param);\r    }\r      return;\r}\r\rbool TreeSocket::ProcessLine(std::string &line)\r{\r   std::deque<std::string> params;\r        irc::string command;\r   std::string prefix;\r\r   line = line.substr(0, line.find_first_of("\r\n"));\r\r    if (line.empty())\r              return true;\r\r  Instance->Log(DEBUG, "S[%d] <- %s", this->GetFd(), line.c_str());\r\r     this->Split(line.c_str(),params);\r      \r       if (params.empty())\r            return true;\r   \r       if ((params[0][0] == ':') && (params.size() > 1))\r      {\r              prefix = params[0].substr(1);\r          params.pop_front();\r    }\r      command = params[0].c_str();\r   params.pop_front();\r    switch (this->LinkState)\r       {\r              TreeServer* Node;\r\r             case WAIT_AUTH_1:\r                      // Waiting for SERVER command from remote server. Server initiating\r                    // the connection sends the first SERVER command, listening server\r                     // replies with theirs if its happy, then if the initiator is happy,\r                   // it starts to send its net sync, which starts the merge, otherwise\r                   // it sends an ERROR.\r                  if (command == "PASS")\r                 {\r                              /* Silently ignored */\r                 }\r                      else if (command == "SERVER")\r                  {\r                              return this->Inbound_Server(params);\r                   }\r                      else if (command == "ERROR")\r                   {\r                              return this->Error(params);\r                    }\r                      else if (command == "USER")\r                    {\r                              this->SendError("Client connections to this port are prohibited.");\r                            return false;\r                  }\r                      else if (command == "CAPAB")\r                   {\r                              return this->Capab(params);\r                    }\r                      else if ((command == "U") || (command == "S"))\r                 {\r                              this->SendError("Cannot use the old-style mesh linking protocol with m_spanningtree.so!");\r                             return false;\r                  }\r                      else\r                   {\r                              irc::string error = "Invalid command in negotiation phase: " + command;\r                                this->SendError(assign(error));\r                                return false;\r                  }\r              break;\r         case WAIT_AUTH_2:\r                      // Waiting for start of other side's netmerge to say they liked our\r                    // password.\r                   if (command == "SERVER")\r                       {\r                              // cant do this, they sent it to us in the WAIT_AUTH_1 state!\r                          // silently ignore.\r                            return true;\r                   }\r                      else if ((command == "U") || (command == "S"))\r                 {\r                              this->SendError("Cannot use the old-style mesh linking protocol with m_spanningtree.so!");\r                             return false;\r                  }\r                      else if (command == "BURST")\r                   {\r                              if (params.size() && Utils->EnableTimeSync)\r                            {\r                                      bool we_have_delta = (Instance->Time(false) != Instance->Time(true));\r                                  time_t them = atoi(params[0].c_str());\r                                 time_t delta = them - Instance->Time(false);\r                                   if ((delta < -300) || (delta > 300))\r                                   {\r                                              Instance->SNO->WriteToSnoMask('l',"\2ERROR\2: Your clocks are out by %d seconds (this is more than five minutes). Link aborted, \2PLEASE SYNC YOUR CLOCKS!\2",abs(delta));\r                                             SendError("Your clocks are out by "+ConvToStr(abs(delta))+" seconds (this is more than five minutes). Link aborted, PLEASE SYNC YOUR CLOCKS!");\r                                                return false;\r                                  }\r                                      else if ((delta < -30) || (delta > 30))\r                                        {\r                                              Instance->SNO->WriteToSnoMask('l',"\2WARNING\2: Your clocks are out by %d seconds. Please consider synching your clocks.", abs(delta));\r                                        }\r\r                                     if (!Utils->MasterTime && !we_have_delta)\r                                      {\r                                              this->Instance->SetTimeDelta(delta);\r                                           // Send this new timestamp to any other servers\r                                                Utils->DoOneToMany(Utils->TreeRoot->GetName(), "TIMESET", params);\r                                     }\r                              }\r                              this->LinkState = CONNECTED;\r                           Link* lnk = Utils->FindLink(InboundServerName);\r                                Node = new TreeServer(this->Utils,this->Instance, InboundServerName, InboundDescription, Utils->TreeRoot, this, lnk ? lnk->Hidden : false);\r                            Utils->DelBurstingServer(this);\r                                Utils->TreeRoot->AddChild(Node);\r                               params.clear();\r                                params.push_back(InboundServerName);\r                           params.push_back("*");\r                         params.push_back("1");\r                         params.push_back(":"+InboundDescription);\r                              Utils->DoOneToAllButSender(Utils->TreeRoot->GetName(),"SERVER",params,InboundServerName);\r                              this->bursting = true;\r                         this->DoBurst(Node);\r                   }\r                      else if (command == "ERROR")\r                   {\r                              return this->Error(params);\r                    }\r                      else if (command == "CAPAB")\r                   {\r                              return this->Capab(params);\r                    }\r\r             break;\r         case LISTENER:\r                 this->SendError("Internal error -- listening socket accepted its own descriptor!!!");\r                  return false;\r          break;\r         case CONNECTING:\r                       if (command == "SERVER")\r                       {\r                              // another server we connected to, which was in WAIT_AUTH_1 state,\r                             // has just sent us their credentials. If we get this far, theyre\r                              // happy with OUR credentials, and they are now in WAIT_AUTH_2 state.\r                          // if we're happy with this, we should send our netburst which\r                         // kickstarts the merge.\r                               return this->Outbound_Reply_Server(params);\r                    }\r                      else if (command == "ERROR")\r                   {\r                              return this->Error(params);\r                    }\r                      else if (command == "CAPAB")\r                   {\r                              return this->Capab(params);\r                    }\r              break;\r         case CONNECTED:\r                        // This is the 'authenticated' state, when all passwords\r                       // have been exchanged and anything past this point is taken\r                   // as gospel.\r\r                 if (!prefix.empty())\r                   {\r                              std::string direction = prefix;\r                                userrec* t = this->Instance->FindNick(prefix);\r                         if (t)\r                         {\r                                      direction = t->server;\r                         }\r                              TreeServer* route_back_again = Utils->BestRouteTo(direction);\r                          if ((!route_back_again) || (route_back_again->GetSocket() != this))\r                            {\r                                      if (route_back_again)\r                                          Instance->Log(DEBUG,"Protocol violation: Fake direction in command '%s' from connection '%s'",line.c_str(),this->GetName().c_str());\r                                   return true;\r                           }\r                              /* Fix by brain:\r                                * When there is activity on the socket, reset the ping counter so\r                              * that we're not wasting bandwidth pinging an active server.\r                           */\r                            route_back_again->SetNextPingTime(time(NULL) + 60);\r                            route_back_again->SetPingFlag();\r                       }\r                      else\r                   {\r                              prefix = this->GetName();\r                      }\r\r                     if ((command == "MODE") && (params.size() >= 2))\r                       {\r                              chanrec* channel = Instance->FindChan(params[0]);\r                              if (channel)\r                           {\r                                      userrec* x = Instance->FindNick(prefix);\r                                       if (x)\r                                 {\r                                              if (warned.find(x->server) == warned.end())\r                                            {\r                                                      Instance->Log(DEFAULT,"WARNING: I revceived modes '%s' from another server '%s'. This is not compliant with InspIRCd. Please check that server for bugs.", params[1].c_str(), x->server);\r                                                      Instance->SNO->WriteToSnoMask('d', "WARNING: The server %s is sending nonstandard modes: '%s MODE %s' where FMODE should be used, and may cause desyncs.", x->server, x->nick, params[1].c_str());\r                                                     warned[x->server] = x->nick;\r                                           }\r                                      }\r                              }\r                      }\r\r                     if (command == "SVSMODE")\r                      {\r                              /* Services expects us to implement\r                             * SVSMODE. In inspircd its the same as\r                                 * MODE anyway.\r                                 */\r                            command = "MODE";\r                      }\r                      std::string target;\r                    /* Yes, know, this is a mess. Its reasonably fast though as we're\r                       * working with std::string here.\r                       */\r                    if ((command == "NICK") && (params.size() >= 8))\r                       {\r                              return this->IntroduceClient(prefix,params);\r                   }\r                      else if (command == "FJOIN")\r                   {\r                              TreeServer* ServerSource = Utils->FindServer(prefix);\r                          if (ServerSource)\r                                      Utils->SetRemoteBursting(ServerSource, false);\r                         return this->ForceJoin(prefix,params);\r                 }\r                      else if (command == "STATS")\r                   {\r                              return this->Stats(prefix, params);\r                    }\r                      else if (command == "MOTD")\r                    {\r                              return this->Motd(prefix, params);\r                     }\r                      else if (command == "KILL" && Utils->IsServer(prefix))\r                 {\r                              return this->RemoteKill(prefix,params);\r                        }\r                      else if (command == "MODULES")\r                 {\r                              return this->Modules(prefix, params);\r                  }\r                      else if (command == "ADMIN")\r                   {\r                              return this->Admin(prefix, params);\r                    }\r                      else if (command == "SERVER")\r                  {\r                              return this->RemoteServer(prefix,params);\r                      }\r                      else if (command == "ERROR")\r                   {\r                              return this->Error(params);\r                    }\r                      else if (command == "OPERTYPE")\r                        {\r                              return this->OperType(prefix,params);\r                  }\r                      else if (command == "FMODE")\r                   {\r                              TreeServer* ServerSource = Utils->FindServer(prefix);\r                          if (ServerSource)\r                                      Utils->SetRemoteBursting(ServerSource, false);\r                         return this->ForceMode(prefix,params);\r                 }\r                      else if (command == "FTOPIC")\r                  {\r                              return this->ForceTopic(prefix,params);\r                        }\r                      else if (command == "REHASH")\r                  {\r                              return this->RemoteRehash(prefix,params);\r                      }\r                      else if (command == "METADATA")\r                        {\r                              return this->MetaData(prefix,params);\r                  }\r                      else if (command == "REMSTATUS")\r                       {\r                              return this->RemoveStatus(prefix,params);\r                      }\r                      else if (command == "PING")\r                    {\r                              if (prefix.empty())\r                                    prefix = this->GetName();\r                              /*\r                              * We just got a ping from a server that's bursting.\r                            * This can't be right, so set them to not bursting, and\r                                * apply their lines.\r                           */\r                            TreeServer* ServerSource = Utils->FindServer(prefix);\r                          if (ServerSource)\r                                      Utils->SetRemoteBursting(ServerSource, false);\r\r                                if (this->bursting)\r                            {\r                                      this->bursting = false;\r                                        Instance->XLines->apply_lines(Utils->lines_to_apply);\r                                  Utils->lines_to_apply = 0;\r                             }\r\r                             return this->LocalPing(prefix,params);\r                 }\r                      else if (command == "PONG")\r                    {\r                              if (prefix.empty())\r                                    prefix = this->GetName();\r                              /*\r                              * We just got a pong from a server that's bursting.\r                            * This can't be right, so set them to not bursting, and\r                                * apply their lines.\r                           */\r                            TreeServer* ServerSource = Utils->FindServer(prefix);\r                          if (ServerSource)\r                                      Utils->SetRemoteBursting(ServerSource, false);\r\r                                if (this->bursting)\r                            {\r                                      this->bursting = false;\r                                        Instance->XLines->apply_lines(Utils->lines_to_apply);\r                                  Utils->lines_to_apply = 0;\r                             }\r\r                             return this->LocalPong(prefix,params);\r                 }\r                      else if (command == "VERSION")\r                 {\r                              return this->ServerVersion(prefix,params);\r                     }\r                      else if (command == "FHOST")\r                   {\r                              return this->ChangeHost(prefix,params);\r                        }\r                      else if (command == "FNAME")\r                   {\r                              return this->ChangeName(prefix,params);\r                        }\r                      else if (command == "ADDLINE")\r                 {\r                              TreeServer* ServerSource = Utils->FindServer(prefix);\r                          if (ServerSource)\r                                      Utils->SetRemoteBursting(ServerSource, false);\r                         return this->AddLine(prefix,params);\r                   }\r                      else if (command == "SVSNICK")\r                 {\r                              if (prefix.empty())\r                            {\r                                      prefix = this->GetName();\r                              }\r                              return this->ForceNick(prefix,params);\r                 }\r                      else if (command == "OPERQUIT")\r                        {\r                              return this->OperQuit(prefix,params);\r                  }\r                      else if (command == "IDLE")\r                    {\r                              return this->Whois(prefix,params);\r                     }\r                      else if (command == "PUSH")\r                    {\r                              return this->Push(prefix,params);\r                      }\r                      else if (command == "TIMESET")\r                 {\r                              return this->HandleSetTime(prefix, params);\r                    }\r                      else if (command == "TIME")\r                    {\r                              return this->Time(prefix,params);\r                      }\r                      else if ((command == "KICK") && (Utils->IsServer(prefix)))\r                     {\r                              std::string sourceserv = this->myhost;\r                         if (params.size() == 3)\r                                {\r                                      userrec* user = this->Instance->FindNick(params[1]);\r                                   chanrec* chan = this->Instance->FindChan(params[0]);\r                                   if (user && chan)\r                                      {\r                                              if (!chan->ServerKickUser(user, params[2].c_str(), false))\r                                                     /* Yikes, the channels gone! */\r                                                        delete chan;\r                                   }\r                              }\r                              if (!this->InboundServerName.empty())\r                          {\r                                      sourceserv = this->InboundServerName;\r                          }\r                              return Utils->DoOneToAllButSenderRaw(line,sourceserv,prefix,command,params);\r                   }\r                      else if (command == "SVSJOIN")\r                 {\r                              if (prefix.empty())\r                            {\r                                      prefix = this->GetName();\r                              }\r                              return this->ServiceJoin(prefix,params);\r                       }\r                      else if (command == "SQUIT")\r                   {\r                              if (params.size() == 2)\r                                {\r                                      this->Squit(Utils->FindServer(params[0]),params[1]);\r                           }\r                              return true;\r                   }\r                      else if (command == "OPERNOTICE")\r                      {\r                              std::string sourceserv = this->myhost;\r                         if (!this->InboundServerName.empty())\r                                  sourceserv = this->InboundServerName;\r                          if (params.size() >= 1)\r                                        Instance->WriteOpers("*** From " + sourceserv + ": " + params[0]);\r                             return Utils->DoOneToAllButSenderRaw(line, sourceserv, prefix, command, params);\r                       }\r                      else if (command == "MODENOTICE")\r                      {\r                              std::string sourceserv = this->myhost;\r                         if (!this->InboundServerName.empty())\r                                  sourceserv = this->InboundServerName;\r                          if (params.size() >= 2)\r                                {\r                                      Instance->WriteMode(params[0].c_str(), WM_AND, "*** From %s: %s", sourceserv.c_str(), params[1].c_str());\r                              }\r                              return Utils->DoOneToAllButSenderRaw(line, sourceserv, prefix, command, params);\r                       }\r                      else if (command == "SNONOTICE")\r                       {\r                              std::string sourceserv = this->myhost;\r                         if (!this->InboundServerName.empty())\r                                  sourceserv = this->InboundServerName;\r                          if (params.size() >= 2)\r                                {\r                                      Instance->SNO->WriteToSnoMask(*(params[0].c_str()), "From " + sourceserv + ": "+ params[1]);\r                           }\r                              return Utils->DoOneToAllButSenderRaw(line, sourceserv, prefix, command, params);\r                       }\r                      else if (command == "ENDBURST")\r                        {\r                              this->bursting = false;\r                                Instance->XLines->apply_lines(Utils->lines_to_apply);\r                          Utils->lines_to_apply = 0;\r                             std::string sourceserv = this->myhost;\r                         if (!this->InboundServerName.empty())\r                                  sourceserv = this->InboundServerName;\r                          this->Instance->SNO->WriteToSnoMask('l',"Received end of netburst from \2%s\2",sourceserv.c_str());\r\r                           Event rmode((char*)sourceserv.c_str(), (Module*)Utils->Creator, "new_server");\r                         rmode.Send(Instance);\r\r                         return true;\r                   }\r                      else\r                   {\r                              // not a special inter-server command.\r                         // Emulate the actual user doing the command,\r                          // this saves us having a huge ugly parser.\r                            userrec* who = this->Instance->FindNick(prefix);\r                               std::string sourceserv = this->myhost;\r                         if (!this->InboundServerName.empty())\r                          {\r                                      sourceserv = this->InboundServerName;\r                          }\r                              if ((!who) && (command == "MODE"))\r                             {\r                                      if (Utils->IsServer(prefix))\r                                   {\r                                              const char* modelist[127];\r                                             for (size_t i = 0; i < params.size(); i++)\r                                                     modelist[i] = params[i].c_str();\r                                               userrec* fake = new userrec(Instance);\r                                         fake->SetFd(FD_MAGIC_NUMBER);\r                                          this->Instance->SendMode(modelist, params.size(), fake);\r\r                                              delete fake;\r                                           /* Hot potato! pass it on! */\r                                          return Utils->DoOneToAllButSenderRaw(line,sourceserv,prefix,command,params);\r                                   }\r                              }\r                              if (who)\r                               {\r                                      if ((command == "NICK") && (params.size() > 0))\r                                        {\r                                              /* On nick messages, check that the nick doesnt\r                                                 * already exist here. If it does, kill their copy,\r                                             * and our copy.\r                                                */\r                                            userrec* x = this->Instance->FindNick(params[0]);\r                                              if ((x) && (x != who))\r                                         {\r                                                      std::deque<std::string> p;\r                                                     p.push_back(params[0]);\r                                                        p.push_back("Nickname collision ("+prefix+" -> "+params[0]+")");\r                                                       Utils->DoOneToMany(this->Instance->Config->ServerName,"KILL",p);\r                                                       p.clear();\r                                                     p.push_back(prefix);\r                                                   p.push_back("Nickname collision");\r                                                     Utils->DoOneToMany(this->Instance->Config->ServerName,"KILL",p);\r                                                       userrec::QuitUser(this->Instance,x,"Nickname collision ("+prefix+" -> "+params[0]+")");\r                                                        userrec* y = this->Instance->FindNick(prefix);\r                                                 if (y)\r                                                 {\r                                                              userrec::QuitUser(this->Instance,y,"Nickname collision");\r                                                      }\r                                                      return Utils->DoOneToAllButSenderRaw(line,sourceserv,prefix,command,params);\r                                           }\r                                      }\r                                      // its a user\r                                  target = who->server;\r                                  const char* strparams[127];\r                                    for (unsigned int q = 0; q < params.size(); q++)\r                                       {\r                                              strparams[q] = params[q].c_str();\r                                      }\r                                      switch (this->Instance->CallCommandHandler(command.c_str(), strparams, params.size(), who))\r                                    {\r                                              case CMD_INVALID:\r                                                      this->SendError("Unrecognised command '"+std::string(command.c_str())+"' -- possibly loaded mismatched modules");\r                                                      return false;\r                                          break;\r                                         case CMD_FAILURE:\r                                                      return true;\r                                           break;\r                                         default:\r                                                       /* CMD_SUCCESS and CMD_USER_DELETED fall through here */\r                                               break;\r                                 }\r                              }\r                              else\r                           {\r                                      // its not a user. Its either a server, or somethings screwed up.\r                                      if (Utils->IsServer(prefix))\r                                           target = this->Instance->Config->ServerName;\r                                   else\r                                           return true;\r                           }\r                              return Utils->DoOneToAllButSenderRaw(line,sourceserv,prefix,command,params);\r\r                  }\r                      return true;\r           break;\r }\r      return true;\r}\r\rstd::string TreeSocket::GetName()\r{\r    std::string sourceserv = this->myhost;\r if (!this->InboundServerName.empty())\r  {\r              sourceserv = this->InboundServerName;\r  }\r      return sourceserv;\r}\r\rvoid TreeSocket::OnTimeout()\r{\r   if (this->LinkState == CONNECTING)\r     {\r              this->Instance->SNO->WriteToSnoMask('l',"CONNECT: Connection to \002"+myhost+"\002 timed out.");\r               Link* MyLink = Utils->FindLink(myhost);\r                if (MyLink)\r                    Utils->DoFailOver(MyLink);\r     }\r}\r\rvoid TreeSocket::OnClose()\r{\r      // Connection closed.\r  // If the connection is fully up (state CONNECTED)\r     // then propogate a netsplit to all peers.\r     std::string quitserver = this->myhost;\r if (!this->InboundServerName.empty())\r  {\r              quitserver = this->InboundServerName;\r  }\r      TreeServer* s = Utils->FindServer(quitserver);\r if (s)\r {\r              Squit(s,"Remote host closed the connection");\r  }\r\r     if (!quitserver.empty())\r       {\r              this->Instance->SNO->WriteToSnoMask('l',"Connection to '\2%s\2' failed.",quitserver.c_str());\r          time_t server_uptime = Instance->Time() - this->age;    \r               if (server_uptime)\r                     Instance->SNO->WriteToSnoMask('l',"Connection to '\2%s\2' was established for %s", quitserver.c_str(), Utils->Creator->TimeToStr(server_uptime).c_str());\r      }\r}\r\rint TreeSocket::OnIncomingConnection(int newsock, char* ip)\r{\r     /* To prevent anyone from attempting to flood opers/DDoS by connecting to the server port,\r      * or discovering if this port is the server port, we don't allow connections from any\r  * IPs for which we don't have a link block.\r    */\r    bool found = false;\r\r   found = (std::find(Utils->ValidIPs.begin(), Utils->ValidIPs.end(), ip) != Utils->ValidIPs.end());\r      if (!found)\r    {\r              for (vector<std::string>::iterator i = Utils->ValidIPs.begin(); i != Utils->ValidIPs.end(); i++)\r                       if (irc::sockets::MatchCIDR(ip, (*i).c_str()))\r                         found = true;\r\r         if (!found)\r            {\r                      this->Instance->SNO->WriteToSnoMask('l',"Server connection from %s denied (no link blocks with that IP address)", ip);\r                 close(newsock);\r                        return false;\r          }\r      }\r\r     TreeSocket* s = new TreeSocket(this->Utils, this->Instance, newsock, ip, this->Hook);\r  s = s; /* Whinge whinge whinge, thats all GCC ever does. */\r    return true;\r}\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "configreader.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+#include "commands/cmd_whois.h"
+#include "commands/cmd_stats.h"
+#include "socket.h"
+#include "wildcard.h"
+#include "xline.h"
+#include "transport.h"
+#include "socketengine.h"
+
+#include "m_spanningtree/main.h"
+#include "m_spanningtree/utils.h"
+#include "m_spanningtree/treeserver.h"
+#include "m_spanningtree/link.h"
+#include "m_spanningtree/treesocket.h"
+#include "m_spanningtree/resolvers.h"
+#include "m_spanningtree/handshaketimer.h"
+
+/* $ModDep: m_spanningtree/timesynctimer.h m_spanningtree/resolvers.h m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/link.h m_spanningtree/treesocket.h */
+
+static std::map<std::string, std::string> warned;       /* Server names that have had protocol violation warnings displayed for them */
+
+int TreeSocket::WriteLine(std::string line)
+{
+       Instance->Log(DEBUG, "S[%d] -> %s", this->GetFd(), line.c_str());
+       line.append("\r\n");
+       return this->Write(line);
+}
+
+
+/* Handle ERROR command */
+bool TreeSocket::Error(std::deque<std::string> &params)
+{
+       if (params.size() < 1)
+               return false;
+       this->Instance->SNO->WriteToSnoMask('l',"ERROR from %s: %s",(!InboundServerName.empty() ? InboundServerName.c_str() : myhost.c_str()),params[0].c_str());
+       /* we will return false to cause the socket to close. */
+       return false;
+}
+
+bool TreeSocket::Modules(const std::string &prefix, std::deque<std::string> &params)
+{
+       if (params.empty())
+               return true;
+
+       if (!this->Instance->MatchText(this->Instance->Config->ServerName, params[0]))
+       {
+               /* Pass it on, not for us */
+               Utils->DoOneToOne(prefix, "MODULES", params, params[0]);
+               return true;
+       }
+
+       char strbuf[MAXBUF];
+       std::deque<std::string> par;
+       par.push_back(prefix);
+       par.push_back("");
+
+       userrec* source = this->Instance->FindNick(prefix);
+       if (!source)
+               return true;
+
+       for (unsigned int i = 0; i < Instance->Config->module_names.size(); i++)
+       {
+               Version V = Instance->modules[i]->GetVersion();
+               char modulename[MAXBUF];
+               char flagstate[MAXBUF];
+               *flagstate = 0;
+               if (V.Flags & VF_STATIC)
+                       strlcat(flagstate,", static",MAXBUF);
+               if (V.Flags & VF_VENDOR)
+                       strlcat(flagstate,", vendor",MAXBUF);
+               if (V.Flags & VF_COMMON)
+                       strlcat(flagstate,", common",MAXBUF);
+               if (V.Flags & VF_SERVICEPROVIDER)
+                       strlcat(flagstate,", service provider",MAXBUF);
+               if (!flagstate[0])
+                       strcpy(flagstate,"  <no flags>");
+               strlcpy(modulename,Instance->Config->module_names[i].c_str(),256);
+               if (*source->oper)
+               {
+                       snprintf(strbuf, MAXBUF, "::%s 900 %s :0x%08lx %d.%d.%d.%d %s (%s)",Instance->Config->ServerName,source->nick,(long unsigned int)Instance->modules[i],V.Major,V.Minor,V.Revision,V.Build,ServerConfig::CleanFilename(modulename),flagstate+2);
+               }
+               else
+               {
+                       snprintf(strbuf, MAXBUF, "::%s 900 %s :%s",Instance->Config->ServerName,source->nick,ServerConfig::CleanFilename(modulename));
+               }
+               par[1] = strbuf;
+               Utils->DoOneToOne(Instance->Config->ServerName, "PUSH", par, source->server);
+       }
+       snprintf(strbuf, MAXBUF, "::%s 901 %s :End of MODULES list", Instance->Config->ServerName, source->nick);
+       par[1] = strbuf;
+       Utils->DoOneToOne(Instance->Config->ServerName, "PUSH", par, source->server);
+       return true;
+}
+
+/** remote MOTD. leet, huh? */
+bool TreeSocket::Motd(const std::string &prefix, std::deque<std::string> &params)
+{
+       if (params.size() > 0)
+       {
+               if (this->Instance->MatchText(this->Instance->Config->ServerName, params[0]))
+               {
+                       /* It's for our server */
+                       string_list results;
+                       userrec* source = this->Instance->FindNick(prefix);
+
+                       if (source)
+                       {
+                               std::deque<std::string> par;
+                               par.push_back(prefix);
+                               par.push_back("");
+
+                               if (!Instance->Config->MOTD.size())
+                               {
+                                       par[1] = std::string("::")+Instance->Config->ServerName+" 422 "+source->nick+" :Message of the day file is missing.";
+                                       Utils->DoOneToOne(this->Instance->Config->ServerName, "PUSH",par, source->server);
+                                       return true;
+                               }
+
+                               par[1] = std::string("::")+Instance->Config->ServerName+" 375 "+source->nick+" :"+Instance->Config->ServerName+" message of the day";
+                               Utils->DoOneToOne(this->Instance->Config->ServerName, "PUSH",par, source->server);
+
+                               for (unsigned int i = 0; i < Instance->Config->MOTD.size(); i++)
+                               {
+                                       par[1] = std::string("::")+Instance->Config->ServerName+" 372 "+source->nick+" :- "+Instance->Config->MOTD[i];
+                                       Utils->DoOneToOne(this->Instance->Config->ServerName, "PUSH",par, source->server);
+                               }
+
+                               par[1] = std::string("::")+Instance->Config->ServerName+" 376 "+source->nick+" End of message of the day.";
+                               Utils->DoOneToOne(this->Instance->Config->ServerName, "PUSH",par, source->server);
+                       }
+               }
+               else
+               {
+                       /* Pass it on */
+                       userrec* source = this->Instance->FindNick(prefix);
+                       if (source)
+                               Utils->DoOneToOne(prefix, "MOTD", params, params[0]);
+               }
+       }
+       return true;
+}
+
+/** remote ADMIN. leet, huh? */
+bool TreeSocket::Admin(const std::string &prefix, std::deque<std::string> &params)
+{
+       if (params.size() > 0)
+       {
+               if (this->Instance->MatchText(this->Instance->Config->ServerName, params[0]))
+               {
+                       /* It's for our server */
+                       string_list results;
+                       userrec* source = this->Instance->FindNick(prefix);
+                       if (source)
+                       {
+                               std::deque<std::string> par;
+                               par.push_back(prefix);
+                               par.push_back("");
+                               par[1] = std::string("::")+Instance->Config->ServerName+" 256 "+source->nick+" :Administrative info for "+Instance->Config->ServerName;
+                               Utils->DoOneToOne(this->Instance->Config->ServerName, "PUSH",par, source->server);
+                               par[1] = std::string("::")+Instance->Config->ServerName+" 257 "+source->nick+" :Name     - "+Instance->Config->AdminName;
+                               Utils->DoOneToOne(this->Instance->Config->ServerName, "PUSH",par, source->server);
+                               par[1] = std::string("::")+Instance->Config->ServerName+" 258 "+source->nick+" :Nickname - "+Instance->Config->AdminNick;
+                               Utils->DoOneToOne(this->Instance->Config->ServerName, "PUSH",par, source->server);
+                               par[1] = std::string("::")+Instance->Config->ServerName+" 258 "+source->nick+" :E-Mail   - "+Instance->Config->AdminEmail;
+                               Utils->DoOneToOne(this->Instance->Config->ServerName, "PUSH",par, source->server);
+                       }
+               }
+               else
+               {
+                       /* Pass it on */
+                       userrec* source = this->Instance->FindNick(prefix);
+                       if (source)
+                               Utils->DoOneToOne(prefix, "ADMIN", params, params[0]);
+               }
+       }
+       return true;
+}
+
+bool TreeSocket::Stats(const std::string &prefix, std::deque<std::string> &params)
+{
+       /* Get the reply to a STATS query if it matches this servername,
+        * and send it back as a load of PUSH queries
+        */
+       if (params.size() > 1)
+       {
+               if (this->Instance->MatchText(this->Instance->Config->ServerName, params[1]))
+               {
+                       /* It's for our server */
+                       string_list results;
+                       userrec* source = this->Instance->FindNick(prefix);
+                       if (source)
+                       {
+                               std::deque<std::string> par;
+                               par.push_back(prefix);
+                               par.push_back("");
+                               DoStats(this->Instance, *(params[0].c_str()), source, results);
+                               for (size_t i = 0; i < results.size(); i++)
+                               {
+                                       par[1] = "::" + results[i];
+                                       Utils->DoOneToOne(this->Instance->Config->ServerName, "PUSH",par, source->server);
+                               }
+                       }
+               }
+               else
+               {
+                       /* Pass it on */
+                       userrec* source = this->Instance->FindNick(prefix);
+                       if (source)
+                               Utils->DoOneToOne(prefix, "STATS", params, params[1]);
+               }
+       }
+       return true;
+}
+
+
+/** Because the core won't let users or even SERVERS set +o,
+ * we use the OPERTYPE command to do this.
+ */
+bool TreeSocket::OperType(const std::string &prefix, std::deque<std::string> &params)
+{
+       if (params.size() != 1)
+               return true;
+       std::string opertype = params[0];
+       userrec* u = this->Instance->FindNick(prefix);
+       if (u)
+       {
+               u->modes[UM_OPERATOR] = 1;
+               this->Instance->all_opers.push_back(u);
+               strlcpy(u->oper,opertype.c_str(),NICKMAX-1);
+               Utils->DoOneToAllButSender(u->nick,"OPERTYPE",params,u->server);
+               this->Instance->SNO->WriteToSnoMask('o',"From %s: User %s (%s@%s) is now an IRC operator of type %s",u->server, u->nick,u->ident,u->host,irc::Spacify(opertype.c_str()));
+       }
+       return true;
+}
+
+/** Because Andy insists that services-compatible servers must
+ * implement SVSNICK and SVSJOIN, that's exactly what we do :p
+ */
+bool TreeSocket::ForceNick(const std::string &prefix, std::deque<std::string> &params)
+{
+       if (params.size() < 3)
+               return true;
+
+       userrec* u = this->Instance->FindNick(params[0]);
+
+       if (u)
+       {
+               Utils->DoOneToAllButSender(prefix,"SVSNICK",params,prefix);
+               if (IS_LOCAL(u))
+               {
+                       std::deque<std::string> par;
+                       par.push_back(params[1]);
+                       if (!u->ForceNickChange(params[1].c_str()))
+                       {
+                               userrec::QuitUser(this->Instance, u, "Nickname collision");
+                               return true;
+                       }
+                       u->age = atoi(params[2].c_str());
+               }
+       }
+       return true;
+}
+
+bool TreeSocket::OperQuit(const std::string &prefix, std::deque<std::string> &params)
+{
+       if (params.size() < 1)
+               return true;
+
+       userrec* u = this->Instance->FindNick(prefix);
+
+       if (u)
+       {
+               u->SetOperQuit(params[0]);
+               params[0] = ":" + params[0];
+               Utils->DoOneToAllButSender(prefix,"OPERQUIT",params,prefix);
+       }
+       return true;
+}
+
+bool TreeSocket::ServiceJoin(const std::string &prefix, std::deque<std::string> &params)
+{
+       if (params.size() < 2)
+               return true;
+
+       userrec* u = this->Instance->FindNick(params[0]);
+
+       if (u)
+       {
+               /* only join if it's local, otherwise just pass it on! */
+               if (IS_LOCAL(u))
+                       chanrec::JoinUser(this->Instance, u, params[1].c_str(), false, "", Instance->Time());
+               Utils->DoOneToAllButSender(prefix,"SVSJOIN",params,prefix);
+       }
+       return true;
+}
+
+bool TreeSocket::RemoteRehash(const std::string &prefix, std::deque<std::string> &params)
+{
+       if (params.size() < 1)
+               return false;
+
+       std::string servermask = params[0];
+
+       if (this->Instance->MatchText(this->Instance->Config->ServerName,servermask))
+       {
+               this->Instance->SNO->WriteToSnoMask('l',"Remote rehash initiated by \002"+prefix+"\002.");
+               this->Instance->RehashServer();
+               Utils->ReadConfiguration(false);
+               InitializeDisabledCommands(Instance->Config->DisabledCommands, Instance);
+       }
+       Utils->DoOneToAllButSender(prefix,"REHASH",params,prefix);
+       return true;
+}
+
+bool TreeSocket::RemoteKill(const std::string &prefix, std::deque<std::string> &params)
+{       
+       if (params.size() != 2)
+               return true;
+
+       userrec* who = this->Instance->FindNick(params[0]);
+
+       if (who)
+       {
+               /* Prepend kill source, if we don't have one */          
+               if (*(params[1].c_str()) != '[')
+               {
+                       params[1] = "[" + prefix + "] Killed (" + params[1] +")";
+               }
+               std::string reason = params[1];
+               params[1] = ":" + params[1];
+               Utils->DoOneToAllButSender(prefix,"KILL",params,prefix);
+               // NOTE: This is safe with kill hiding on, as RemoteKill is only reached if we have a server prefix.
+               // in short this is not executed for USERS.
+               who->Write(":%s KILL %s :%s (%s)", prefix.c_str(), who->nick, prefix.c_str(), reason.c_str());
+               userrec::QuitUser(this->Instance,who,reason);
+       }
+       return true;
+}
+
+bool TreeSocket::LocalPong(const std::string &prefix, std::deque<std::string> &params)
+{
+       if (params.size() < 1)
+               return true;
+
+       if (params.size() == 1)
+       {
+               TreeServer* ServerSource = Utils->FindServer(prefix);
+               if (ServerSource)
+               {
+                       ServerSource->SetPingFlag();
+                       ServerSource->rtt = Instance->Time() - ServerSource->LastPing;
+               }
+       }
+       else
+       {
+               std::string forwardto = params[1];
+               if (forwardto == this->Instance->Config->ServerName)
+               {
+                       /*
+                        * this is a PONG for us
+                        * if the prefix is a user, check theyre local, and if they are,
+                        * dump the PONG reply back to their fd. If its a server, do nowt.
+                        * Services might want to send these s->s, but we dont need to yet.
+                        */
+                       userrec* u = this->Instance->FindNick(prefix);
+                       if (u)
+                       {
+                               u->WriteServ("PONG %s %s",params[0].c_str(),params[1].c_str());
+                       }
+               }
+               else
+               {
+                       // not for us, pass it on :)
+                       Utils->DoOneToOne(prefix,"PONG",params,forwardto);
+               }
+       }
+
+       return true;
+}
+
+bool TreeSocket::MetaData(const std::string &prefix, std::deque<std::string> &params)
+{
+       if (params.size() < 2)
+               return true;
+       else if (params.size() < 3)
+               params.push_back("");
+       TreeServer* ServerSource = Utils->FindServer(prefix);
+       if (ServerSource)
+       {
+               Utils->SetRemoteBursting(ServerSource, false);
+
+               if (params[0] == "*")
+               {
+                       FOREACH_MOD_I(this->Instance,I_OnDecodeMetaData,OnDecodeMetaData(TYPE_OTHER,NULL,params[1],params[2]));
+               }
+               else if (*(params[0].c_str()) == '#')
+               {
+                       chanrec* c = this->Instance->FindChan(params[0]);
+                       if (c)
+                       {
+                               FOREACH_MOD_I(this->Instance,I_OnDecodeMetaData,OnDecodeMetaData(TYPE_CHANNEL,c,params[1],params[2]));
+                       }
+               }
+               else if (*(params[0].c_str()) != '#')
+               {
+                       userrec* u = this->Instance->FindNick(params[0]);
+                       if (u)
+                       {
+                               FOREACH_MOD_I(this->Instance,I_OnDecodeMetaData,OnDecodeMetaData(TYPE_USER,u,params[1],params[2]));
+                       }
+               }
+       }
+
+       params[2] = ":" + params[2];
+       Utils->DoOneToAllButSender(prefix,"METADATA",params,prefix);
+       return true;
+}
+
+bool TreeSocket::ServerVersion(const std::string &prefix, std::deque<std::string> &params)
+{
+       if (params.size() < 1)
+               return true;
+
+       TreeServer* ServerSource = Utils->FindServer(prefix);
+
+       if (ServerSource)
+       {
+               ServerSource->SetVersion(params[0]);
+       }
+       params[0] = ":" + params[0];
+       Utils->DoOneToAllButSender(prefix,"VERSION",params,prefix);
+       return true;
+}
+
+bool TreeSocket::ChangeHost(const std::string &prefix, std::deque<std::string> &params)
+{
+       if (params.size() < 1)
+               return true;
+       userrec* u = this->Instance->FindNick(prefix);
+
+       if (u)
+       {
+               u->ChangeDisplayedHost(params[0].c_str());
+               Utils->DoOneToAllButSender(prefix,"FHOST",params,u->server);
+       }
+       return true;
+}
+
+bool TreeSocket::AddLine(const std::string &prefix, std::deque<std::string> &params)
+{
+       if (params.size() < 6)
+               return true;
+       bool propogate = false;
+       if (!this->bursting)
+               Utils->lines_to_apply = 0;
+       switch (*(params[0].c_str()))
+       {
+               case 'Z':
+                       propogate = Instance->XLines->add_zline(atoi(params[4].c_str()), params[2].c_str(), params[5].c_str(), params[1].c_str());
+                       Instance->XLines->zline_set_creation_time(params[1].c_str(), atoi(params[3].c_str()));
+                       if (propogate)
+                               Utils->lines_to_apply |= APPLY_ZLINES;
+               break;
+               case 'Q':
+                       propogate = Instance->XLines->add_qline(atoi(params[4].c_str()), params[2].c_str(), params[5].c_str(), params[1].c_str());
+                       Instance->XLines->qline_set_creation_time(params[1].c_str(), atoi(params[3].c_str()));
+                       if (propogate)
+                               Utils->lines_to_apply |= APPLY_QLINES;
+               break;
+               case 'E':
+                       propogate = Instance->XLines->add_eline(atoi(params[4].c_str()), params[2].c_str(), params[5].c_str(), params[1].c_str());
+                       Instance->XLines->eline_set_creation_time(params[1].c_str(), atoi(params[3].c_str()));
+               break;
+               case 'G':
+                       propogate = Instance->XLines->add_gline(atoi(params[4].c_str()), params[2].c_str(), params[5].c_str(), params[1].c_str());
+                       Instance->XLines->gline_set_creation_time(params[1].c_str(), atoi(params[3].c_str()));
+                       if (propogate)
+                               Utils->lines_to_apply |= APPLY_GLINES;
+               break;
+               case 'K':
+                       propogate = Instance->XLines->add_kline(atoi(params[4].c_str()), params[2].c_str(), params[5].c_str(), params[1].c_str());
+                       if (propogate)
+                               Utils->lines_to_apply |= APPLY_KLINES;
+               break;
+               default:
+                       /* Just in case... */
+                       this->Instance->SNO->WriteToSnoMask('x',"\2WARNING\2: Invalid xline type '"+params[0]+"' sent by server "+prefix+", ignored!");
+                       propogate = false;
+               break;
+       }
+       /* Send it on its way */
+       if (propogate)
+       {
+               if (atoi(params[4].c_str()))
+               {
+                       time_t c_requires_crap = ConvToInt(params[4]) + Instance->Time();
+                       this->Instance->SNO->WriteToSnoMask('x',"%s Added %cLINE on %s to expire on %s (%s).",prefix.c_str(),*(params[0].c_str()),params[1].c_str(),Instance->TimeString(c_requires_crap).c_str(),params[5].c_str());
+               }
+               else
+               {
+                       this->Instance->SNO->WriteToSnoMask('x',"%s Added permenant %cLINE on %s (%s).",prefix.c_str(),*(params[0].c_str()),params[1].c_str(),params[5].c_str());
+               }
+               params[5] = ":" + params[5];
+               Utils->DoOneToAllButSender(prefix,"ADDLINE",params,prefix);
+       }
+       if (!this->bursting)
+       {
+               Instance->XLines->apply_lines(Utils->lines_to_apply);
+               Utils->lines_to_apply = 0;
+       }
+       return true;
+}
+
+bool TreeSocket::ChangeName(const std::string &prefix, std::deque<std::string> &params)
+{
+       if (params.size() < 1)
+               return true;
+       userrec* u = this->Instance->FindNick(prefix);
+       if (u)
+       {
+               u->ChangeName(params[0].c_str());
+               params[0] = ":" + params[0];
+               Utils->DoOneToAllButSender(prefix,"FNAME",params,u->server);
+       }
+       return true;
+}
+
+bool TreeSocket::Whois(const std::string &prefix, std::deque<std::string> &params)
+{
+       if (params.size() < 1)
+               return true;
+       userrec* u = this->Instance->FindNick(prefix);
+       if (u)
+       {
+               // an incoming request
+               if (params.size() == 1)
+               {
+                       userrec* x = this->Instance->FindNick(params[0]);
+                       if ((x) && (IS_LOCAL(x)))
+                       {
+                               userrec* x = this->Instance->FindNick(params[0]);
+                               char signon[MAXBUF];
+                               char idle[MAXBUF];
+                               snprintf(signon, MAXBUF, "%lu", (unsigned long)x->signon);
+                               snprintf(idle, MAXBUF, "%lu", (unsigned long)abs((x->idle_lastmsg) - Instance->Time(true)));
+                               std::deque<std::string> par;
+                               par.push_back(prefix);
+                               par.push_back(signon);
+                               par.push_back(idle);
+                               // ours, we're done, pass it BACK
+                               Utils->DoOneToOne(params[0], "IDLE", par, u->server);
+                       }
+                       else
+                       {
+                               // not ours pass it on
+                               if (x)
+                                       Utils->DoOneToOne(prefix, "IDLE", params, x->server);
+                       }
+               }
+               else if (params.size() == 3)
+               {
+                       std::string who_did_the_whois = params[0];
+                       userrec* who_to_send_to = this->Instance->FindNick(who_did_the_whois);
+                       if ((who_to_send_to) && (IS_LOCAL(who_to_send_to)))
+                       {
+                               // an incoming reply to a whois we sent out
+                               std::string nick_whoised = prefix;
+                               unsigned long signon = atoi(params[1].c_str());
+                               unsigned long idle = atoi(params[2].c_str());
+                               if ((who_to_send_to) && (IS_LOCAL(who_to_send_to)))
+                               {
+                                       do_whois(this->Instance, who_to_send_to, u, signon, idle, nick_whoised.c_str());
+                               }
+                       }
+                       else
+                       {
+                               // not ours, pass it on
+                               if (who_to_send_to)
+                                       Utils->DoOneToOne(prefix, "IDLE", params, who_to_send_to->server);
+                       }
+               }
+       }
+       return true;
+}
+
+bool TreeSocket::Push(const std::string &prefix, std::deque<std::string> &params)
+{
+       if (params.size() < 2)
+               return true;
+       userrec* u = this->Instance->FindNick(params[0]);
+       if (!u)
+               return true;
+       if (IS_LOCAL(u))
+       {
+               u->Write(params[1]);
+       }
+       else
+       {
+               // continue the raw onwards
+               params[1] = ":" + params[1];
+               Utils->DoOneToOne(prefix,"PUSH",params,u->server);
+       }
+       return true;
+}
+
+bool TreeSocket::HandleSetTime(const std::string &prefix, std::deque<std::string> &params)
+{
+       if (!params.size() || !Utils->EnableTimeSync)
+               return true;
+
+       bool force = false;
+
+       if ((params.size() == 2) && (params[1] == "FORCE"))
+               force = true;
+
+       time_t them = atoi(params[0].c_str());
+       time_t us = Instance->Time(false);
+
+       time_t diff = them - us;
+
+       Utils->DoOneToAllButSender(prefix, "TIMESET", params, prefix);
+
+       if (force || (them != us))
+       {
+               time_t old = Instance->SetTimeDelta(diff);
+               Instance->Log(DEBUG, "TS (diff %d) from %s applied (old delta was %d)", diff, prefix.c_str(), old);
+       }
+
+       return true;
+}
+
+bool TreeSocket::Time(const std::string &prefix, std::deque<std::string> &params)
+{
+       // :source.server TIME remote.server sendernick
+       // :remote.server TIME source.server sendernick TS
+       if (params.size() == 2)
+       {
+               // someone querying our time?
+               if (this->Instance->Config->ServerName == params[0])
+               {
+                       userrec* u = this->Instance->FindNick(params[1]);
+                       if (u)
+                       {
+                               params.push_back(ConvToStr(Instance->Time(false)));
+                               params[0] = prefix;
+                               Utils->DoOneToOne(this->Instance->Config->ServerName,"TIME",params,params[0]);
+                       }
+               }
+               else
+               {
+                       // not us, pass it on
+                       userrec* u = this->Instance->FindNick(params[1]);
+                       if (u)
+                               Utils->DoOneToOne(prefix,"TIME",params,params[0]);
+               }
+       }
+       else if (params.size() == 3)
+       {
+               // a response to a previous TIME
+               userrec* u = this->Instance->FindNick(params[1]);
+               if ((u) && (IS_LOCAL(u)))
+               {
+                       time_t rawtime = atol(params[2].c_str());
+                       struct tm * timeinfo;
+                       timeinfo = localtime(&rawtime);
+                       char tms[26];
+                       snprintf(tms,26,"%s",asctime(timeinfo));
+                       tms[24] = 0;
+                       u->WriteServ("391 %s %s :%s",u->nick,prefix.c_str(),tms);
+               }
+               else
+               {
+                       if (u)
+                               Utils->DoOneToOne(prefix,"TIME",params,u->server);
+               }
+       }
+       return true;
+}
+
+bool TreeSocket::LocalPing(const std::string &prefix, std::deque<std::string> &params)
+{
+       if (params.size() < 1)
+               return true;
+       if (params.size() == 1)
+       {
+               std::string stufftobounce = params[0];
+               this->WriteLine(std::string(":")+this->Instance->Config->ServerName+" PONG "+stufftobounce);
+               return true;
+       }
+       else
+       {
+               std::string forwardto = params[1];
+               if (forwardto == this->Instance->Config->ServerName)
+               {
+                       // this is a ping for us, send back PONG to the requesting server
+                       params[1] = params[0];
+                       params[0] = forwardto;
+                       Utils->DoOneToOne(forwardto,"PONG",params,params[1]);
+               }
+               else
+               {
+                       // not for us, pass it on :)
+                       Utils->DoOneToOne(prefix,"PING",params,forwardto);
+               }
+               return true;
+       }
+}
+
+/** TODO: This creates a total mess of output and needs to really use irc::modestacker.
+ */
+bool TreeSocket::RemoveStatus(const std::string &prefix, std::deque<std::string> &params)
+{
+       if (params.size() < 1)
+               return true;
+       chanrec* c = Instance->FindChan(params[0]);
+       if (c)
+       {
+               for (char modeletter = 'A'; modeletter <= 'z'; modeletter++)
+               {
+                       ModeHandler* mh = Instance->Modes->FindMode(modeletter, MODETYPE_CHANNEL);
+                       if (mh)
+                               mh->RemoveMode(c);
+               }
+       }
+       return true;
+}
+
+bool TreeSocket::RemoteServer(const std::string &prefix, std::deque<std::string> &params)
+{
+       if (params.size() < 4)
+               return false;
+       std::string servername = params[0];
+       std::string password = params[1];
+       // hopcount is not used for a remote server, we calculate this ourselves
+       std::string description = params[3];
+       TreeServer* ParentOfThis = Utils->FindServer(prefix);
+       if (!ParentOfThis)
+       {
+               this->SendError("Protocol error - Introduced remote server from unknown server "+prefix);
+               return false;
+       }
+       TreeServer* CheckDupe = Utils->FindServer(servername);
+       if (CheckDupe)
+       {
+               this->SendError("Server "+servername+" already exists!");
+               this->Instance->SNO->WriteToSnoMask('l',"Server \2"+servername+"\2 being introduced from \2" + prefix + "\2 denied, already exists. Closing link with " + prefix);
+               return false;
+       }
+       Link* lnk = Utils->FindLink(servername);
+       TreeServer* Node = new TreeServer(this->Utils,this->Instance,servername,description,ParentOfThis,NULL, lnk ? lnk->Hidden : false);
+       ParentOfThis->AddChild(Node);
+       params[3] = ":" + params[3];
+       Utils->SetRemoteBursting(Node, true);
+       Utils->DoOneToAllButSender(prefix,"SERVER",params,prefix);
+       this->Instance->SNO->WriteToSnoMask('l',"Server \002"+prefix+"\002 introduced server \002"+servername+"\002 ("+description+")");
+       return true;
+}
+
+bool TreeSocket::ComparePass(const std::string &ours, const std::string &theirs)
+{
+       if ((!strncmp(ours.c_str(), "HMAC-SHA256:", 12)) || (!strncmp(theirs.c_str(), "HMAC-SHA256:", 12)))
+       {
+               /* One or both of us specified hmac sha256, but we don't have sha256 module loaded!
+                * We can't allow this password as valid.
+                */
+               if (!Instance->FindModule("m_sha256.so") || !Utils->ChallengeResponse)
+                               return false;
+               else
+                       /* Straight string compare of hashes */
+                       return ours == theirs;
+       }
+       else
+               /* Straight string compare of plaintext */
+               return ours == theirs;
+}
+
+bool TreeSocket::Outbound_Reply_Server(std::deque<std::string> &params)
+{
+       if (params.size() < 4)
+               return false;
+
+       irc::string servername = params[0].c_str();
+       std::string sname = params[0];
+       std::string password = params[1];
+       std::string description = params[3];
+       int hops = atoi(params[2].c_str());
+
+       this->InboundServerName = sname;
+       this->InboundDescription = description;
+
+       if (!sentcapab)
+               this->SendCapabilities();
+
+       if (hops)
+       {
+               this->SendError("Server too far away for authentication");
+               this->Instance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, server is too far away for authentication");
+               return false;
+       }
+
+       for (std::vector<Link>::iterator x = Utils->LinkBlocks.begin(); x < Utils->LinkBlocks.end(); x++)
+       {
+               if ((x->Name == servername) && ((ComparePass(this->MakePass(x->RecvPass,this->GetOurChallenge()),password)) || (x->RecvPass == password && (this->GetTheirChallenge().empty()))))
+               {
+                       TreeServer* CheckDupe = Utils->FindServer(sname);
+                       if (CheckDupe)
+                       {
+                               this->SendError("Server "+sname+" already exists on server "+CheckDupe->GetParent()->GetName()+"!");
+                               this->Instance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, already exists on server "+CheckDupe->GetParent()->GetName());
+                               return false;
+                       }
+                       // Begin the sync here. this kickstarts the
+                       // other side, waiting in WAIT_AUTH_2 state,
+                       // into starting their burst, as it shows
+                       // that we're happy.
+                       this->LinkState = CONNECTED;
+                       // we should add the details of this server now
+                       // to the servers tree, as a child of the root
+                       // node.
+                       TreeServer* Node = new TreeServer(this->Utils,this->Instance,sname,description,Utils->TreeRoot,this,x->Hidden);
+                       Utils->TreeRoot->AddChild(Node);
+                       params[3] = ":" + params[3];
+                       Utils->DoOneToAllButSender(Utils->TreeRoot->GetName(),"SERVER",params,sname);
+                       this->bursting = true;
+                       this->DoBurst(Node);
+                       return true;
+               }
+       }
+       this->SendError("Invalid credentials");
+       this->Instance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, invalid link credentials");
+       return false;
+}
+
+bool TreeSocket::Inbound_Server(std::deque<std::string> &params)
+{
+       if (params.size() < 4)
+               return false;
+       irc::string servername = params[0].c_str();
+       std::string sname = params[0];
+       std::string password = params[1];
+       std::string description = params[3];
+       int hops = atoi(params[2].c_str());
+
+       this->InboundServerName = sname;
+       this->InboundDescription = description;
+
+       if (!sentcapab)
+               this->SendCapabilities();
+
+       if (hops)
+       {
+               this->SendError("Server too far away for authentication");
+               this->Instance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, server is too far away for authentication");
+               return false;
+       }
+
+       for (std::vector<Link>::iterator x = Utils->LinkBlocks.begin(); x < Utils->LinkBlocks.end(); x++)
+       {
+               if ((x->Name == servername) && ((ComparePass(this->MakePass(x->RecvPass,this->GetOurChallenge()),password) || x->RecvPass == password && (this->GetTheirChallenge().empty()))))
+               {
+                       /* First check for instances of the server that are waiting between the inbound and outbound SERVER command */
+                       TreeSocket* CheckDupeSocket = Utils->FindBurstingServer(sname);
+                       if (CheckDupeSocket)
+                       {
+                               /* If we find one, we abort the link to prevent a race condition */
+                               this->SendError("Negotiation collision");
+                               this->Instance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, already exists in a negotiating state.");
+                               CheckDupeSocket->SendError("Negotiation collision");
+                               Instance->SE->DelFd(CheckDupeSocket);
+                               CheckDupeSocket->Close();
+                               delete CheckDupeSocket;
+                               return false;
+                       }
+                       /* Now check for fully initialized instances of the server */
+                       TreeServer* CheckDupe = Utils->FindServer(sname);
+                       if (CheckDupe)
+                       {
+                               this->SendError("Server "+sname+" already exists on server "+CheckDupe->GetParent()->GetName()+"!");
+                               this->Instance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, already exists on server "+CheckDupe->GetParent()->GetName());
+                               return false;
+                       }
+                       this->Instance->SNO->WriteToSnoMask('l',"Verified incoming server connection from \002"+sname+"\002["+(x->HiddenFromStats ? "<hidden>" : this->GetIP())+"] ("+description+")");
+                       if (this->Hook)
+                       {
+                               std::string name = InspSocketNameRequest((Module*)Utils->Creator, this->Hook).Send();
+                               this->Instance->SNO->WriteToSnoMask('l',"Connection from \2"+sname+"\2["+(x->HiddenFromStats ? "<hidden>" : this->GetIP())+"] using transport \2"+name+"\2");
+                       }
+
+                       Utils->AddBurstingServer(sname,this);
+
+                       // this is good. Send our details: Our server name and description and hopcount of 0,
+                       // along with the sendpass from this block.
+                       this->WriteLine(std::string("SERVER ")+this->Instance->Config->ServerName+" "+this->MakePass(x->SendPass, this->GetTheirChallenge())+" 0 :"+this->Instance->Config->ServerDesc);
+                       // move to the next state, we are now waiting for THEM.
+                       this->LinkState = WAIT_AUTH_2;
+                       return true;
+               }
+       }
+       this->SendError("Invalid credentials");
+       this->Instance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, invalid link credentials");
+       return false;
+}
+
+void TreeSocket::Split(const std::string &line, std::deque<std::string> &n)
+{
+       n.clear();
+       irc::tokenstream tokens(line);
+       std::string param;
+       while (tokens.GetToken(param))
+       {
+               if (!param.empty())
+                       n.push_back(param);
+       }
+       return;
+}
+
+bool TreeSocket::ProcessLine(std::string &line)
+{
+       std::deque<std::string> params;
+       irc::string command;
+       std::string prefix;
+
+       line = line.substr(0, line.find_first_of("\r\n"));
+
+       if (line.empty())
+               return true;
+
+       Instance->Log(DEBUG, "S[%d] <- %s", this->GetFd(), line.c_str());
+
+       this->Split(line.c_str(),params);
+       
+       if (params.empty())
+               return true;
+       
+       if ((params[0][0] == ':') && (params.size() > 1))
+       {
+               prefix = params[0].substr(1);
+               params.pop_front();
+       }
+       command = params[0].c_str();
+       params.pop_front();
+       switch (this->LinkState)
+       {
+               TreeServer* Node;
+
+               case WAIT_AUTH_1:
+                       // Waiting for SERVER command from remote server. Server initiating
+                       // the connection sends the first SERVER command, listening server
+                       // replies with theirs if its happy, then if the initiator is happy,
+                       // it starts to send its net sync, which starts the merge, otherwise
+                       // it sends an ERROR.
+                       if (command == "PASS")
+                       {
+                               /* Silently ignored */
+                       }
+                       else if (command == "SERVER")
+                       {
+                               return this->Inbound_Server(params);
+                       }
+                       else if (command == "ERROR")
+                       {
+                               return this->Error(params);
+                       }
+                       else if (command == "USER")
+                       {
+                               this->SendError("Client connections to this port are prohibited.");
+                               return false;
+                       }
+                       else if (command == "CAPAB")
+                       {
+                               return this->Capab(params);
+                       }
+                       else if ((command == "U") || (command == "S"))
+                       {
+                               this->SendError("Cannot use the old-style mesh linking protocol with m_spanningtree.so!");
+                               return false;
+                       }
+                       else
+                       {
+                               irc::string error = "Invalid command in negotiation phase: " + command;
+                               this->SendError(assign(error));
+                               return false;
+                       }
+               break;
+               case WAIT_AUTH_2:
+                       // Waiting for start of other side's netmerge to say they liked our
+                       // password.
+                       if (command == "SERVER")
+                       {
+                               // cant do this, they sent it to us in the WAIT_AUTH_1 state!
+                               // silently ignore.
+                               return true;
+                       }
+                       else if ((command == "U") || (command == "S"))
+                       {
+                               this->SendError("Cannot use the old-style mesh linking protocol with m_spanningtree.so!");
+                               return false;
+                       }
+                       else if (command == "BURST")
+                       {
+                               if (params.size() && Utils->EnableTimeSync)
+                               {
+                                       bool we_have_delta = (Instance->Time(false) != Instance->Time(true));
+                                       time_t them = atoi(params[0].c_str());
+                                       time_t delta = them - Instance->Time(false);
+                                       if ((delta < -300) || (delta > 300))
+                                       {
+                                               Instance->SNO->WriteToSnoMask('l',"\2ERROR\2: Your clocks are out by %d seconds (this is more than five minutes). Link aborted, \2PLEASE SYNC YOUR CLOCKS!\2",abs(delta));
+                                               SendError("Your clocks are out by "+ConvToStr(abs(delta))+" seconds (this is more than five minutes). Link aborted, PLEASE SYNC YOUR CLOCKS!");
+                                               return false;
+                                       }
+                                       else if ((delta < -30) || (delta > 30))
+                                       {
+                                               Instance->SNO->WriteToSnoMask('l',"\2WARNING\2: Your clocks are out by %d seconds. Please consider synching your clocks.", abs(delta));
+                                       }
+
+                                       if (!Utils->MasterTime && !we_have_delta)
+                                       {
+                                               this->Instance->SetTimeDelta(delta);
+                                               // Send this new timestamp to any other servers
+                                               Utils->DoOneToMany(Utils->TreeRoot->GetName(), "TIMESET", params);
+                                       }
+                               }
+                               this->LinkState = CONNECTED;
+                               Link* lnk = Utils->FindLink(InboundServerName);
+                               Node = new TreeServer(this->Utils,this->Instance, InboundServerName, InboundDescription, Utils->TreeRoot, this, lnk ? lnk->Hidden : false);
+                               Utils->DelBurstingServer(this);
+                               Utils->TreeRoot->AddChild(Node);
+                               params.clear();
+                               params.push_back(InboundServerName);
+                               params.push_back("*");
+                               params.push_back("1");
+                               params.push_back(":"+InboundDescription);
+                               Utils->DoOneToAllButSender(Utils->TreeRoot->GetName(),"SERVER",params,InboundServerName);
+                               this->bursting = true;
+                               this->DoBurst(Node);
+                       }
+                       else if (command == "ERROR")
+                       {
+                               return this->Error(params);
+                       }
+                       else if (command == "CAPAB")
+                       {
+                               return this->Capab(params);
+                       }
+
+               break;
+               case LISTENER:
+                       this->SendError("Internal error -- listening socket accepted its own descriptor!!!");
+                       return false;
+               break;
+               case CONNECTING:
+                       if (command == "SERVER")
+                       {
+                               // another server we connected to, which was in WAIT_AUTH_1 state,
+                               // has just sent us their credentials. If we get this far, theyre
+                               // happy with OUR credentials, and they are now in WAIT_AUTH_2 state.
+                               // if we're happy with this, we should send our netburst which
+                               // kickstarts the merge.
+                               return this->Outbound_Reply_Server(params);
+                       }
+                       else if (command == "ERROR")
+                       {
+                               return this->Error(params);
+                       }
+                       else if (command == "CAPAB")
+                       {
+                               return this->Capab(params);
+                       }
+               break;
+               case CONNECTED:
+                       // This is the 'authenticated' state, when all passwords
+                       // have been exchanged and anything past this point is taken
+                       // as gospel.
+
+                       if (!prefix.empty())
+                       {
+                               std::string direction = prefix;
+                               userrec* t = this->Instance->FindNick(prefix);
+                               if (t)
+                               {
+                                       direction = t->server;
+                               }
+                               TreeServer* route_back_again = Utils->BestRouteTo(direction);
+                               if ((!route_back_again) || (route_back_again->GetSocket() != this))
+                               {
+                                       if (route_back_again)
+                                               Instance->Log(DEBUG,"Protocol violation: Fake direction in command '%s' from connection '%s'",line.c_str(),this->GetName().c_str());
+                                       return true;
+                               }
+                               /* Fix by brain:
+                                * When there is activity on the socket, reset the ping counter so
+                                * that we're not wasting bandwidth pinging an active server.
+                                */
+                               route_back_again->SetNextPingTime(time(NULL) + 60);
+                               route_back_again->SetPingFlag();
+                       }
+                       else
+                       {
+                               prefix = this->GetName();
+                       }
+
+                       if ((command == "MODE") && (params.size() >= 2))
+                       {
+                               chanrec* channel = Instance->FindChan(params[0]);
+                               if (channel)
+                               {
+                                       userrec* x = Instance->FindNick(prefix);
+                                       if (x)
+                                       {
+                                               if (warned.find(x->server) == warned.end())
+                                               {
+                                                       Instance->Log(DEFAULT,"WARNING: I revceived modes '%s' from another server '%s'. This is not compliant with InspIRCd. Please check that server for bugs.", params[1].c_str(), x->server);
+                                                       Instance->SNO->WriteToSnoMask('d', "WARNING: The server %s is sending nonstandard modes: '%s MODE %s' where FMODE should be used, and may cause desyncs.", x->server, x->nick, params[1].c_str());
+                                                       warned[x->server] = x->nick;
+                                               }
+                                       }
+                               }
+                       }
+
+                       if (command == "SVSMODE")
+                       {
+                               /* Services expects us to implement
+                                * SVSMODE. In inspircd its the same as
+                                * MODE anyway.
+                                */
+                               command = "MODE";
+                       }
+                       std::string target;
+                       /* Yes, know, this is a mess. Its reasonably fast though as we're
+                        * working with std::string here.
+                        */
+                       if ((command == "NICK") && (params.size() >= 8))
+                       {
+                               return this->IntroduceClient(prefix,params);
+                       }
+                       else if (command == "FJOIN")
+                       {
+                               TreeServer* ServerSource = Utils->FindServer(prefix);
+                               if (ServerSource)
+                                       Utils->SetRemoteBursting(ServerSource, false);
+                               return this->ForceJoin(prefix,params);
+                       }
+                       else if (command == "STATS")
+                       {
+                               return this->Stats(prefix, params);
+                       }
+                       else if (command == "MOTD")
+                       {
+                               return this->Motd(prefix, params);
+                       }
+                       else if (command == "KILL" && Utils->IsServer(prefix))
+                       {
+                               return this->RemoteKill(prefix,params);
+                       }
+                       else if (command == "MODULES")
+                       {
+                               return this->Modules(prefix, params);
+                       }
+                       else if (command == "ADMIN")
+                       {
+                               return this->Admin(prefix, params);
+                       }
+                       else if (command == "SERVER")
+                       {
+                               return this->RemoteServer(prefix,params);
+                       }
+                       else if (command == "ERROR")
+                       {
+                               return this->Error(params);
+                       }
+                       else if (command == "OPERTYPE")
+                       {
+                               return this->OperType(prefix,params);
+                       }
+                       else if (command == "FMODE")
+                       {
+                               TreeServer* ServerSource = Utils->FindServer(prefix);
+                               if (ServerSource)
+                                       Utils->SetRemoteBursting(ServerSource, false);
+                               return this->ForceMode(prefix,params);
+                       }
+                       else if (command == "FTOPIC")
+                       {
+                               return this->ForceTopic(prefix,params);
+                       }
+                       else if (command == "REHASH")
+                       {
+                               return this->RemoteRehash(prefix,params);
+                       }
+                       else if (command == "METADATA")
+                       {
+                               return this->MetaData(prefix,params);
+                       }
+                       else if (command == "REMSTATUS")
+                       {
+                               return this->RemoveStatus(prefix,params);
+                       }
+                       else if (command == "PING")
+                       {
+                               if (prefix.empty())
+                                       prefix = this->GetName();
+                               /*
+                                * We just got a ping from a server that's bursting.
+                                * This can't be right, so set them to not bursting, and
+                                * apply their lines.
+                                */
+                               TreeServer* ServerSource = Utils->FindServer(prefix);
+                               if (ServerSource)
+                                       Utils->SetRemoteBursting(ServerSource, false);
+
+                               if (this->bursting)
+                               {
+                                       this->bursting = false;
+                                       Instance->XLines->apply_lines(Utils->lines_to_apply);
+                                       Utils->lines_to_apply = 0;
+                               }
+
+                               return this->LocalPing(prefix,params);
+                       }
+                       else if (command == "PONG")
+                       {
+                               if (prefix.empty())
+                                       prefix = this->GetName();
+                               /*
+                                * We just got a pong from a server that's bursting.
+                                * This can't be right, so set them to not bursting, and
+                                * apply their lines.
+                                */
+                               TreeServer* ServerSource = Utils->FindServer(prefix);
+                               if (ServerSource)
+                                       Utils->SetRemoteBursting(ServerSource, false);
+
+                               if (this->bursting)
+                               {
+                                       this->bursting = false;
+                                       Instance->XLines->apply_lines(Utils->lines_to_apply);
+                                       Utils->lines_to_apply = 0;
+                               }
+
+                               return this->LocalPong(prefix,params);
+                       }
+                       else if (command == "VERSION")
+                       {
+                               return this->ServerVersion(prefix,params);
+                       }
+                       else if (command == "FHOST")
+                       {
+                               return this->ChangeHost(prefix,params);
+                       }
+                       else if (command == "FNAME")
+                       {
+                               return this->ChangeName(prefix,params);
+                       }
+                       else if (command == "ADDLINE")
+                       {
+                               TreeServer* ServerSource = Utils->FindServer(prefix);
+                               if (ServerSource)
+                                       Utils->SetRemoteBursting(ServerSource, false);
+                               return this->AddLine(prefix,params);
+                       }
+                       else if (command == "SVSNICK")
+                       {
+                               if (prefix.empty())
+                               {
+                                       prefix = this->GetName();
+                               }
+                               return this->ForceNick(prefix,params);
+                       }
+                       else if (command == "OPERQUIT")
+                       {
+                               return this->OperQuit(prefix,params);
+                       }
+                       else if (command == "IDLE")
+                       {
+                               return this->Whois(prefix,params);
+                       }
+                       else if (command == "PUSH")
+                       {
+                               return this->Push(prefix,params);
+                       }
+                       else if (command == "TIMESET")
+                       {
+                               return this->HandleSetTime(prefix, params);
+                       }
+                       else if (command == "TIME")
+                       {
+                               return this->Time(prefix,params);
+                       }
+                       else if ((command == "KICK") && (Utils->IsServer(prefix)))
+                       {
+                               std::string sourceserv = this->myhost;
+                               if (params.size() == 3)
+                               {
+                                       userrec* user = this->Instance->FindNick(params[1]);
+                                       chanrec* chan = this->Instance->FindChan(params[0]);
+                                       if (user && chan)
+                                       {
+                                               if (!chan->ServerKickUser(user, params[2].c_str(), false))
+                                                       /* Yikes, the channels gone! */
+                                                       delete chan;
+                                       }
+                               }
+                               if (!this->InboundServerName.empty())
+                               {
+                                       sourceserv = this->InboundServerName;
+                               }
+                               return Utils->DoOneToAllButSenderRaw(line,sourceserv,prefix,command,params);
+                       }
+                       else if (command == "SVSJOIN")
+                       {
+                               if (prefix.empty())
+                               {
+                                       prefix = this->GetName();
+                               }
+                               return this->ServiceJoin(prefix,params);
+                       }
+                       else if (command == "SQUIT")
+                       {
+                               if (params.size() == 2)
+                               {
+                                       this->Squit(Utils->FindServer(params[0]),params[1]);
+                               }
+                               return true;
+                       }
+                       else if (command == "OPERNOTICE")
+                       {
+                               std::string sourceserv = this->myhost;
+                               if (!this->InboundServerName.empty())
+                                       sourceserv = this->InboundServerName;
+                               if (params.size() >= 1)
+                                       Instance->WriteOpers("*** From " + sourceserv + ": " + params[0]);
+                               return Utils->DoOneToAllButSenderRaw(line, sourceserv, prefix, command, params);
+                       }
+                       else if (command == "MODENOTICE")
+                       {
+                               std::string sourceserv = this->myhost;
+                               if (!this->InboundServerName.empty())
+                                       sourceserv = this->InboundServerName;
+                               if (params.size() >= 2)
+                               {
+                                       Instance->WriteMode(params[0].c_str(), WM_AND, "*** From %s: %s", sourceserv.c_str(), params[1].c_str());
+                               }
+                               return Utils->DoOneToAllButSenderRaw(line, sourceserv, prefix, command, params);
+                       }
+                       else if (command == "SNONOTICE")
+                       {
+                               std::string sourceserv = this->myhost;
+                               if (!this->InboundServerName.empty())
+                                       sourceserv = this->InboundServerName;
+                               if (params.size() >= 2)
+                               {
+                                       Instance->SNO->WriteToSnoMask(*(params[0].c_str()), "From " + sourceserv + ": "+ params[1]);
+                               }
+                               return Utils->DoOneToAllButSenderRaw(line, sourceserv, prefix, command, params);
+                       }
+                       else if (command == "ENDBURST")
+                       {
+                               this->bursting = false;
+                               Instance->XLines->apply_lines(Utils->lines_to_apply);
+                               Utils->lines_to_apply = 0;
+                               std::string sourceserv = this->myhost;
+                               if (!this->InboundServerName.empty())
+                                       sourceserv = this->InboundServerName;
+                               this->Instance->SNO->WriteToSnoMask('l',"Received end of netburst from \2%s\2",sourceserv.c_str());
+
+                               Event rmode((char*)sourceserv.c_str(), (Module*)Utils->Creator, "new_server");
+                               rmode.Send(Instance);
+
+                               return true;
+                       }
+                       else
+                       {
+                               // not a special inter-server command.
+                               // Emulate the actual user doing the command,
+                               // this saves us having a huge ugly parser.
+                               userrec* who = this->Instance->FindNick(prefix);
+                               std::string sourceserv = this->myhost;
+                               if (!this->InboundServerName.empty())
+                               {
+                                       sourceserv = this->InboundServerName;
+                               }
+                               if ((!who) && (command == "MODE"))
+                               {
+                                       if (Utils->IsServer(prefix))
+                                       {
+                                               const char* modelist[127];
+                                               for (size_t i = 0; i < params.size(); i++)
+                                                       modelist[i] = params[i].c_str();
+                                               userrec* fake = new userrec(Instance);
+                                               fake->SetFd(FD_MAGIC_NUMBER);
+                                               this->Instance->SendMode(modelist, params.size(), fake);
+
+                                               delete fake;
+                                               /* Hot potato! pass it on! */
+                                               return Utils->DoOneToAllButSenderRaw(line,sourceserv,prefix,command,params);
+                                       }
+                               }
+                               if (who)
+                               {
+                                       if ((command == "NICK") && (params.size() > 0))
+                                       {
+                                               /* On nick messages, check that the nick doesnt
+                                                * already exist here. If it does, kill their copy,
+                                                * and our copy.
+                                                */
+                                               userrec* x = this->Instance->FindNick(params[0]);
+                                               if ((x) && (x != who))
+                                               {
+                                                       std::deque<std::string> p;
+                                                       p.push_back(params[0]);
+                                                       p.push_back("Nickname collision ("+prefix+" -> "+params[0]+")");
+                                                       Utils->DoOneToMany(this->Instance->Config->ServerName,"KILL",p);
+                                                       p.clear();
+                                                       p.push_back(prefix);
+                                                       p.push_back("Nickname collision");
+                                                       Utils->DoOneToMany(this->Instance->Config->ServerName,"KILL",p);
+                                                       userrec::QuitUser(this->Instance,x,"Nickname collision ("+prefix+" -> "+params[0]+")");
+                                                       userrec* y = this->Instance->FindNick(prefix);
+                                                       if (y)
+                                                       {
+                                                               userrec::QuitUser(this->Instance,y,"Nickname collision");
+                                                       }
+                                                       return Utils->DoOneToAllButSenderRaw(line,sourceserv,prefix,command,params);
+                                               }
+                                       }
+                                       // its a user
+                                       target = who->server;
+                                       const char* strparams[127];
+                                       for (unsigned int q = 0; q < params.size(); q++)
+                                       {
+                                               strparams[q] = params[q].c_str();
+                                       }
+                                       switch (this->Instance->CallCommandHandler(command.c_str(), strparams, params.size(), who))
+                                       {
+                                               case CMD_INVALID:
+                                                       this->SendError("Unrecognised command '"+std::string(command.c_str())+"' -- possibly loaded mismatched modules");
+                                                       return false;
+                                               break;
+                                               case CMD_FAILURE:
+                                                       return true;
+                                               break;
+                                               default:
+                                                       /* CMD_SUCCESS and CMD_USER_DELETED fall through here */
+                                               break;
+                                       }
+                               }
+                               else
+                               {
+                                       // its not a user. Its either a server, or somethings screwed up.
+                                       if (Utils->IsServer(prefix))
+                                               target = this->Instance->Config->ServerName;
+                                       else
+                                               return true;
+                               }
+                               return Utils->DoOneToAllButSenderRaw(line,sourceserv,prefix,command,params);
+
+                       }
+                       return true;
+               break;
+       }
+       return true;
+}
+
+std::string TreeSocket::GetName()
+{
+       std::string sourceserv = this->myhost;
+       if (!this->InboundServerName.empty())
+       {
+               sourceserv = this->InboundServerName;
+       }
+       return sourceserv;
+}
+
+void TreeSocket::OnTimeout()
+{
+       if (this->LinkState == CONNECTING)
+       {
+               this->Instance->SNO->WriteToSnoMask('l',"CONNECT: Connection to \002"+myhost+"\002 timed out.");
+               Link* MyLink = Utils->FindLink(myhost);
+               if (MyLink)
+                       Utils->DoFailOver(MyLink);
+       }
+}
+
+void TreeSocket::OnClose()
+{
+       // Connection closed.
+       // If the connection is fully up (state CONNECTED)
+       // then propogate a netsplit to all peers.
+       std::string quitserver = this->myhost;
+       if (!this->InboundServerName.empty())
+       {
+               quitserver = this->InboundServerName;
+       }
+       TreeServer* s = Utils->FindServer(quitserver);
+       if (s)
+       {
+               Squit(s,"Remote host closed the connection");
+       }
+
+       if (!quitserver.empty())
+       {
+               this->Instance->SNO->WriteToSnoMask('l',"Connection to '\2%s\2' failed.",quitserver.c_str());
+               time_t server_uptime = Instance->Time() - this->age;    
+               if (server_uptime)
+                       Instance->SNO->WriteToSnoMask('l',"Connection to '\2%s\2' was established for %s", quitserver.c_str(), Utils->Creator->TimeToStr(server_uptime).c_str());
+       }
+}
+
+int TreeSocket::OnIncomingConnection(int newsock, char* ip)
+{
+       /* To prevent anyone from attempting to flood opers/DDoS by connecting to the server port,
+        * or discovering if this port is the server port, we don't allow connections from any
+        * IPs for which we don't have a link block.
+        */
+       bool found = false;
+
+       found = (std::find(Utils->ValidIPs.begin(), Utils->ValidIPs.end(), ip) != Utils->ValidIPs.end());
+       if (!found)
+       {
+               for (vector<std::string>::iterator i = Utils->ValidIPs.begin(); i != Utils->ValidIPs.end(); i++)
+                       if (irc::sockets::MatchCIDR(ip, (*i).c_str()))
+                               found = true;
+
+               if (!found)
+               {
+                       this->Instance->SNO->WriteToSnoMask('l',"Server connection from %s denied (no link blocks with that IP address)", ip);
+                       close(newsock);
+                       return false;
+               }
+       }
+
+       TreeSocket* s = new TreeSocket(this->Utils, this->Instance, newsock, ip, this->Hook);
+       s = s; /* Whinge whinge whinge, thats all GCC ever does. */
+       return true;
+}
index 4d0256fa2662428b7f2fbf95b7a5577499f131ac..9675a6ac8588f35dbf2ca71a1d1c41de0a3a1713 100644 (file)
@@ -1 +1,649 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "configreader.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r#include "commands/cmd_whois.h"\r#include "commands/cmd_stats.h"\r#include "socket.h"\r#include "wildcard.h"\r#include "xline.h"\r#include "transport.h"\r#include "socketengine.h"\r\r#include "m_spanningtree/main.h"\r#include "m_spanningtree/utils.h"\r#include "m_spanningtree/treeserver.h"\r#include "m_spanningtree/link.h"\r#include "m_spanningtree/treesocket.h"\r#include "m_spanningtree/resolvers.h"\r\r/* $ModDep: m_spanningtree/timesynctimer.h m_spanningtree/resolvers.h m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/link.h m_spanningtree/treesocket.h */\r\r/** Yay for fast searches!\r * This is hundreds of times faster than recursion\r * or even scanning a linked list, especially when\r * there are more than a few servers to deal with.\r * (read as: lots).\r */\rTreeServer* SpanningTreeUtilities::FindServer(const std::string &ServerName)\r{\r     server_hash::iterator iter = serverlist.find(ServerName.c_str());\r      if (iter != serverlist.end())\r  {\r              return iter->second;\r   }\r      else\r   {\r              return NULL;\r   }\r}\r\rTreeServer* SpanningTreeUtilities::FindRemoteBurstServer(TreeServer* Server)\r{\r    server_hash::iterator iter = RemoteServersBursting.find(Server->GetName().c_str());\r    if (iter != RemoteServersBursting.end())\r               return iter->second;\r   else\r           return NULL;\r}\r\rTreeSocket* SpanningTreeUtilities::FindBurstingServer(const std::string &ServerName)\r{\r std::map<irc::string,TreeSocket*>::iterator iter;\r      iter = burstingserverlist.find(ServerName.c_str());\r    if (iter != burstingserverlist.end())\r  {\r              return iter->second;\r   }\r      else\r   {\r              return NULL;\r   }\r}\r\rvoid SpanningTreeUtilities::SetRemoteBursting(TreeServer* Server, bool bursting)\r{\r        server_hash::iterator iter = RemoteServersBursting.find(Server->GetName().c_str());\r    if (bursting)\r  {\r              if (iter == RemoteServersBursting.end())\r                       RemoteServersBursting.insert(make_pair(Server->GetName(), Server));\r            else return;\r   }\r      else\r   {\r              if (iter != RemoteServersBursting.end())\r                       RemoteServersBursting.erase(iter);\r             else return;\r   }\r      ServerInstance->Log(DEBUG,"Server %s is %sbursting nicknames", Server->GetName().c_str(), bursting ? "" : "no longer ");\r}\r\rvoid SpanningTreeUtilities::AddBurstingServer(const std::string &ServerName, TreeSocket* s)\r{\r      std::map<irc::string,TreeSocket*>::iterator iter = burstingserverlist.find(ServerName.c_str());\r        if (iter == burstingserverlist.end())\r          burstingserverlist[ServerName.c_str()] = s;\r}\r\rvoid SpanningTreeUtilities::DelBurstingServer(TreeSocket* s)\r{\r   for (std::map<irc::string,TreeSocket*>::iterator iter = burstingserverlist.begin(); iter != burstingserverlist.end(); iter++)\r  {\r              if (iter->second == s)\r                 {\r                      burstingserverlist.erase(iter);\r                        return;\r                }\r      }\r}\r\r/** Returns the locally connected server we must route a\r * message through to reach server 'ServerName'. This\r * only applies to one-to-one and not one-to-many routing.\r * See the comments for the constructor of TreeServer\r * for more details.\r */\rTreeServer* SpanningTreeUtilities::BestRouteTo(const std::string &ServerName)\r{\r if (ServerName.c_str() == TreeRoot->GetName())\r         return NULL;\r   TreeServer* Found = FindServer(ServerName);\r    if (Found)\r     {\r              return Found->GetRoute();\r      }\r      else\r   {\r              return NULL;\r   }\r}\r\r/** Find the first server matching a given glob mask.\r * Theres no find-using-glob method of hash_map [awwww :-(]\r * so instead, we iterate over the list using an iterator\r * and match each one until we get a hit. Yes its slow,\r * deal with it.\r */\rTreeServer* SpanningTreeUtilities::FindServerMask(const std::string &ServerName)\r{\r       for (server_hash::iterator i = serverlist.begin(); i != serverlist.end(); i++)\r {\r              if (match(i->first.c_str(),ServerName.c_str()))\r                        return i->second;\r      }\r      return NULL;\r}\r\r/* A convenient wrapper that returns true if a server exists */\rbool SpanningTreeUtilities::IsServer(const std::string &ServerName)\r{\r  return (FindServer(ServerName) != NULL);\r}\r\rSpanningTreeUtilities::SpanningTreeUtilities(InspIRCd* Instance, ModuleSpanningTree* C) : ServerInstance(Instance), Creator(C)\r{\r   Bindings.clear();\r\r     lines_to_apply = 0;\r\r   this->TreeRoot = new TreeServer(this, ServerInstance, ServerInstance->Config->ServerName, ServerInstance->Config->ServerDesc);\r\r        modulelist* ml = ServerInstance->FindInterface("InspSocketHook");\r\r     /* Did we find any modules? */\r if (ml)\r        {\r              /* Yes, enumerate them all to find out the hook name */\r                for (modulelist::iterator m = ml->begin(); m != ml->end(); m++)\r                {\r                      /* Make a request to it for its name, its implementing\r                  * InspSocketHook so we know its safe to do this\r                        */\r                    std::string name = InspSocketNameRequest((Module*)Creator, *m).Send();\r                 /* Build a map of them */\r                      hooks[name.c_str()] = *m;\r                      hooknames.push_back(name);\r             }\r      }\r\r     this->ReadConfiguration(true);\r}\r\rSpanningTreeUtilities::~SpanningTreeUtilities()\r{\r    for (unsigned int i = 0; i < Bindings.size(); i++)\r     {\r              ServerInstance->SE->DelFd(Bindings[i]);\r                Bindings[i]->Close();\r          DELETE(Bindings[i]);\r   }\r      while (TreeRoot->ChildCount())\r {\r              TreeServer* child_server = TreeRoot->GetChild(0);\r              if (child_server)\r              {\r                      TreeSocket* sock = child_server->GetSocket();\r                  ServerInstance->SE->DelFd(sock);\r                       sock->Close();\r                 DELETE(sock);\r          }\r      }\r      delete TreeRoot;\r}\r\rvoid SpanningTreeUtilities::AddThisServer(TreeServer* server, TreeServerList &list)\r{\r      if (list.find(server) == list.end())\r           list[server] = server;\r}\r\r/* returns a list of DIRECT servernames for a specific channel */\rvoid SpanningTreeUtilities::GetListOfServersForChannel(chanrec* c, TreeServerList &list, char status, const CUList &exempt_list)\r{\r CUList *ulist;\r switch (status)\r        {\r              case '@':\r                      ulist = c->GetOppedUsers();\r            break;\r         case '%':\r                      ulist = c->GetHalfoppedUsers();\r                break;\r         case '+':\r                      ulist = c->GetVoicedUsers();\r           break;\r         default:\r                       ulist = c->GetUsers();\r         break;\r }\r      for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)\r      {\r              if ((i->first->GetFd() < 0) && (exempt_list.find(i->first) == exempt_list.end()))\r              {\r                      TreeServer* best = this->BestRouteTo(i->first->server);\r                        if (best)\r                              AddThisServer(best,list);\r              }\r      }\r      return;\r}\r\rbool SpanningTreeUtilities::DoOneToAllButSenderRaw(const std::string &data, const std::string &omit, const std::string &prefix, const irc::string &command, std::deque<std::string> &params)\r{\r      char pfx = 0;\r  TreeServer* omitroute = this->BestRouteTo(omit);\r       if ((command == "NOTICE") || (command == "PRIVMSG"))\r   {\r              if (params.size() >= 2)\r                {\r                      /* Prefixes */\r                 if ((*(params[0].c_str()) == '@') || (*(params[0].c_str()) == '%') || (*(params[0].c_str()) == '+'))\r                   {\r                              pfx = params[0][0];\r                            params[0] = params[0].substr(1, params[0].length()-1);\r                 }\r                      if ((*(params[0].c_str()) != '#') && (*(params[0].c_str()) != '$'))\r                    {\r                              // special routing for private messages/notices\r                                userrec* d = ServerInstance->FindNick(params[0]);\r                              if (d)\r                         {\r                                      std::deque<std::string> par;\r                                   par.push_back(params[0]);\r                                      par.push_back(":"+params[1]);\r                                  this->DoOneToOne(prefix,command.c_str(),par,d->server);\r                                        return true;\r                           }\r                      }\r                      else if (*(params[0].c_str()) == '$')\r                  {\r                              std::deque<std::string> par;\r                           par.push_back(params[0]);\r                              par.push_back(":"+params[1]);\r                          this->DoOneToAllButSender(prefix,command.c_str(),par,omitroute->GetName());\r                            return true;\r                   }\r                      else\r                   {\r                              chanrec* c = ServerInstance->FindChan(params[0]);\r                              userrec* u = ServerInstance->FindNick(prefix);\r                         if (c && u)\r                            {\r                                      CUList elist;\r                                  TreeServerList list;\r                                   FOREACH_MOD(I_OnBuildExemptList, OnBuildExemptList((command == "PRIVMSG" ? MSG_PRIVMSG : MSG_NOTICE), c, u, pfx, elist));\r                                      GetListOfServersForChannel(c,list,pfx,elist);\r\r                                 for (TreeServerList::iterator i = list.begin(); i != list.end(); i++)\r                                  {\r                                              TreeSocket* Sock = i->second->GetSocket();\r                                             if ((Sock) && (i->second->GetName() != omit) && (omitroute != i->second))\r                                              {\r                                                      Sock->WriteLine(data);\r                                         }\r                                      }\r                                      return true;\r                           }\r                      }\r              }\r      }\r      unsigned int items =this->TreeRoot->ChildCount();\r      for (unsigned int x = 0; x < items; x++)\r       {\r              TreeServer* Route = this->TreeRoot->GetChild(x);\r               if ((Route) && (Route->GetSocket()) && (Route->GetName() != omit) && (omitroute != Route))\r             {\r                      TreeSocket* Sock = Route->GetSocket();\r                 if (Sock)\r                              Sock->WriteLine(data);\r         }\r      }\r      return true;\r}\r\rbool SpanningTreeUtilities::DoOneToAllButSender(const std::string &prefix, const std::string &command, std::deque<std::string> &params, std::string omit)\r{\r    TreeServer* omitroute = this->BestRouteTo(omit);\r       std::string FullLine = ":" + prefix + " " + command;\r   unsigned int words = params.size();\r    for (unsigned int x = 0; x < words; x++)\r       {\r              FullLine = FullLine + " " + params[x];\r }\r      unsigned int items = this->TreeRoot->ChildCount();\r     for (unsigned int x = 0; x < items; x++)\r       {\r              TreeServer* Route = this->TreeRoot->GetChild(x);\r               // Send the line IF:\r           // The route has a socket (its a direct connection)\r            // The route isnt the one to be omitted\r                // The route isnt the path to the one to be omitted\r            if ((Route) && (Route->GetSocket()) && (Route->GetName() != omit) && (omitroute != Route))\r             {\r                      TreeSocket* Sock = Route->GetSocket();\r                 if (Sock)\r                              Sock->WriteLine(FullLine);\r             }\r      }\r      return true;\r}\r\rbool SpanningTreeUtilities::DoOneToMany(const std::string &prefix, const std::string &command, std::deque<std::string> &params)\r{\r      std::string FullLine = ":" + prefix + " " + command;\r   unsigned int words = params.size();\r    for (unsigned int x = 0; x < words; x++)\r       {\r              FullLine = FullLine + " " + params[x];\r }\r      unsigned int items = this->TreeRoot->ChildCount();\r     for (unsigned int x = 0; x < items; x++)\r       {\r              TreeServer* Route = this->TreeRoot->GetChild(x);\r               if (Route && Route->GetSocket())\r               {\r                      TreeSocket* Sock = Route->GetSocket();\r                 if (Sock)\r                              Sock->WriteLine(FullLine);\r             }\r      }\r      return true;\r}\r\rbool SpanningTreeUtilities::DoOneToMany(const char* prefix, const char* command, std::deque<std::string> &params)\r{\r    std::string spfx = prefix;\r     std::string scmd = command;\r    return this->DoOneToMany(spfx, scmd, params);\r}\r\rbool SpanningTreeUtilities::DoOneToAllButSender(const char* prefix, const char* command, std::deque<std::string> &params, std::string omit)\r{\r std::string spfx = prefix;\r     std::string scmd = command;\r    return this->DoOneToAllButSender(spfx, scmd, params, omit);\r}\r\rbool SpanningTreeUtilities::DoOneToOne(const std::string &prefix, const std::string &command, std::deque<std::string> &params, std::string target)\r{\r    TreeServer* Route = this->BestRouteTo(target);\r if (Route)\r     {\r              std::string FullLine = ":" + prefix + " " + command;\r           unsigned int words = params.size();\r            for (unsigned int x = 0; x < words; x++)\r               {\r                      FullLine = FullLine + " " + params[x];\r         }\r              if (Route && Route->GetSocket())\r               {\r                      TreeSocket* Sock = Route->GetSocket();\r                 if (Sock)\r                              Sock->WriteLine(FullLine);\r             }\r              return true;\r   }\r      else\r   {\r              return false;\r  }\r}\r\rvoid SpanningTreeUtilities::RefreshIPCache()\r{\r    ValidIPs.clear();\r      for (std::vector<Link>::iterator L = LinkBlocks.begin(); L != LinkBlocks.end(); L++)\r   {\r              if ((!L->IPAddr.empty()) && (!L->RecvPass.empty()) && (!L->SendPass.empty()) && (!L->Name.empty()) && (L->Port))\r               {\r                      ValidIPs.push_back(L->IPAddr);\r\r                        if (L->AllowMask.length())\r                             ValidIPs.push_back(L->AllowMask);\r\r                     /* Needs resolving */\r                  bool ipvalid = true;\r                   QueryType start_type = DNS_QUERY_A;\r#ifdef IPV6\r                        start_type = DNS_QUERY_AAAA;\r                   if (strchr(L->IPAddr.c_str(),':'))\r                     {\r                              in6_addr n;\r                            if (inet_pton(AF_INET6, L->IPAddr.c_str(), &n) < 1)\r                                    ipvalid = false;\r                       }\r                      else\r#endif\r                    {\r                              in_addr n;\r                             if (inet_aton(L->IPAddr.c_str(),&n) < 1)\r                                       ipvalid = false;\r                       }\r                      if (!ipvalid)\r                  {\r                              try\r                            {\r                                      bool cached;\r                                   SecurityIPResolver* sr = new SecurityIPResolver((Module*)this->Creator, this, ServerInstance, L->IPAddr, *L, cached, start_type);\r                                      ServerInstance->AddResolver(sr, cached);\r                               }\r                              catch (...)\r                            {\r                              }\r                      }\r              }\r      }\r}\r\rvoid SpanningTreeUtilities::ReadConfiguration(bool rebind)\r{\r      ConfigReader* Conf = new ConfigReader(ServerInstance);\r if (rebind)\r    {\r              for (int j = 0; j < Conf->Enumerate("bind"); j++)\r              {\r                      std::string Type = Conf->ReadValue("bind","type",j);\r                   std::string IP = Conf->ReadValue("bind","address",j);\r                  std::string Port = Conf->ReadValue("bind","port",j);\r                   std::string transport = Conf->ReadValue("bind","transport",j);\r                 if (Type == "servers")\r                 {\r                              irc::portparser portrange(Port, false);\r                                int portno = -1;\r                               while ((portno = portrange.GetToken()))\r                                {\r                                      if (IP == "*")\r                                         IP.clear();\r\r                                   if ((!transport.empty()) && (hooks.find(transport.c_str()) ==  hooks.end()))\r                                   {\r                                              ServerInstance->Log(DEFAULT,"m_spanningtree: WARNING: Can't find transport type '%s' for port %s:%s - maybe you forgot to load it BEFORE m_spanningtree in your config file? - Skipping this port binding", transport.c_str(), IP.c_str(), Port.c_str());\r                                              break;\r                                 }\r\r                                     TreeSocket* listener = new TreeSocket(this, ServerInstance, IP.c_str(), portno, true, 10, transport.empty() ? NULL : hooks[transport.c_str()]);\r                                        if (listener->GetState() == I_LISTENING)\r                                       {\r                                              ServerInstance->Log(DEFAULT,"m_spanningtree: Binding server port %s:%d successful!", IP.c_str(), portno);\r                                              Bindings.push_back(listener);\r                                  }\r                                      else\r                                   {\r                                              ServerInstance->Log(DEFAULT,"m_spanningtree: Warning: Failed to bind server port: %s:%d: %s",IP.c_str(), portno, strerror(errno));\r                                             listener->Close();\r                                             DELETE(listener);\r                                      }\r                              }\r                      }\r              }\r      }\r      FlatLinks = Conf->ReadFlag("options","flatlinks",0);\r   HideULines = Conf->ReadFlag("options","hideulines",0);\r AnnounceTSChange = Conf->ReadFlag("options","announcets",0);\r   EnableTimeSync = Conf->ReadFlag("timesync","enable",0);\r        MasterTime = Conf->ReadFlag("timesync", "master", 0);\r  ChallengeResponse = !Conf->ReadFlag("options", "disablehmac", 0);\r      quiet_bursts = Conf->ReadFlag("options", "quietbursts", 0);\r    PingWarnTime = Conf->ReadInteger("options", "pingwarning", 0, true);\r\r  if (PingWarnTime < 0 || PingWarnTime > 59)\r             PingWarnTime = 0;\r\r     LinkBlocks.clear();\r    ValidIPs.clear();\r      for (int j = 0; j < Conf->Enumerate("link"); j++)\r      {\r              Link L;\r                std::string Allow = Conf->ReadValue("link", "allowmask", j);\r           L.Name = (Conf->ReadValue("link", "name", j)).c_str();\r         L.AllowMask = Allow;\r           L.IPAddr = Conf->ReadValue("link", "ipaddr", j);\r               L.FailOver = Conf->ReadValue("link", "failover", j).c_str();\r           L.Port = Conf->ReadInteger("link", "port", j, true);\r           L.SendPass = Conf->ReadValue("link", "sendpass", j);\r           L.RecvPass = Conf->ReadValue("link", "recvpass", j);\r           L.AutoConnect = Conf->ReadInteger("link", "autoconnect", j, true);\r             L.HiddenFromStats = Conf->ReadFlag("link", "statshidden", j);\r          L.Timeout = Conf->ReadInteger("link", "timeout", j, true);\r             L.Hook = Conf->ReadValue("link", "transport", j);\r              L.Bind = Conf->ReadValue("link", "bind", j);\r           L.Hidden = Conf->ReadFlag("link", "hidden", j);\r\r               if ((!L.Hook.empty()) && (hooks.find(L.Hook.c_str()) ==  hooks.end()))\r         {\r                      ServerInstance->Log(DEFAULT,"m_spanningtree: WARNING: Can't find transport type '%s' for link '%s' - maybe you forgot to load it BEFORE m_spanningtree in your config file? Skipping <link> tag completely.",\r                  L.Hook.c_str(), L.Name.c_str());\r                       continue;\r\r             }\r\r             L.NextConnectTime = time(NULL) + L.AutoConnect;\r                /* Bugfix by brain, do not allow people to enter bad configurations */\r         if (L.Name != ServerInstance->Config->ServerName)\r              {\r                      if ((!L.IPAddr.empty()) && (!L.RecvPass.empty()) && (!L.SendPass.empty()) && (!L.Name.empty()) && (L.Port))\r                    {\r                              ValidIPs.push_back(L.IPAddr);\r\r                         if (Allow.length())\r                                    ValidIPs.push_back(Allow);\r\r                            /* Needs resolving */\r                          bool ipvalid = true;\r                           QueryType start_type = DNS_QUERY_A;\r#ifdef IPV6\r                                start_type = DNS_QUERY_AAAA;\r                           if (strchr(L.IPAddr.c_str(),':'))\r                              {\r                                      in6_addr n;\r                                    if (inet_pton(AF_INET6, L.IPAddr.c_str(), &n) < 1)\r                                             ipvalid = false;\r                               }\r                              else\r                           {\r                                      in_addr n;\r                                     if (inet_aton(L.IPAddr.c_str(),&n) < 1)\r                                                ipvalid = false;\r                               }\r#else\r                                in_addr n;\r                             if (inet_aton(L.IPAddr.c_str(),&n) < 1)\r                                        ipvalid = false;\r#endif\r\r                               if (!ipvalid)\r                          {\r                                      try\r                                    {\r                                              bool cached;\r                                           SecurityIPResolver* sr = new SecurityIPResolver((Module*)this->Creator, this, ServerInstance, L.IPAddr, L, cached, start_type);\r                                                ServerInstance->AddResolver(sr, cached);\r                                       }\r                                      catch (...)\r                                    {\r                                      }\r                              }\r\r                             LinkBlocks.push_back(L);\r                       }\r                      else\r                   {\r                              if (L.IPAddr.empty())\r                          {\r                                      ServerInstance->Log(DEFAULT,"Invalid configuration for server '%s', IP address not defined!",L.Name.c_str());\r                          }\r                              else if (L.RecvPass.empty())\r                           {\r                                      ServerInstance->Log(DEFAULT,"Invalid configuration for server '%s', recvpass not defined!",L.Name.c_str());\r                            }\r                              else if (L.SendPass.empty())\r                           {\r                                      ServerInstance->Log(DEFAULT,"Invalid configuration for server '%s', sendpass not defined!",L.Name.c_str());\r                            }\r                              else if (L.Name.empty())\r                               {\r                                      ServerInstance->Log(DEFAULT,"Invalid configuration, link tag without a name!");\r                                }\r                              else if (!L.Port)\r                              {\r                                      ServerInstance->Log(DEFAULT,"Invalid configuration for server '%s', no port specified!",L.Name.c_str());\r                               }\r                      }\r              }\r              else\r           {\r                      ServerInstance->Log(DEFAULT,"Invalid configuration for server '%s', link tag has the same server name as the local server!",L.Name.c_str());\r           }\r      }\r      DELETE(Conf);\r}\r\rvoid SpanningTreeUtilities::DoFailOver(Link* x)\r{\r     if (x->FailOver.length())\r      {\r              if (x->FailOver == x->Name)\r            {\r                      ServerInstance->SNO->WriteToSnoMask('l',"FAILOVER: Some muppet configured the failover for server \002%s\002 to point at itself. Not following it!", x->Name.c_str());\r                 return;\r                }\r              Link* TryThisOne = this->FindLink(x->FailOver.c_str());\r                if (TryThisOne)\r                {\r                      ServerInstance->SNO->WriteToSnoMask('l',"FAILOVER: Trying failover link for \002%s\002: \002%s\002...", x->Name.c_str(), TryThisOne->Name.c_str());\r                    Creator->ConnectServer(TryThisOne);\r            }\r              else\r           {\r                      ServerInstance->SNO->WriteToSnoMask('l',"FAILOVER: Invalid failover server specified for server \002%s\002, will not follow!", x->Name.c_str());\r               }\r      }\r}\r\rLink* SpanningTreeUtilities::FindLink(const std::string& name)\r{\r  for (std::vector<Link>::iterator x = LinkBlocks.begin(); x < LinkBlocks.end(); x++)\r    {\r              if (ServerInstance->MatchText(x->Name.c_str(), name.c_str()))\r          {\r                      return &(*x);\r          }\r      }\r      return NULL;\r}\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "configreader.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+#include "commands/cmd_whois.h"
+#include "commands/cmd_stats.h"
+#include "socket.h"
+#include "wildcard.h"
+#include "xline.h"
+#include "transport.h"
+#include "socketengine.h"
+
+#include "m_spanningtree/main.h"
+#include "m_spanningtree/utils.h"
+#include "m_spanningtree/treeserver.h"
+#include "m_spanningtree/link.h"
+#include "m_spanningtree/treesocket.h"
+#include "m_spanningtree/resolvers.h"
+
+/* $ModDep: m_spanningtree/timesynctimer.h m_spanningtree/resolvers.h m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/link.h m_spanningtree/treesocket.h */
+
+/** Yay for fast searches!
+ * This is hundreds of times faster than recursion
+ * or even scanning a linked list, especially when
+ * there are more than a few servers to deal with.
+ * (read as: lots).
+ */
+TreeServer* SpanningTreeUtilities::FindServer(const std::string &ServerName)
+{
+       server_hash::iterator iter = serverlist.find(ServerName.c_str());
+       if (iter != serverlist.end())
+       {
+               return iter->second;
+       }
+       else
+       {
+               return NULL;
+       }
+}
+
+TreeServer* SpanningTreeUtilities::FindRemoteBurstServer(TreeServer* Server)
+{
+       server_hash::iterator iter = RemoteServersBursting.find(Server->GetName().c_str());
+       if (iter != RemoteServersBursting.end())
+               return iter->second;
+       else
+               return NULL;
+}
+
+TreeSocket* SpanningTreeUtilities::FindBurstingServer(const std::string &ServerName)
+{
+       std::map<irc::string,TreeSocket*>::iterator iter;
+       iter = burstingserverlist.find(ServerName.c_str());
+       if (iter != burstingserverlist.end())
+       {
+               return iter->second;
+       }
+       else
+       {
+               return NULL;
+       }
+}
+
+void SpanningTreeUtilities::SetRemoteBursting(TreeServer* Server, bool bursting)
+{
+       server_hash::iterator iter = RemoteServersBursting.find(Server->GetName().c_str());
+       if (bursting)
+       {
+               if (iter == RemoteServersBursting.end())
+                       RemoteServersBursting.insert(make_pair(Server->GetName(), Server));
+               else return;
+       }
+       else
+       {
+               if (iter != RemoteServersBursting.end())
+                       RemoteServersBursting.erase(iter);
+               else return;
+       }
+       ServerInstance->Log(DEBUG,"Server %s is %sbursting nicknames", Server->GetName().c_str(), bursting ? "" : "no longer ");
+}
+
+void SpanningTreeUtilities::AddBurstingServer(const std::string &ServerName, TreeSocket* s)
+{
+       std::map<irc::string,TreeSocket*>::iterator iter = burstingserverlist.find(ServerName.c_str());
+       if (iter == burstingserverlist.end())
+               burstingserverlist[ServerName.c_str()] = s;
+}
+
+void SpanningTreeUtilities::DelBurstingServer(TreeSocket* s)
+{
+        for (std::map<irc::string,TreeSocket*>::iterator iter = burstingserverlist.begin(); iter != burstingserverlist.end(); iter++)
+        {
+                if (iter->second == s)
+                {
+                        burstingserverlist.erase(iter);
+                        return;
+                }
+        }
+}
+
+/** Returns the locally connected server we must route a
+ * message through to reach server 'ServerName'. This
+ * only applies to one-to-one and not one-to-many routing.
+ * See the comments for the constructor of TreeServer
+ * for more details.
+ */
+TreeServer* SpanningTreeUtilities::BestRouteTo(const std::string &ServerName)
+{
+       if (ServerName.c_str() == TreeRoot->GetName())
+               return NULL;
+       TreeServer* Found = FindServer(ServerName);
+       if (Found)
+       {
+               return Found->GetRoute();
+       }
+       else
+       {
+               return NULL;
+       }
+}
+
+/** Find the first server matching a given glob mask.
+ * Theres no find-using-glob method of hash_map [awwww :-(]
+ * so instead, we iterate over the list using an iterator
+ * and match each one until we get a hit. Yes its slow,
+ * deal with it.
+ */
+TreeServer* SpanningTreeUtilities::FindServerMask(const std::string &ServerName)
+{
+       for (server_hash::iterator i = serverlist.begin(); i != serverlist.end(); i++)
+       {
+               if (match(i->first.c_str(),ServerName.c_str()))
+                       return i->second;
+       }
+       return NULL;
+}
+
+/* A convenient wrapper that returns true if a server exists */
+bool SpanningTreeUtilities::IsServer(const std::string &ServerName)
+{
+       return (FindServer(ServerName) != NULL);
+}
+
+SpanningTreeUtilities::SpanningTreeUtilities(InspIRCd* Instance, ModuleSpanningTree* C) : ServerInstance(Instance), Creator(C)
+{
+       Bindings.clear();
+
+       lines_to_apply = 0;
+
+       this->TreeRoot = new TreeServer(this, ServerInstance, ServerInstance->Config->ServerName, ServerInstance->Config->ServerDesc);
+
+       modulelist* ml = ServerInstance->FindInterface("InspSocketHook");
+
+       /* Did we find any modules? */
+       if (ml)
+       {
+               /* Yes, enumerate them all to find out the hook name */
+               for (modulelist::iterator m = ml->begin(); m != ml->end(); m++)
+               {
+                       /* Make a request to it for its name, its implementing
+                        * InspSocketHook so we know its safe to do this
+                        */
+                       std::string name = InspSocketNameRequest((Module*)Creator, *m).Send();
+                       /* Build a map of them */
+                       hooks[name.c_str()] = *m;
+                       hooknames.push_back(name);
+               }
+       }
+
+       this->ReadConfiguration(true);
+}
+
+SpanningTreeUtilities::~SpanningTreeUtilities()
+{
+       for (unsigned int i = 0; i < Bindings.size(); i++)
+       {
+               ServerInstance->SE->DelFd(Bindings[i]);
+               Bindings[i]->Close();
+               DELETE(Bindings[i]);
+       }
+       while (TreeRoot->ChildCount())
+       {
+               TreeServer* child_server = TreeRoot->GetChild(0);
+               if (child_server)
+               {
+                       TreeSocket* sock = child_server->GetSocket();
+                       ServerInstance->SE->DelFd(sock);
+                       sock->Close();
+                       DELETE(sock);
+               }
+       }
+       delete TreeRoot;
+}
+
+void SpanningTreeUtilities::AddThisServer(TreeServer* server, TreeServerList &list)
+{
+       if (list.find(server) == list.end())
+               list[server] = server;
+}
+
+/* returns a list of DIRECT servernames for a specific channel */
+void SpanningTreeUtilities::GetListOfServersForChannel(chanrec* c, TreeServerList &list, char status, const CUList &exempt_list)
+{
+       CUList *ulist;
+       switch (status)
+       {
+               case '@':
+                       ulist = c->GetOppedUsers();
+               break;
+               case '%':
+                       ulist = c->GetHalfoppedUsers();
+               break;
+               case '+':
+                       ulist = c->GetVoicedUsers();
+               break;
+               default:
+                       ulist = c->GetUsers();
+               break;
+       }
+       for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
+       {
+               if ((i->first->GetFd() < 0) && (exempt_list.find(i->first) == exempt_list.end()))
+               {
+                       TreeServer* best = this->BestRouteTo(i->first->server);
+                       if (best)
+                               AddThisServer(best,list);
+               }
+       }
+       return;
+}
+
+bool SpanningTreeUtilities::DoOneToAllButSenderRaw(const std::string &data, const std::string &omit, const std::string &prefix, const irc::string &command, std::deque<std::string> &params)
+{
+       char pfx = 0;
+       TreeServer* omitroute = this->BestRouteTo(omit);
+       if ((command == "NOTICE") || (command == "PRIVMSG"))
+       {
+               if (params.size() >= 2)
+               {
+                       /* Prefixes */
+                       if ((*(params[0].c_str()) == '@') || (*(params[0].c_str()) == '%') || (*(params[0].c_str()) == '+'))
+                       {
+                               pfx = params[0][0];
+                               params[0] = params[0].substr(1, params[0].length()-1);
+                       }
+                       if ((*(params[0].c_str()) != '#') && (*(params[0].c_str()) != '$'))
+                       {
+                               // special routing for private messages/notices
+                               userrec* d = ServerInstance->FindNick(params[0]);
+                               if (d)
+                               {
+                                       std::deque<std::string> par;
+                                       par.push_back(params[0]);
+                                       par.push_back(":"+params[1]);
+                                       this->DoOneToOne(prefix,command.c_str(),par,d->server);
+                                       return true;
+                               }
+                       }
+                       else if (*(params[0].c_str()) == '$')
+                       {
+                               std::deque<std::string> par;
+                               par.push_back(params[0]);
+                               par.push_back(":"+params[1]);
+                               this->DoOneToAllButSender(prefix,command.c_str(),par,omitroute->GetName());
+                               return true;
+                       }
+                       else
+                       {
+                               chanrec* c = ServerInstance->FindChan(params[0]);
+                               userrec* u = ServerInstance->FindNick(prefix);
+                               if (c && u)
+                               {
+                                       CUList elist;
+                                       TreeServerList list;
+                                       FOREACH_MOD(I_OnBuildExemptList, OnBuildExemptList((command == "PRIVMSG" ? MSG_PRIVMSG : MSG_NOTICE), c, u, pfx, elist));
+                                       GetListOfServersForChannel(c,list,pfx,elist);
+
+                                       for (TreeServerList::iterator i = list.begin(); i != list.end(); i++)
+                                       {
+                                               TreeSocket* Sock = i->second->GetSocket();
+                                               if ((Sock) && (i->second->GetName() != omit) && (omitroute != i->second))
+                                               {
+                                                       Sock->WriteLine(data);
+                                               }
+                                       }
+                                       return true;
+                               }
+                       }
+               }
+       }
+       unsigned int items =this->TreeRoot->ChildCount();
+       for (unsigned int x = 0; x < items; x++)
+       {
+               TreeServer* Route = this->TreeRoot->GetChild(x);
+               if ((Route) && (Route->GetSocket()) && (Route->GetName() != omit) && (omitroute != Route))
+               {
+                       TreeSocket* Sock = Route->GetSocket();
+                       if (Sock)
+                               Sock->WriteLine(data);
+               }
+       }
+       return true;
+}
+
+bool SpanningTreeUtilities::DoOneToAllButSender(const std::string &prefix, const std::string &command, std::deque<std::string> &params, std::string omit)
+{
+       TreeServer* omitroute = this->BestRouteTo(omit);
+       std::string FullLine = ":" + prefix + " " + command;
+       unsigned int words = params.size();
+       for (unsigned int x = 0; x < words; x++)
+       {
+               FullLine = FullLine + " " + params[x];
+       }
+       unsigned int items = this->TreeRoot->ChildCount();
+       for (unsigned int x = 0; x < items; x++)
+       {
+               TreeServer* Route = this->TreeRoot->GetChild(x);
+               // Send the line IF:
+               // The route has a socket (its a direct connection)
+               // The route isnt the one to be omitted
+               // The route isnt the path to the one to be omitted
+               if ((Route) && (Route->GetSocket()) && (Route->GetName() != omit) && (omitroute != Route))
+               {
+                       TreeSocket* Sock = Route->GetSocket();
+                       if (Sock)
+                               Sock->WriteLine(FullLine);
+               }
+       }
+       return true;
+}
+
+bool SpanningTreeUtilities::DoOneToMany(const std::string &prefix, const std::string &command, std::deque<std::string> &params)
+{
+       std::string FullLine = ":" + prefix + " " + command;
+       unsigned int words = params.size();
+       for (unsigned int x = 0; x < words; x++)
+       {
+               FullLine = FullLine + " " + params[x];
+       }
+       unsigned int items = this->TreeRoot->ChildCount();
+       for (unsigned int x = 0; x < items; x++)
+       {
+               TreeServer* Route = this->TreeRoot->GetChild(x);
+               if (Route && Route->GetSocket())
+               {
+                       TreeSocket* Sock = Route->GetSocket();
+                       if (Sock)
+                               Sock->WriteLine(FullLine);
+               }
+       }
+       return true;
+}
+
+bool SpanningTreeUtilities::DoOneToMany(const char* prefix, const char* command, std::deque<std::string> &params)
+{
+       std::string spfx = prefix;
+       std::string scmd = command;
+       return this->DoOneToMany(spfx, scmd, params);
+}
+
+bool SpanningTreeUtilities::DoOneToAllButSender(const char* prefix, const char* command, std::deque<std::string> &params, std::string omit)
+{
+       std::string spfx = prefix;
+       std::string scmd = command;
+       return this->DoOneToAllButSender(spfx, scmd, params, omit);
+}
+
+bool SpanningTreeUtilities::DoOneToOne(const std::string &prefix, const std::string &command, std::deque<std::string> &params, std::string target)
+{
+       TreeServer* Route = this->BestRouteTo(target);
+       if (Route)
+       {
+               std::string FullLine = ":" + prefix + " " + command;
+               unsigned int words = params.size();
+               for (unsigned int x = 0; x < words; x++)
+               {
+                       FullLine = FullLine + " " + params[x];
+               }
+               if (Route && Route->GetSocket())
+               {
+                       TreeSocket* Sock = Route->GetSocket();
+                       if (Sock)
+                               Sock->WriteLine(FullLine);
+               }
+               return true;
+       }
+       else
+       {
+               return false;
+       }
+}
+
+void SpanningTreeUtilities::RefreshIPCache()
+{
+       ValidIPs.clear();
+       for (std::vector<Link>::iterator L = LinkBlocks.begin(); L != LinkBlocks.end(); L++)
+       {
+               if ((!L->IPAddr.empty()) && (!L->RecvPass.empty()) && (!L->SendPass.empty()) && (!L->Name.empty()) && (L->Port))
+               {
+                       ValidIPs.push_back(L->IPAddr);
+
+                       if (L->AllowMask.length())
+                               ValidIPs.push_back(L->AllowMask);
+
+                       /* Needs resolving */
+                       bool ipvalid = true;
+                       QueryType start_type = DNS_QUERY_A;
+#ifdef IPV6
+                       start_type = DNS_QUERY_AAAA;
+                       if (strchr(L->IPAddr.c_str(),':'))
+                       {
+                               in6_addr n;
+                               if (inet_pton(AF_INET6, L->IPAddr.c_str(), &n) < 1)
+                                       ipvalid = false;
+                       }
+                       else
+#endif
+                       {
+                               in_addr n;
+                               if (inet_aton(L->IPAddr.c_str(),&n) < 1)
+                                       ipvalid = false;
+                       }
+                       if (!ipvalid)
+                       {
+                               try
+                               {
+                                       bool cached;
+                                       SecurityIPResolver* sr = new SecurityIPResolver((Module*)this->Creator, this, ServerInstance, L->IPAddr, *L, cached, start_type);
+                                       ServerInstance->AddResolver(sr, cached);
+                               }
+                               catch (...)
+                               {
+                               }
+                       }
+               }
+       }
+}
+
+void SpanningTreeUtilities::ReadConfiguration(bool rebind)
+{
+       ConfigReader* Conf = new ConfigReader(ServerInstance);
+       if (rebind)
+       {
+               for (int j = 0; j < Conf->Enumerate("bind"); j++)
+               {
+                       std::string Type = Conf->ReadValue("bind","type",j);
+                       std::string IP = Conf->ReadValue("bind","address",j);
+                       std::string Port = Conf->ReadValue("bind","port",j);
+                       std::string transport = Conf->ReadValue("bind","transport",j);
+                       if (Type == "servers")
+                       {
+                               irc::portparser portrange(Port, false);
+                               int portno = -1;
+                               while ((portno = portrange.GetToken()))
+                               {
+                                       if (IP == "*")
+                                               IP.clear();
+
+                                       if ((!transport.empty()) && (hooks.find(transport.c_str()) ==  hooks.end()))
+                                       {
+                                               ServerInstance->Log(DEFAULT,"m_spanningtree: WARNING: Can't find transport type '%s' for port %s:%s - maybe you forgot to load it BEFORE m_spanningtree in your config file? - Skipping this port binding", transport.c_str(), IP.c_str(), Port.c_str());
+                                               break;
+                                       }
+
+                                       TreeSocket* listener = new TreeSocket(this, ServerInstance, IP.c_str(), portno, true, 10, transport.empty() ? NULL : hooks[transport.c_str()]);
+                                       if (listener->GetState() == I_LISTENING)
+                                       {
+                                               ServerInstance->Log(DEFAULT,"m_spanningtree: Binding server port %s:%d successful!", IP.c_str(), portno);
+                                               Bindings.push_back(listener);
+                                       }
+                                       else
+                                       {
+                                               ServerInstance->Log(DEFAULT,"m_spanningtree: Warning: Failed to bind server port: %s:%d: %s",IP.c_str(), portno, strerror(errno));
+                                               listener->Close();
+                                               DELETE(listener);
+                                       }
+                               }
+                       }
+               }
+       }
+       FlatLinks = Conf->ReadFlag("options","flatlinks",0);
+       HideULines = Conf->ReadFlag("options","hideulines",0);
+       AnnounceTSChange = Conf->ReadFlag("options","announcets",0);
+       EnableTimeSync = Conf->ReadFlag("timesync","enable",0);
+       MasterTime = Conf->ReadFlag("timesync", "master", 0);
+       ChallengeResponse = !Conf->ReadFlag("options", "disablehmac", 0);
+       quiet_bursts = Conf->ReadFlag("options", "quietbursts", 0);
+       PingWarnTime = Conf->ReadInteger("options", "pingwarning", 0, true);
+
+       if (PingWarnTime < 0 || PingWarnTime > 59)
+               PingWarnTime = 0;
+
+       LinkBlocks.clear();
+       ValidIPs.clear();
+       for (int j = 0; j < Conf->Enumerate("link"); j++)
+       {
+               Link L;
+               std::string Allow = Conf->ReadValue("link", "allowmask", j);
+               L.Name = (Conf->ReadValue("link", "name", j)).c_str();
+               L.AllowMask = Allow;
+               L.IPAddr = Conf->ReadValue("link", "ipaddr", j);
+               L.FailOver = Conf->ReadValue("link", "failover", j).c_str();
+               L.Port = Conf->ReadInteger("link", "port", j, true);
+               L.SendPass = Conf->ReadValue("link", "sendpass", j);
+               L.RecvPass = Conf->ReadValue("link", "recvpass", j);
+               L.AutoConnect = Conf->ReadInteger("link", "autoconnect", j, true);
+               L.HiddenFromStats = Conf->ReadFlag("link", "statshidden", j);
+               L.Timeout = Conf->ReadInteger("link", "timeout", j, true);
+               L.Hook = Conf->ReadValue("link", "transport", j);
+               L.Bind = Conf->ReadValue("link", "bind", j);
+               L.Hidden = Conf->ReadFlag("link", "hidden", j);
+
+               if ((!L.Hook.empty()) && (hooks.find(L.Hook.c_str()) ==  hooks.end()))
+               {
+                       ServerInstance->Log(DEFAULT,"m_spanningtree: WARNING: Can't find transport type '%s' for link '%s' - maybe you forgot to load it BEFORE m_spanningtree in your config file? Skipping <link> tag completely.",
+                       L.Hook.c_str(), L.Name.c_str());
+                       continue;
+
+               }
+
+               L.NextConnectTime = time(NULL) + L.AutoConnect;
+               /* Bugfix by brain, do not allow people to enter bad configurations */
+               if (L.Name != ServerInstance->Config->ServerName)
+               {
+                       if ((!L.IPAddr.empty()) && (!L.RecvPass.empty()) && (!L.SendPass.empty()) && (!L.Name.empty()) && (L.Port))
+                       {
+                               ValidIPs.push_back(L.IPAddr);
+
+                               if (Allow.length())
+                                       ValidIPs.push_back(Allow);
+
+                               /* Needs resolving */
+                               bool ipvalid = true;
+                               QueryType start_type = DNS_QUERY_A;
+#ifdef IPV6
+                               start_type = DNS_QUERY_AAAA;
+                               if (strchr(L.IPAddr.c_str(),':'))
+                               {
+                                       in6_addr n;
+                                       if (inet_pton(AF_INET6, L.IPAddr.c_str(), &n) < 1)
+                                               ipvalid = false;
+                               }
+                               else
+                               {
+                                       in_addr n;
+                                       if (inet_aton(L.IPAddr.c_str(),&n) < 1)
+                                               ipvalid = false;
+                               }
+#else
+                               in_addr n;
+                               if (inet_aton(L.IPAddr.c_str(),&n) < 1)
+                                       ipvalid = false;
+#endif
+
+                               if (!ipvalid)
+                               {
+                                       try
+                                       {
+                                               bool cached;
+                                               SecurityIPResolver* sr = new SecurityIPResolver((Module*)this->Creator, this, ServerInstance, L.IPAddr, L, cached, start_type);
+                                               ServerInstance->AddResolver(sr, cached);
+                                       }
+                                       catch (...)
+                                       {
+                                       }
+                               }
+
+                               LinkBlocks.push_back(L);
+                       }
+                       else
+                       {
+                               if (L.IPAddr.empty())
+                               {
+                                       ServerInstance->Log(DEFAULT,"Invalid configuration for server '%s', IP address not defined!",L.Name.c_str());
+                               }
+                               else if (L.RecvPass.empty())
+                               {
+                                       ServerInstance->Log(DEFAULT,"Invalid configuration for server '%s', recvpass not defined!",L.Name.c_str());
+                               }
+                               else if (L.SendPass.empty())
+                               {
+                                       ServerInstance->Log(DEFAULT,"Invalid configuration for server '%s', sendpass not defined!",L.Name.c_str());
+                               }
+                               else if (L.Name.empty())
+                               {
+                                       ServerInstance->Log(DEFAULT,"Invalid configuration, link tag without a name!");
+                               }
+                               else if (!L.Port)
+                               {
+                                       ServerInstance->Log(DEFAULT,"Invalid configuration for server '%s', no port specified!",L.Name.c_str());
+                               }
+                       }
+               }
+               else
+               {
+                       ServerInstance->Log(DEFAULT,"Invalid configuration for server '%s', link tag has the same server name as the local server!",L.Name.c_str());
+               }
+       }
+       DELETE(Conf);
+}
+
+void SpanningTreeUtilities::DoFailOver(Link* x)
+{
+       if (x->FailOver.length())
+       {
+               if (x->FailOver == x->Name)
+               {
+                       ServerInstance->SNO->WriteToSnoMask('l',"FAILOVER: Some muppet configured the failover for server \002%s\002 to point at itself. Not following it!", x->Name.c_str());
+                       return;
+               }
+               Link* TryThisOne = this->FindLink(x->FailOver.c_str());
+               if (TryThisOne)
+               {
+                       ServerInstance->SNO->WriteToSnoMask('l',"FAILOVER: Trying failover link for \002%s\002: \002%s\002...", x->Name.c_str(), TryThisOne->Name.c_str());
+                       Creator->ConnectServer(TryThisOne);
+               }
+               else
+               {
+                       ServerInstance->SNO->WriteToSnoMask('l',"FAILOVER: Invalid failover server specified for server \002%s\002, will not follow!", x->Name.c_str());
+               }
+       }
+}
+
+Link* SpanningTreeUtilities::FindLink(const std::string& name)
+{
+       for (std::vector<Link>::iterator x = LinkBlocks.begin(); x < LinkBlocks.end(); x++)
+       {
+               if (ServerInstance->MatchText(x->Name.c_str(), name.c_str()))
+               {
+                       return &(*x);
+               }
+       }
+       return NULL;
+}
+
index 48146e89e4977a95e8a37b6c8ea8192ff87d414f..cb783a81a16bcf2393d1bcc4f9e28b67a48ba91f 100644 (file)
@@ -1 +1,194 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __ST__UTIL__\r#define __ST__UTIL__\r\r#include "configreader.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r#include "inspircd.h"\r\r/* Foward declarations */\rclass TreeServer;\rclass TreeSocket;\rclass Link;\rclass ModuleSpanningTree;\r\r/* This hash_map holds the hash equivalent of the server\r * tree, used for rapid linear lookups.\r */\r#ifdef WINDOWS\rtypedef nspace::hash_map<std::string, TreeServer*, nspace::hash_compare<string, less<string> > > server_hash;\r#else\rtypedef nspace::hash_map<std::string, TreeServer*, nspace::hash<string>, irc::StrHashComp> server_hash;\r#endif\r\rtypedef std::map<TreeServer*,TreeServer*> TreeServerList;\r\r/** A group of modules that implement InspSocketHook\r * that we can use to hook our server to server connections.\r */\rtypedef std::map<irc::string, Module*> hookmodules;\r\r/** Contains helper functions and variables for this module,\r * and keeps them out of the global namespace\r */\rclass SpanningTreeUtilities\r{\r private:\r       /** Creator server\r      */\r    InspIRCd* ServerInstance;\r public:\r     /** Creator module\r      */\r    ModuleSpanningTree* Creator;\r   /** Remote servers that are currently bursting\r  */\r    server_hash RemoteServersBursting;\r     /** Flatten links and /MAP for non-opers\r        */\r    bool FlatLinks;\r        /** Hide U-Lined servers in /MAP and /LINKS\r     */\r    bool HideULines;\r       /** Announce TS changes to channels on merge\r    */\r    bool AnnounceTSChange;\r /** Synchronize timestamps between servers\r      */\r    bool EnableTimeSync;\r   /** Make snomasks +CQ quiet during bursts and splits\r    */\r    bool quiet_bursts;\r     /** Socket bindings for listening sockets\r       */\r    std::vector<TreeSocket*> Bindings;\r     /* Number of seconds that a server can go without ping\r  * before opers are warned of high latency.\r     */\r    int PingWarnTime;\r      /** This variable represents the root of the server tree\r        */\r    TreeServer *TreeRoot;\r  /** IPs allowed to link to us\r   */\r    std::vector<std::string> ValidIPs;\r     /** Hash of currently connected servers by name\r         */\r    server_hash serverlist;\r        /** Hash of servers currently bursting but not initialized as connected\r         */\r    std::map<irc::string,TreeSocket*> burstingserverlist;\r  /** Holds the data from the <link> tags in the conf\r     */\r    std::vector<Link> LinkBlocks;\r  /** Holds a bitmask of queued xline types waiting to be applied.\r        * Will be a mask containing values APPLY_GLINES, APPLY_KLINES,\r         * APPLY_QLINES and APPLY_ZLINES.\r       */\r    int lines_to_apply;\r\r   /** If this is true, this server is the master sync server for time\r     * synching - e.g. it is the server with its clock correct. It will\r     * send out the correct time at intervals.\r      */\r    bool MasterTime;\r\r      /** List of module pointers which can provide I/O abstraction\r   */\r    hookmodules hooks;\r\r    /** List of module names which can provide I/O abstraction\r      */\r    std::vector<std::string> hooknames;\r\r   /** True (default) if we are to use challenge-response HMAC\r     * to authenticate passwords.\r   *\r      * NOTE: This defaults to on, but should be turned off if\r       * you are linking to an older version of inspircd.\r     */\r    bool ChallengeResponse;\r\r       /** Initialise utility class\r    */\r    SpanningTreeUtilities(InspIRCd* Instance, ModuleSpanningTree* Creator);\r        /** Destroy class and free listeners etc\r        */\r    ~SpanningTreeUtilities();\r      /** Send a message from this server to one other local or remote\r        */\r    bool DoOneToOne(const std::string &prefix, const std::string &command, std::deque<std::string> &params, std::string target);\r   /** Send a message from this server to all but one other, local or remote\r       */\r    bool DoOneToAllButSender(const std::string &prefix, const std::string &command, std::deque<std::string> &params, std::string omit);\r    /** Send a message from this server to all but one other, local or remote\r       */\r    bool DoOneToAllButSender(const char* prefix, const char* command, std::deque<std::string> &params, std::string omit);\r  /** Send a message from this server to all others\r       */\r    bool DoOneToMany(const std::string &prefix, const std::string &command, std::deque<std::string> &params);\r      /** Send a message from this server to all others\r       */\r    bool DoOneToMany(const char* prefix, const char* command, std::deque<std::string> &params);\r    /** Send a message from this server to all others, without doing any processing on the command (e.g. send it as-is with colons and all)\r         */\r    bool DoOneToAllButSenderRaw(const std::string &data, const std::string &omit, const std::string &prefix, const irc::string &command, std::deque<std::string> &params);\r /** Read the spanningtree module's tags from the config file\r    */\r    void ReadConfiguration(bool rebind);\r   /** Add a server to the server list for GetListOfServersForChannel\r      */\r    void AddThisServer(TreeServer* server, TreeServerList &list);\r  /** Compile a list of servers which contain members of channel c\r        */\r    void GetListOfServersForChannel(chanrec* c, TreeServerList &list, char status, const CUList &exempt_list);\r     /** Find a server by name\r       */\r    TreeServer* FindServer(const std::string &ServerName);\r /** Find a remote bursting server by name\r       */\r    TreeServer* FindRemoteBurstServer(TreeServer* Server);\r /** Set a remote server to bursting or not bursting\r     */\r    void SetRemoteBursting(TreeServer* Server, bool bursting);\r     /** Find a route to a server by name\r    */\r    TreeServer* BestRouteTo(const std::string &ServerName);\r        /** Find a server by glob mask\r  */\r    TreeServer* FindServerMask(const std::string &ServerName);\r     /** Returns true if this is a server name we recognise\r  */\r    bool IsServer(const std::string &ServerName);\r  /** Attempt to connect to the failover link of link x\r   */\r    void DoFailOver(Link* x);\r      /** Find a link tag from a server name\r  */\r    Link* FindLink(const std::string& name);\r       /** Refresh the IP cache used for allowing inbound connections\r  */\r    void RefreshIPCache();\r\r        TreeSocket* FindBurstingServer(const std::string &ServerName);\r\r        void AddBurstingServer(const std::string &ServerName, TreeSocket* s);\r\r void DelBurstingServer(TreeSocket* s);\r};\r\r#endif\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __ST__UTIL__
+#define __ST__UTIL__
+
+#include "configreader.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+#include "inspircd.h"
+
+/* Foward declarations */
+class TreeServer;
+class TreeSocket;
+class Link;
+class ModuleSpanningTree;
+
+/* This hash_map holds the hash equivalent of the server
+ * tree, used for rapid linear lookups.
+ */
+#ifdef WINDOWS
+typedef nspace::hash_map<std::string, TreeServer*, nspace::hash_compare<string, less<string> > > server_hash;
+#else
+typedef nspace::hash_map<std::string, TreeServer*, nspace::hash<string>, irc::StrHashComp> server_hash;
+#endif
+
+typedef std::map<TreeServer*,TreeServer*> TreeServerList;
+
+/** A group of modules that implement InspSocketHook
+ * that we can use to hook our server to server connections.
+ */
+typedef std::map<irc::string, Module*> hookmodules;
+
+/** Contains helper functions and variables for this module,
+ * and keeps them out of the global namespace
+ */
+class SpanningTreeUtilities
+{
+ private:
+       /** Creator server
+        */
+       InspIRCd* ServerInstance;
+ public:
+       /** Creator module
+        */
+       ModuleSpanningTree* Creator;
+       /** Remote servers that are currently bursting
+        */
+       server_hash RemoteServersBursting;
+       /** Flatten links and /MAP for non-opers
+        */
+       bool FlatLinks;
+       /** Hide U-Lined servers in /MAP and /LINKS
+        */
+       bool HideULines;
+       /** Announce TS changes to channels on merge
+        */
+       bool AnnounceTSChange;
+       /** Synchronize timestamps between servers
+        */
+       bool EnableTimeSync;
+       /** Make snomasks +CQ quiet during bursts and splits
+        */
+       bool quiet_bursts;
+       /** Socket bindings for listening sockets
+        */
+       std::vector<TreeSocket*> Bindings;
+       /* Number of seconds that a server can go without ping
+        * before opers are warned of high latency.
+        */
+       int PingWarnTime;
+       /** This variable represents the root of the server tree
+        */
+       TreeServer *TreeRoot;
+       /** IPs allowed to link to us
+        */
+       std::vector<std::string> ValidIPs;
+       /** Hash of currently connected servers by name
+        */
+       server_hash serverlist;
+       /** Hash of servers currently bursting but not initialized as connected
+        */
+       std::map<irc::string,TreeSocket*> burstingserverlist;
+       /** Holds the data from the <link> tags in the conf
+        */
+       std::vector<Link> LinkBlocks;
+       /** Holds a bitmask of queued xline types waiting to be applied.
+        * Will be a mask containing values APPLY_GLINES, APPLY_KLINES,
+        * APPLY_QLINES and APPLY_ZLINES.
+        */
+       int lines_to_apply;
+
+       /** If this is true, this server is the master sync server for time
+        * synching - e.g. it is the server with its clock correct. It will
+        * send out the correct time at intervals.
+        */
+       bool MasterTime;
+
+       /** List of module pointers which can provide I/O abstraction
+        */
+       hookmodules hooks;
+
+       /** List of module names which can provide I/O abstraction
+        */
+       std::vector<std::string> hooknames;
+
+       /** True (default) if we are to use challenge-response HMAC
+        * to authenticate passwords.
+        *
+        * NOTE: This defaults to on, but should be turned off if
+        * you are linking to an older version of inspircd.
+        */
+       bool ChallengeResponse;
+
+       /** Initialise utility class
+        */
+       SpanningTreeUtilities(InspIRCd* Instance, ModuleSpanningTree* Creator);
+       /** Destroy class and free listeners etc
+        */
+       ~SpanningTreeUtilities();
+       /** Send a message from this server to one other local or remote
+        */
+       bool DoOneToOne(const std::string &prefix, const std::string &command, std::deque<std::string> &params, std::string target);
+       /** Send a message from this server to all but one other, local or remote
+        */
+       bool DoOneToAllButSender(const std::string &prefix, const std::string &command, std::deque<std::string> &params, std::string omit);
+       /** Send a message from this server to all but one other, local or remote
+        */
+       bool DoOneToAllButSender(const char* prefix, const char* command, std::deque<std::string> &params, std::string omit);
+       /** Send a message from this server to all others
+        */
+       bool DoOneToMany(const std::string &prefix, const std::string &command, std::deque<std::string> &params);
+       /** Send a message from this server to all others
+        */
+       bool DoOneToMany(const char* prefix, const char* command, std::deque<std::string> &params);
+       /** Send a message from this server to all others, without doing any processing on the command (e.g. send it as-is with colons and all)
+        */
+       bool DoOneToAllButSenderRaw(const std::string &data, const std::string &omit, const std::string &prefix, const irc::string &command, std::deque<std::string> &params);
+       /** Read the spanningtree module's tags from the config file
+        */
+       void ReadConfiguration(bool rebind);
+       /** Add a server to the server list for GetListOfServersForChannel
+        */
+       void AddThisServer(TreeServer* server, TreeServerList &list);
+       /** Compile a list of servers which contain members of channel c
+        */
+       void GetListOfServersForChannel(chanrec* c, TreeServerList &list, char status, const CUList &exempt_list);
+       /** Find a server by name
+        */
+       TreeServer* FindServer(const std::string &ServerName);
+       /** Find a remote bursting server by name
+        */
+       TreeServer* FindRemoteBurstServer(TreeServer* Server);
+       /** Set a remote server to bursting or not bursting
+        */
+       void SetRemoteBursting(TreeServer* Server, bool bursting);
+       /** Find a route to a server by name
+        */
+       TreeServer* BestRouteTo(const std::string &ServerName);
+       /** Find a server by glob mask
+        */
+       TreeServer* FindServerMask(const std::string &ServerName);
+       /** Returns true if this is a server name we recognise
+        */
+       bool IsServer(const std::string &ServerName);
+       /** Attempt to connect to the failover link of link x
+        */
+       void DoFailOver(Link* x);
+       /** Find a link tag from a server name
+        */
+       Link* FindLink(const std::string& name);
+       /** Refresh the IP cache used for allowing inbound connections
+        */
+       void RefreshIPCache();
+
+       TreeSocket* FindBurstingServer(const std::string &ServerName);
+
+       void AddBurstingServer(const std::string &ServerName, TreeSocket* s);
+
+       void DelBurstingServer(TreeSocket* s);
+};
+
+#endif
index 11257c437e1357c767bbbe7f8a56853cde415230..20b59977c340f2a62b2c9746d769ac3379511340 100644 (file)
@@ -1 +1,163 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r/* NO, THIS MODULE DOES NOT SPY ON CHANNELS OR USERS.\r * IT JUST ALLOWS OPERS TO SEE +s CHANNELS IN LIST AND\r * WHOIS, WHICH IS SUPPORTED BY MOST IRCDS IN CORE.\r */\r\r/* $ModDesc: Provides SPYLIST and SPYNAMES capability, allowing opers to see who's in +s channels */\r\r#include "inspircd.h"\r#include "users.h" \r#include "channels.h"\r#include "modules.h"\r#include "wildcard.h"\r\rvoid spy_userlist(userrec *user, chanrec *c)\r{\r    char list[MAXBUF];\r     size_t dlen, curlen;\r\r  dlen = curlen = snprintf(list,MAXBUF,"353 %s = %s :", user->nick, c->name);\r\r   int numusers = 0;\r      char* ptr = list + dlen;\r\r      CUList *ulist= c->GetUsers();\r\r for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)\r      {\r              size_t ptrlen = snprintf(ptr, MAXBUF, "%s%s ", c->GetPrefixChar(i->first), i->first->nick);\r\r           curlen += ptrlen;\r              ptr += ptrlen;\r\r                numusers++;\r\r           if (curlen > (480-NICKMAX))\r            {\r                      /* list overflowed into multiple numerics */\r                   user->WriteServ(std::string(list));\r\r                   /* reset our lengths */\r                        dlen = curlen = snprintf(list,MAXBUF,"353 %s = %s :", user->nick, c->name);\r                    ptr = list + dlen;\r\r                    ptrlen = 0;\r                    numusers = 0;\r          }\r      }\r\r     /* if whats left in the list isnt empty, send it */\r    if (numusers)\r  {\r              user->WriteServ(std::string(list));\r    }\r\r     user->WriteServ("366 %s %s :End of /NAMES list.", user->nick, c->name);\r\r}\r\r/** Handle /SPYLIST\r */\rclass cmd_spylist : public command_t\r{\r  public:\r   cmd_spylist (InspIRCd* Instance) : command_t(Instance,"SPYLIST", 'o', 0)\r       {\r              this->source = "m_spy.so";\r             syntax.clear();\r        }\r\r     CmdResult Handle (const char** parameters, int pcnt, userrec *user)\r    {\r              ServerInstance->WriteOpers("*** Oper %s used SPYLIST to list +s/+p channels and keys.",user->nick);\r            user->WriteServ("321 %s Channel :Users Name",user->nick);\r              for (chan_hash::const_iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++)\r               {\r                      if (pcnt && !match(i->second->name, parameters[0]))\r                            continue;\r                      user->WriteServ("322 %s %s %d :[+%s] %s",user->nick,i->second->name,i->second->GetUserCounter(),i->second->ChanModes(true),i->second->topic);\r          }\r              user->WriteServ("323 %s :End of channel list.",user->nick);\r\r           /* Dont send out across the network */\r         return CMD_FAILURE;\r    }\r};\r\r/** Handle /SPYNAMES\r */\rclass cmd_spynames : public command_t\r{\r  public:\r       cmd_spynames (InspIRCd* Instance) : command_t(Instance,"SPYNAMES", 'o', 0)\r     {\r              this->source = "m_spy.so";\r             syntax = "{<channel>{,<channel>}}";\r    }\r\r     CmdResult Handle (const char** parameters, int pcnt, userrec *user)\r    {\r              chanrec* c = NULL;\r\r            if (!pcnt)\r             {\r                      user->WriteServ("366 %s * :End of /NAMES list.",user->nick);\r                   return CMD_FAILURE;\r            }\r\r             if (ServerInstance->Parser->LoopCall(user, this, parameters, pcnt, 0))\r                 return CMD_FAILURE;\r\r           c = ServerInstance->FindChan(parameters[0]);\r           if (c)\r         {\r                      ServerInstance->WriteOpers("*** Oper %s used SPYNAMES to view the users on %s", user->nick, parameters[0]);\r                    spy_userlist(user,c);\r          }\r              else\r           {\r                      user->WriteServ("401 %s %s :No such nick/channel",user->nick, parameters[0]);\r          }\r\r             return CMD_FAILURE;\r    }\r};\r\rclass ModuleSpy : public Module\r{\r        cmd_spylist *mycommand;\r        cmd_spynames *mycommand2;\r public:\r     ModuleSpy(InspIRCd* Me) : Module(Me)\r   {\r              \r               mycommand = new cmd_spylist(ServerInstance);\r           mycommand2 = new cmd_spynames(ServerInstance);\r         ServerInstance->AddCommand(mycommand);\r         ServerInstance->AddCommand(mycommand2);\r        }\r      \r       virtual ~ModuleSpy()\r   {\r      }\r      \r       virtual Version GetVersion()\r   {\r              return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION);\r    }\r};\r\rMODULE_INIT(ModuleSpy)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+/* NO, THIS MODULE DOES NOT SPY ON CHANNELS OR USERS.
+ * IT JUST ALLOWS OPERS TO SEE +s CHANNELS IN LIST AND
+ * WHOIS, WHICH IS SUPPORTED BY MOST IRCDS IN CORE.
+ */
+
+/* $ModDesc: Provides SPYLIST and SPYNAMES capability, allowing opers to see who's in +s channels */
+
+#include "inspircd.h"
+#include "users.h" 
+#include "channels.h"
+#include "modules.h"
+#include "wildcard.h"
+
+void spy_userlist(userrec *user, chanrec *c)
+{
+       char list[MAXBUF];
+       size_t dlen, curlen;
+
+       dlen = curlen = snprintf(list,MAXBUF,"353 %s = %s :", user->nick, c->name);
+
+       int numusers = 0;
+       char* ptr = list + dlen;
+
+       CUList *ulist= c->GetUsers();
+
+       for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
+       {
+               size_t ptrlen = snprintf(ptr, MAXBUF, "%s%s ", c->GetPrefixChar(i->first), i->first->nick);
+
+               curlen += ptrlen;
+               ptr += ptrlen;
+
+               numusers++;
+
+               if (curlen > (480-NICKMAX))
+               {
+                       /* list overflowed into multiple numerics */
+                       user->WriteServ(std::string(list));
+
+                       /* reset our lengths */
+                       dlen = curlen = snprintf(list,MAXBUF,"353 %s = %s :", user->nick, c->name);
+                       ptr = list + dlen;
+
+                       ptrlen = 0;
+                       numusers = 0;
+               }
+       }
+
+       /* if whats left in the list isnt empty, send it */
+       if (numusers)
+       {
+               user->WriteServ(std::string(list));
+       }
+
+       user->WriteServ("366 %s %s :End of /NAMES list.", user->nick, c->name);
+
+}
+
+/** Handle /SPYLIST
+ */
+class cmd_spylist : public command_t
+{
+  public:
+       cmd_spylist (InspIRCd* Instance) : command_t(Instance,"SPYLIST", 'o', 0)
+       {
+               this->source = "m_spy.so";
+               syntax.clear();
+       }
+
+       CmdResult Handle (const char** parameters, int pcnt, userrec *user)
+       {
+               ServerInstance->WriteOpers("*** Oper %s used SPYLIST to list +s/+p channels and keys.",user->nick);
+               user->WriteServ("321 %s Channel :Users Name",user->nick);
+               for (chan_hash::const_iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++)
+               {
+                       if (pcnt && !match(i->second->name, parameters[0]))
+                               continue;
+                       user->WriteServ("322 %s %s %d :[+%s] %s",user->nick,i->second->name,i->second->GetUserCounter(),i->second->ChanModes(true),i->second->topic);
+               }
+               user->WriteServ("323 %s :End of channel list.",user->nick);
+
+               /* Dont send out across the network */
+               return CMD_FAILURE;
+       }
+};
+
+/** Handle /SPYNAMES
+ */
+class cmd_spynames : public command_t
+{
+  public:
+       cmd_spynames (InspIRCd* Instance) : command_t(Instance,"SPYNAMES", 'o', 0)
+       {
+               this->source = "m_spy.so";
+               syntax = "{<channel>{,<channel>}}";
+       }
+
+       CmdResult Handle (const char** parameters, int pcnt, userrec *user)
+       {
+               chanrec* c = NULL;
+
+               if (!pcnt)
+               {
+                       user->WriteServ("366 %s * :End of /NAMES list.",user->nick);
+                       return CMD_FAILURE;
+               }
+
+               if (ServerInstance->Parser->LoopCall(user, this, parameters, pcnt, 0))
+                       return CMD_FAILURE;
+
+               c = ServerInstance->FindChan(parameters[0]);
+               if (c)
+               {
+                       ServerInstance->WriteOpers("*** Oper %s used SPYNAMES to view the users on %s", user->nick, parameters[0]);
+                       spy_userlist(user,c);
+               }
+               else
+               {
+                       user->WriteServ("401 %s %s :No such nick/channel",user->nick, parameters[0]);
+               }
+
+               return CMD_FAILURE;
+       }
+};
+
+class ModuleSpy : public Module
+{
+       cmd_spylist *mycommand;
+       cmd_spynames *mycommand2;
+ public:
+       ModuleSpy(InspIRCd* Me) : Module(Me)
+       {
+               
+               mycommand = new cmd_spylist(ServerInstance);
+               mycommand2 = new cmd_spynames(ServerInstance);
+               ServerInstance->AddCommand(mycommand);
+               ServerInstance->AddCommand(mycommand2);
+       }
+       
+       virtual ~ModuleSpy()
+       {
+       }
+       
+       virtual Version GetVersion()
+       {
+               return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION);
+       }
+};
+
+MODULE_INIT(ModuleSpy)
index 3b872b81caebd1e1191e56e862403605f57d1325..fb3032da2ca5e68d00c53c08ec79170f4e08b4bd 100644 (file)
@@ -1 +1,84 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "modules.h"\r\r/* $ModDesc: Makes remote /whoises to SSL servers work on a non-ssl server */\r\rclass ModuleSSLDummy : public Module\r{\r      \r       char* dummy;\r public:\r  \r       ModuleSSLDummy(InspIRCd* Me)    : Module(Me)\r   {\r              \r       }\r      \r       virtual ~ModuleSSLDummy()\r      {\r      }\r              \r       virtual Version GetVersion()\r   {\r              return Version(1, 0, 0, 0, VF_VENDOR, API_VERSION);\r    }\r\r     void Implements(char* List)\r    {\r              List[I_OnSyncUserMetaData] = List[I_OnDecodeMetaData] = List[I_OnWhois] = 1;\r   }\r\r     // :kenny.chatspike.net 320 Om Epy|AFK :is a Secure Connection\r virtual void OnWhois(userrec* source, userrec* dest)\r   {\r              if(dest->GetExt("ssl", dummy))\r         {\r                      ServerInstance->SendWhoisLine(source, dest, 320, "%s %s :is using a secure connection", source->nick, dest->nick);\r             }\r      }\r      \r       virtual void OnSyncUserMetaData(userrec* user, Module* proto, void* opaque, const std::string &extname, bool displayable)\r      {\r              // check if the linking module wants to know about OUR metadata\r                if(extname == "ssl")\r           {\r                      // check if this user has an ssl field to send\r                 if(user->GetExt(extname, dummy))\r                       {\r                              // call this function in the linking module, let it format the data how it\r                             // sees fit, and send it on its way. We dont need or want to know how.\r                         proto->ProtoSendMetaData(opaque, TYPE_USER, user, extname, displayable ? "Enabled" : "ON");\r                    }\r              }\r      }\r      \r       virtual void OnDecodeMetaData(int target_type, void* target, const std::string &extname, const std::string &extdata)\r   {\r              // check if its our metadata key, and its associated with a user\r               if ((target_type == TYPE_USER) && (extname == "ssl"))\r          {\r                      userrec* dest = (userrec*)target;\r                      // if they dont already have an ssl flag, accept the remote server's\r                   if (!dest->GetExt(extname, dummy))\r                     {\r                              dest->Extend(extname, "ON");\r                   }\r              }\r      }\r};\r\rMODULE_INIT(ModuleSSLDummy)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "modules.h"
+
+/* $ModDesc: Makes remote /whoises to SSL servers work on a non-ssl server */
+
+class ModuleSSLDummy : public Module
+{
+       
+       char* dummy;
+ public:
+       
+       ModuleSSLDummy(InspIRCd* Me)    : Module(Me)
+       {
+               
+       }
+       
+       virtual ~ModuleSSLDummy()
+       {
+       }
+               
+       virtual Version GetVersion()
+       {
+               return Version(1, 0, 0, 0, VF_VENDOR, API_VERSION);
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnSyncUserMetaData] = List[I_OnDecodeMetaData] = List[I_OnWhois] = 1;
+       }
+
+       // :kenny.chatspike.net 320 Om Epy|AFK :is a Secure Connection
+       virtual void OnWhois(userrec* source, userrec* dest)
+       {
+               if(dest->GetExt("ssl", dummy))
+               {
+                       ServerInstance->SendWhoisLine(source, dest, 320, "%s %s :is using a secure connection", source->nick, dest->nick);
+               }
+       }
+       
+       virtual void OnSyncUserMetaData(userrec* user, Module* proto, void* opaque, const std::string &extname, bool displayable)
+       {
+               // check if the linking module wants to know about OUR metadata
+               if(extname == "ssl")
+               {
+                       // check if this user has an ssl field to send
+                       if(user->GetExt(extname, dummy))
+                       {
+                               // call this function in the linking module, let it format the data how it
+                               // sees fit, and send it on its way. We dont need or want to know how.
+                               proto->ProtoSendMetaData(opaque, TYPE_USER, user, extname, displayable ? "Enabled" : "ON");
+                       }
+               }
+       }
+       
+       virtual void OnDecodeMetaData(int target_type, void* target, const std::string &extname, const std::string &extdata)
+       {
+               // check if its our metadata key, and its associated with a user
+               if ((target_type == TYPE_USER) && (extname == "ssl"))
+               {
+                       userrec* dest = (userrec*)target;
+                       // if they dont already have an ssl flag, accept the remote server's
+                       if (!dest->GetExt(extname, dummy))
+                       {
+                               dest->Extend(extname, "ON");
+                       }
+               }
+       }
+};
+
+MODULE_INIT(ModuleSSLDummy)
index 0e06aa3148c26455437643a8109678705850ff16..c8eee5a0362fceade3cc1ae5615f1e4f22bb6e14 100644 (file)
@@ -1 +1,145 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r\r/* $ModDesc: Provides support for unreal-style channel mode +z */\r\rstatic char* dummy;\r\r/** Handle channel mode +z\r */\rclass SSLMode : public ModeHandler\r{\r public:\r SSLMode(InspIRCd* Instance) : ModeHandler(Instance, 'z', 0, 0, false, MODETYPE_CHANNEL, false) { }\r\r    ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)\r {\r              if (adding)\r            {\r                      if (!channel->IsModeSet('z'))\r                  {\r                              if (IS_LOCAL(source))\r                          {\r                                      CUList* userlist = channel->GetUsers();\r                                        for(CUList::iterator i = userlist->begin(); i != userlist->end(); i++)\r                                 {\r                                              if(!i->first->GetExt("ssl", dummy))\r                                            {\r                                                      source->WriteServ("490 %s %s :all members of the channel must be connected via SSL", source->nick, channel->name);\r                                                     return MODEACTION_DENY;\r                                                }\r                                      }\r                              }\r                              channel->SetMode('z',true);\r                            return MODEACTION_ALLOW;\r                       }\r                      else\r                   {\r                              return MODEACTION_DENY;\r                        }\r              }\r              else\r           {\r                      if (channel->IsModeSet('z'))\r                   {\r                              channel->SetMode('z',false);\r                           return MODEACTION_ALLOW;\r                       }\r\r                     return MODEACTION_DENY;\r                }\r      }\r};\r\rclass ModuleSSLModes : public Module\r{\r   \r       SSLMode* sslm;\r \r public:\r      ModuleSSLModes(InspIRCd* Me)\r           : Module(Me)\r   {\r              \r\r              sslm = new SSLMode(ServerInstance);\r            if (!ServerInstance->AddMode(sslm, 'z'))\r                       throw ModuleException("Could not add new modes!");\r     }\r\r     void Implements(char* List)\r    {\r              List[I_OnUserPreJoin] = 1;\r     }\r\r     virtual int OnUserPreJoin(userrec* user, chanrec* chan, const char* cname, std::string &privs)\r {\r              if(chan && chan->IsModeSet('z'))\r               {\r                      if(user->GetExt("ssl", dummy))\r                 {\r                              // Let them in\r                         return 0;\r                      }\r                      else\r                   {\r                              // Deny\r                                user->WriteServ( "489 %s %s :Cannot join channel; SSL users only (+z)", user->nick, cname);\r                            return 1;\r                      }\r              }\r              \r               return 0;\r      }\r\r     virtual ~ModuleSSLModes()\r      {\r              ServerInstance->Modes->DelMode(sslm);\r          DELETE(sslm);\r  }\r      \r       virtual Version GetVersion()\r   {\r              return Version(1, 1, 0, 0, VF_COMMON | VF_VENDOR, API_VERSION);\r        }\r};\r\r\rclass ModuleSSLModesFactory : public ModuleFactory\r{\r public:\r   ModuleSSLModesFactory()\r        {\r      }\r      \r       ~ModuleSSLModesFactory()\r       {\r      }\r      \r       virtual Module* CreateModule(InspIRCd* Me)\r     {\r              return new ModuleSSLModes(Me);\r }\r      \r};\r\r\rextern "C" DllExport void * init_module( void )\r{\r        return new ModuleSSLModesFactory;\r}\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+
+/* $ModDesc: Provides support for unreal-style channel mode +z */
+
+static char* dummy;
+
+/** Handle channel mode +z
+ */
+class SSLMode : public ModeHandler
+{
+ public:
+       SSLMode(InspIRCd* Instance) : ModeHandler(Instance, 'z', 0, 0, false, MODETYPE_CHANNEL, false) { }
+
+       ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)
+       {
+               if (adding)
+               {
+                       if (!channel->IsModeSet('z'))
+                       {
+                               if (IS_LOCAL(source))
+                               {
+                                       CUList* userlist = channel->GetUsers();
+                                       for(CUList::iterator i = userlist->begin(); i != userlist->end(); i++)
+                                       {
+                                               if(!i->first->GetExt("ssl", dummy))
+                                               {
+                                                       source->WriteServ("490 %s %s :all members of the channel must be connected via SSL", source->nick, channel->name);
+                                                       return MODEACTION_DENY;
+                                               }
+                                       }
+                               }
+                               channel->SetMode('z',true);
+                               return MODEACTION_ALLOW;
+                       }
+                       else
+                       {
+                               return MODEACTION_DENY;
+                       }
+               }
+               else
+               {
+                       if (channel->IsModeSet('z'))
+                       {
+                               channel->SetMode('z',false);
+                               return MODEACTION_ALLOW;
+                       }
+
+                       return MODEACTION_DENY;
+               }
+       }
+};
+
+class ModuleSSLModes : public Module
+{
+       
+       SSLMode* sslm;
+       
+ public:
+       ModuleSSLModes(InspIRCd* Me)
+               : Module(Me)
+       {
+               
+
+               sslm = new SSLMode(ServerInstance);
+               if (!ServerInstance->AddMode(sslm, 'z'))
+                       throw ModuleException("Could not add new modes!");
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnUserPreJoin] = 1;
+       }
+
+       virtual int OnUserPreJoin(userrec* user, chanrec* chan, const char* cname, std::string &privs)
+       {
+               if(chan && chan->IsModeSet('z'))
+               {
+                       if(user->GetExt("ssl", dummy))
+                       {
+                               // Let them in
+                               return 0;
+                       }
+                       else
+                       {
+                               // Deny
+                               user->WriteServ( "489 %s %s :Cannot join channel; SSL users only (+z)", user->nick, cname);
+                               return 1;
+                       }
+               }
+               
+               return 0;
+       }
+
+       virtual ~ModuleSSLModes()
+       {
+               ServerInstance->Modes->DelMode(sslm);
+               DELETE(sslm);
+       }
+       
+       virtual Version GetVersion()
+       {
+               return Version(1, 1, 0, 0, VF_COMMON | VF_VENDOR, API_VERSION);
+       }
+};
+
+
+class ModuleSSLModesFactory : public ModuleFactory
+{
+ public:
+       ModuleSSLModesFactory()
+       {
+       }
+       
+       ~ModuleSSLModesFactory()
+       {
+       }
+       
+       virtual Module* CreateModule(InspIRCd* Me)
+       {
+               return new ModuleSSLModes(Me);
+       }
+       
+};
+
+
+extern "C" DllExport void * init_module( void )
+{
+       return new ModuleSSLModesFactory;
+}
index 6f1d7b130efad37a129d8432001723127f60484a..aad253bc740bfbc1445ed6e00b3ffa80556ece6d 100644 (file)
@@ -1 +1,185 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *        the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r\r/* $ModDesc: Provides channel +S mode (strip ansi colour) */\r\r/** Handles channel mode +S\r */\rclass ChannelStripColor : public ModeHandler\r{\r public:\r    ChannelStripColor(InspIRCd* Instance) : ModeHandler(Instance, 'S', 0, 0, false, MODETYPE_CHANNEL, false) { }\r\r  ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)\r {\r              if (adding)\r            {\r                      if (!channel->IsModeSet('S'))\r                  {\r                              channel->SetMode('S',true);\r                            return MODEACTION_ALLOW;\r                       }\r              }\r              else\r           {\r                      if (channel->IsModeSet('S'))\r                   {\r                              channel->SetMode('S',false);\r                           return MODEACTION_ALLOW;\r                       }\r              }\r\r             return MODEACTION_DENY;\r        }\r};\r\r/** Handles user mode +S\r */\rclass UserStripColor : public ModeHandler\r{\r public:\r        UserStripColor(InspIRCd* Instance) : ModeHandler(Instance, 'S', 0, 0, false, MODETYPE_USER, false) { }\r\r        ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)\r {\r              /* Only opers can change other users modes */\r          if (source != dest)\r                    return MODEACTION_DENY;\r\r               if (adding)\r            {\r                      if (!dest->IsModeSet('S'))\r                     {\r                              dest->SetMode('S',true);\r                               return MODEACTION_ALLOW;\r                       }\r              }\r              else\r           {\r                      if (dest->IsModeSet('S'))\r                      {\r                              dest->SetMode('S',false);\r                              return MODEACTION_ALLOW;\r                       }\r              }\r\r             return MODEACTION_DENY;\r        }\r};\r\r\rclass ModuleStripColor : public Module\r{\r        bool AllowChanOps;\r     ChannelStripColor *csc;\r        UserStripColor *usc;\r \r public:\r        ModuleStripColor(InspIRCd* Me) : Module(Me)\r    {\r              usc = new UserStripColor(ServerInstance);\r              csc = new ChannelStripColor(ServerInstance);\r\r          if (!ServerInstance->AddMode(usc, 'S') || !ServerInstance->AddMode(csc, 'S'))\r                  throw ModuleException("Could not add new modes!");\r     }\r\r     void Implements(char* List)\r    {\r              List[I_OnUserPreMessage] = List[I_OnUserPreNotice] = 1;\r        }\r\r     virtual ~ModuleStripColor()\r    {\r              ServerInstance->Modes->DelMode(usc);\r           ServerInstance->Modes->DelMode(csc);\r           DELETE(usc);\r           DELETE(csc);\r   }\r      \r       virtual void ReplaceLine(std::string &sentence)\r        {\r              /* refactor this completely due to SQUIT bug since the old code would strip last char and replace with \0 --peavey */\r          int seq = 0;\r           std::string::iterator i,safei;\r                 for (i = sentence.begin(); i != sentence.end(); ++i)\r           {\r                      if ((*i == 3))\r                         seq = 1;\r                       else if (seq && ( (*i >= '0') && (*i <= '9') || (*i == ',') ) )\r                        {\r                              seq++;\r                         if ( (seq <= 4) && (*i == ',') )\r                                       seq = 1;\r                               else if (seq > 3)\r                                      seq = 0;\r                       }\r                      else\r                           seq = 0;\r                       \r                       if (seq || ((*i == 2) || (*i == 15) || (*i == 22) || (*i == 21) || (*i == 31)))\r                        {\r                              safei = i;\r                             --i;\r                           sentence.erase(safei);\r                 }\r              }\r      }\r\r     virtual int OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)\r    {\r              if (!IS_LOCAL(user))\r                   return 0;\r\r             bool active = false;\r           if (target_type == TYPE_USER)\r          {\r                      userrec* t = (userrec*)dest;\r                   active = t->IsModeSet('S');\r            }\r              else if (target_type == TYPE_CHANNEL)\r          {\r                      chanrec* t = (chanrec*)dest;\r\r                  // check if we allow ops to bypass filtering, if we do, check if they're opped accordingly.\r                    // note: short circut logic here, don't wreck it. -- w00t\r                      if (!CHANOPS_EXEMPT(ServerInstance, 'S') || CHANOPS_EXEMPT(ServerInstance, 'S') && t->GetStatus(user) != STATUS_OP)\r                            active = t->IsModeSet('S');\r            }\r\r             if (active)\r            {\r                      this->ReplaceLine(text);\r               }\r\r             return 0;\r      }\r      \r       virtual int OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)\r     {\r              return OnUserPreMessage(user,dest,target_type,text,status,exempt_list);\r        }\r      \r       virtual Version GetVersion()\r   {\r              return Version(1, 1, 0, 0, VF_COMMON | VF_VENDOR, API_VERSION);\r        }\r      \r};\r\rMODULE_INIT(ModuleStripColor)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *         the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+
+/* $ModDesc: Provides channel +S mode (strip ansi colour) */
+
+/** Handles channel mode +S
+ */
+class ChannelStripColor : public ModeHandler
+{
+ public:
+       ChannelStripColor(InspIRCd* Instance) : ModeHandler(Instance, 'S', 0, 0, false, MODETYPE_CHANNEL, false) { }
+
+       ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)
+       {
+               if (adding)
+               {
+                       if (!channel->IsModeSet('S'))
+                       {
+                               channel->SetMode('S',true);
+                               return MODEACTION_ALLOW;
+                       }
+               }
+               else
+               {
+                       if (channel->IsModeSet('S'))
+                       {
+                               channel->SetMode('S',false);
+                               return MODEACTION_ALLOW;
+                       }
+               }
+
+               return MODEACTION_DENY;
+       }
+};
+
+/** Handles user mode +S
+ */
+class UserStripColor : public ModeHandler
+{
+ public:
+       UserStripColor(InspIRCd* Instance) : ModeHandler(Instance, 'S', 0, 0, false, MODETYPE_USER, false) { }
+
+       ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)
+       {
+               /* Only opers can change other users modes */
+               if (source != dest)
+                       return MODEACTION_DENY;
+
+               if (adding)
+               {
+                       if (!dest->IsModeSet('S'))
+                       {
+                               dest->SetMode('S',true);
+                               return MODEACTION_ALLOW;
+                       }
+               }
+               else
+               {
+                       if (dest->IsModeSet('S'))
+                       {
+                               dest->SetMode('S',false);
+                               return MODEACTION_ALLOW;
+                       }
+               }
+
+               return MODEACTION_DENY;
+       }
+};
+
+
+class ModuleStripColor : public Module
+{
+       bool AllowChanOps;
+       ChannelStripColor *csc;
+       UserStripColor *usc;
+ public:
+       ModuleStripColor(InspIRCd* Me) : Module(Me)
+       {
+               usc = new UserStripColor(ServerInstance);
+               csc = new ChannelStripColor(ServerInstance);
+
+               if (!ServerInstance->AddMode(usc, 'S') || !ServerInstance->AddMode(csc, 'S'))
+                       throw ModuleException("Could not add new modes!");
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnUserPreMessage] = List[I_OnUserPreNotice] = 1;
+       }
+
+       virtual ~ModuleStripColor()
+       {
+               ServerInstance->Modes->DelMode(usc);
+               ServerInstance->Modes->DelMode(csc);
+               DELETE(usc);
+               DELETE(csc);
+       }
+       
+       virtual void ReplaceLine(std::string &sentence)
+       {
+               /* refactor this completely due to SQUIT bug since the old code would strip last char and replace with \0 --peavey */
+               int seq = 0;
+               std::string::iterator i,safei;
+               for (i = sentence.begin(); i != sentence.end(); ++i)
+               {
+                       if ((*i == 3))
+                               seq = 1;
+                       else if (seq && ( (*i >= '0') && (*i <= '9') || (*i == ',') ) )
+                       {
+                               seq++;
+                               if ( (seq <= 4) && (*i == ',') )
+                                       seq = 1;
+                               else if (seq > 3)
+                                       seq = 0;
+                       }
+                       else
+                               seq = 0;
+                       
+                       if (seq || ((*i == 2) || (*i == 15) || (*i == 22) || (*i == 21) || (*i == 31)))
+                       {
+                               safei = i;
+                               --i;
+                               sentence.erase(safei);
+                       }
+               }
+       }
+
+       virtual int OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
+       {
+               if (!IS_LOCAL(user))
+                       return 0;
+
+               bool active = false;
+               if (target_type == TYPE_USER)
+               {
+                       userrec* t = (userrec*)dest;
+                       active = t->IsModeSet('S');
+               }
+               else if (target_type == TYPE_CHANNEL)
+               {
+                       chanrec* t = (chanrec*)dest;
+
+                       // check if we allow ops to bypass filtering, if we do, check if they're opped accordingly.
+                       // note: short circut logic here, don't wreck it. -- w00t
+                       if (!CHANOPS_EXEMPT(ServerInstance, 'S') || CHANOPS_EXEMPT(ServerInstance, 'S') && t->GetStatus(user) != STATUS_OP)
+                               active = t->IsModeSet('S');
+               }
+
+               if (active)
+               {
+                       this->ReplaceLine(text);
+               }
+
+               return 0;
+       }
+       
+       virtual int OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
+       {
+               return OnUserPreMessage(user,dest,target_type,text,status,exempt_list);
+       }
+       
+       virtual Version GetVersion()
+       {
+               return Version(1, 1, 0, 0, VF_COMMON | VF_VENDOR, API_VERSION);
+       }
+       
+};
+
+MODULE_INIT(ModuleStripColor)
index f220d1638d86e479be25a359fb21782921a869a9..4058c04d07312c9b752eccca37e2667f62fccc80 100644 (file)
@@ -1 +1,282 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include <algorithm>\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r#include "configreader.h"\r\r/* $ModDesc: Implements SVSHOLD. Like Q:Lines, but can only be added/removed by Services. */\r\r/** Holds a SVSHold item\r */\rclass SVSHold : public classbase\r{\rpublic:\r std::string nickname;\r  std::string set_by;\r    time_t set_on;\r long length;\r   std::string reason;\r\r   SVSHold()\r      {\r      }\r\r     SVSHold(const std::string &nn, const std::string &sb, const time_t so, const long ln, const std::string &rs) : nickname(nn), set_by(sb), set_on(so), length(ln), reason(rs)\r    {\r      }\r};\r\r\rbool SVSHoldComp(const SVSHold* ban1, const SVSHold* ban2);\r\rtypedef std::vector<SVSHold*> SVSHoldlist;\rtypedef std::map<irc::string, SVSHold*> SVSHoldMap;\r\r/* SVSHolds is declared here, as our type is right above. Don't try move it. */\rSVSHoldlist SVSHolds;\rSVSHoldMap HoldMap;\r\r/** Handle /SVSHold\r */\rclass cmd_svshold : public command_t\r{\r public:\r cmd_svshold(InspIRCd* Me) : command_t(Me, "SVSHOLD", 'o', 1)\r   {\r              this->source = "m_svshold.so";\r         this->syntax = "<nickname> [<duration> :<reason>]";\r    }\r\r     CmdResult Handle(const char** parameters, int pcnt, userrec *user)\r     {\r              /* syntax: svshold nickname time :reason goes here */\r          /* 'time' is a human-readable timestring, like 2d3h2s. */\r\r             if (!ServerInstance->ULine(user->server))\r              {\r                      /* don't allow SVSHOLD from non-ulined clients */\r                      return CMD_FAILURE;\r            }\r\r             if (pcnt == 1)\r         {\r                      SVSHoldMap::iterator n = HoldMap.find(parameters[0]);\r                  if (n != HoldMap.end())\r                        {\r                              /* form: svshold nickname removes a hold. */\r                           for (SVSHoldlist::iterator iter = SVSHolds.begin(); iter != SVSHolds.end(); iter++)\r                            {\r                                      if (parameters[0] == assign((*iter)->nickname))\r                                        {\r                                              unsigned long remaining = 0;\r                                           if ((*iter)->length)\r                                           {\r                                                      remaining = ((*iter)->set_on + (*iter)->length) - ServerInstance->Time();\r                                                      user->WriteServ( "386 %s %s :Removed SVSHOLD with %lu seconds left before expiry (%s)", user->nick, (*iter)->nickname.c_str(), remaining, (*iter)->reason.c_str());\r                                            }\r                                              else\r                                           {\r                                                      user->WriteServ( "386 %s %s :Removed permanent SVSHOLD (%s)", user->nick, (*iter)->nickname.c_str(), (*iter)->reason.c_str());\r                                         }\r                                              SVSHolds.erase(iter);\r                                          break;\r                                 }\r                              }\r\r                             HoldMap.erase(n);\r                              delete n->second;\r                      }\r              }\r              else if (pcnt >= 2)\r            {\r                      /* full form to add a SVSHold */\r                       if (ServerInstance->IsNick(parameters[0]))\r                     {\r                              // parameters[0] = w00t\r                                // parameters[1] = 1h3m2s\r                              // parameters[2] = Registered nickname\r                         \r                               /* Already exists? */\r                          if (HoldMap.find(parameters[0]) != HoldMap.end())\r                              {\r                                      user->WriteServ( "385 %s %s :SVSHOLD already exists", user->nick, parameters[0]);\r                                      return CMD_FAILURE;\r                            }\r\r                             long length = ServerInstance->Duration(parameters[1]);\r                         std::string reason = (pcnt > 2) ? parameters[2] : "No reason supplied";\r                                \r                               SVSHold* S = new SVSHold(parameters[0], user->nick, ServerInstance->Time(), length, reason);\r                           SVSHolds.push_back(S);\r                         HoldMap[parameters[0]] = S;\r\r                           std::sort(SVSHolds.begin(), SVSHolds.end(), SVSHoldComp);\r\r                             if(length > 0)\r                         {\r                                      user->WriteServ( "385 %s %s :Added %lu second SVSHOLD (%s)", user->nick, parameters[0], length, reason.c_str());\r                                       ServerInstance->WriteOpers("*** %s added %lu second SVSHOLD on %s (%s)", user->nick, length, parameters[0], reason.c_str());\r                           }\r                              else\r                           {\r                                      user->WriteServ( "385 %s %s :Added permanent SVSHOLD on %s (%s)", user->nick, parameters[0], parameters[0], reason.c_str());\r                                   ServerInstance->WriteOpers("*** %s added permanent SVSHOLD on %s (%s)", user->nick, parameters[0], reason.c_str());\r                            }\r                      }\r                      else\r                   {\r                              /* as this is primarily a Services command, do not provide an error */\r                         return CMD_FAILURE;\r                    }\r              }\r\r             return CMD_SUCCESS;\r    }\r};\r\rbool SVSHoldComp(const SVSHold* ban1, const SVSHold* ban2)\r{\r     return ((ban1->set_on + ban1->length) < (ban2->set_on + ban2->length));\r}\r\rclass ModuleSVSHold : public Module\r{\r       cmd_svshold *mycommand;\r        \r\r public:\r     ModuleSVSHold(InspIRCd* Me) : Module(Me)\r       {\r              mycommand = new cmd_svshold(Me);\r               ServerInstance->AddCommand(mycommand);\r }\r\r     void Implements(char* List)\r    {\r              List[I_OnUserPreNick] = List[I_OnSyncOtherMetaData] = List[I_OnDecodeMetaData] = List[I_OnStats] = 1;\r  }\r      \r       virtual int OnStats(char symbol, userrec* user, string_list &results)\r  {\r              ExpireBans();\r  \r               if(symbol == 'S')\r              {\r                      for(SVSHoldlist::iterator iter = SVSHolds.begin(); iter != SVSHolds.end(); iter++)\r                     {\r                              unsigned long remaining = ((*iter)->set_on + (*iter)->length) - ServerInstance->Time();\r                                results.push_back(std::string(ServerInstance->Config->ServerName)+" 210 "+user->nick+" "+(*iter)->nickname.c_str()+" "+(*iter)->set_by+" "+ConvToStr((*iter)->set_on)+" "+ConvToStr((*iter)->length)+" "+ConvToStr(remaining)+" :"+(*iter)->reason);\r                   }\r              }\r              \r               return 0;\r      }\r\r     virtual int OnUserPreNick(userrec *user, const std::string &newnick)\r   {\r              ExpireBans();\r  \r               /* check SVSHolds in here, and apply as necessary. */\r          SVSHoldMap::iterator n = HoldMap.find(assign(newnick));\r                if (n != HoldMap.end())\r                {\r                      user->WriteServ( "432 %s %s :Reserved nickname: %s", user->nick, newnick.c_str(), n->second->reason.c_str());\r                  return 1;\r              }\r              return 0;\r      }\r      \r       virtual void OnSyncOtherMetaData(Module* proto, void* opaque, bool displayable)\r        {\r              for(SVSHoldMap::iterator iter = HoldMap.begin(); iter != HoldMap.end(); iter++)\r                {\r                      proto->ProtoSendMetaData(opaque, TYPE_OTHER, NULL, "SVSHold", EncodeSVSHold(iter->second));\r            }\r      }\r\r     virtual void OnDecodeMetaData(int target_type, void* target, const std::string &extname, const std::string &extdata)\r   {\r              if((target_type == TYPE_OTHER) && (extname == "SVSHold"))\r              {\r                      SVSHold* S = DecodeSVSHold(extdata); /* NOTE: Allocates a new SVSHold* */\r                      if (HoldMap.find(assign(S->nickname)) == HoldMap.end())\r                        {\r                              SVSHolds.push_back(S);\r                         HoldMap[assign(S->nickname)] = S;\r                              std::sort(SVSHolds.begin(), SVSHolds.end(), SVSHoldComp);\r                      }\r                      else\r                   {\r                              delete S;\r                      }\r              }\r      }\r\r     virtual ~ModuleSVSHold()\r       {\r      }\r      \r       virtual Version GetVersion()\r   {\r              return Version(1,1,0,1,VF_VENDOR|VF_COMMON,API_VERSION);\r       }\r\r     std::string EncodeSVSHold(const SVSHold* ban)\r  {\r              std::ostringstream stream;      \r               stream << ban->nickname << " " << ban->set_by << " " << ban->set_on << " " << ban->length << " :" << ban->reason;\r              return stream.str();    \r       }\r\r     SVSHold* DecodeSVSHold(const std::string &data)\r        {\r              SVSHold* res = new SVSHold();\r          int set_on;\r            irc::tokenstream tokens(data);\r         tokens.GetToken(res->nickname);\r                tokens.GetToken(res->set_by);\r          tokens.GetToken(set_on);\r               res->set_on = set_on;\r          tokens.GetToken(res->length);\r          tokens.GetToken(res->reason);\r          return res;\r    }\r\r     void ExpireBans()\r      {\r              SVSHoldlist::iterator iter,safeiter;\r           for (iter = SVSHolds.begin(); iter != SVSHolds.end(); iter++)\r          {\r                      /* 0 == permanent, don't mess with them! -- w00t */\r                    if ((*iter)->length != 0)\r                      {\r                              if ((*iter)->set_on + (*iter)->length <= ServerInstance->Time())\r                               {\r                                      ServerInstance->Log(DEBUG, "m_svshold.so: hold on %s expired, removing...", (*iter)->nickname.c_str());\r                                        ServerInstance->WriteOpers("*** %li second SVSHOLD on %s (%s) set %u seconds ago expired", (*iter)->length, (*iter)->nickname.c_str(), (*iter)->reason.c_str(), ServerInstance->Time() - (*iter)->set_on);\r                                     HoldMap.erase(assign((*iter)->nickname));\r                                      delete *iter;\r                                  safeiter = iter;\r                                       --iter;\r                                        SVSHolds.erase(safeiter);\r                              }\r                      }\r              }\r      }\r};\r\rMODULE_INIT(ModuleSVSHold)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include <algorithm>
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+#include "configreader.h"
+
+/* $ModDesc: Implements SVSHOLD. Like Q:Lines, but can only be added/removed by Services. */
+
+/** Holds a SVSHold item
+ */
+class SVSHold : public classbase
+{
+public:
+       std::string nickname;
+       std::string set_by;
+       time_t set_on;
+       long length;
+       std::string reason;
+
+       SVSHold()
+       {
+       }
+
+       SVSHold(const std::string &nn, const std::string &sb, const time_t so, const long ln, const std::string &rs) : nickname(nn), set_by(sb), set_on(so), length(ln), reason(rs)
+       {
+       }
+};
+
+
+bool SVSHoldComp(const SVSHold* ban1, const SVSHold* ban2);
+
+typedef std::vector<SVSHold*> SVSHoldlist;
+typedef std::map<irc::string, SVSHold*> SVSHoldMap;
+
+/* SVSHolds is declared here, as our type is right above. Don't try move it. */
+SVSHoldlist SVSHolds;
+SVSHoldMap HoldMap;
+
+/** Handle /SVSHold
+ */
+class cmd_svshold : public command_t
+{
+ public:
+       cmd_svshold(InspIRCd* Me) : command_t(Me, "SVSHOLD", 'o', 1)
+       {
+               this->source = "m_svshold.so";
+               this->syntax = "<nickname> [<duration> :<reason>]";
+       }
+
+       CmdResult Handle(const char** parameters, int pcnt, userrec *user)
+       {
+               /* syntax: svshold nickname time :reason goes here */
+               /* 'time' is a human-readable timestring, like 2d3h2s. */
+
+               if (!ServerInstance->ULine(user->server))
+               {
+                       /* don't allow SVSHOLD from non-ulined clients */
+                       return CMD_FAILURE;
+               }
+
+               if (pcnt == 1)
+               {
+                       SVSHoldMap::iterator n = HoldMap.find(parameters[0]);
+                       if (n != HoldMap.end())
+                       {
+                               /* form: svshold nickname removes a hold. */
+                               for (SVSHoldlist::iterator iter = SVSHolds.begin(); iter != SVSHolds.end(); iter++)
+                               {
+                                       if (parameters[0] == assign((*iter)->nickname))
+                                       {
+                                               unsigned long remaining = 0;
+                                               if ((*iter)->length)
+                                               {
+                                                       remaining = ((*iter)->set_on + (*iter)->length) - ServerInstance->Time();
+                                                       user->WriteServ( "386 %s %s :Removed SVSHOLD with %lu seconds left before expiry (%s)", user->nick, (*iter)->nickname.c_str(), remaining, (*iter)->reason.c_str());
+                                               }
+                                               else
+                                               {
+                                                       user->WriteServ( "386 %s %s :Removed permanent SVSHOLD (%s)", user->nick, (*iter)->nickname.c_str(), (*iter)->reason.c_str());
+                                               }
+                                               SVSHolds.erase(iter);
+                                               break;
+                                       }
+                               }
+
+                               HoldMap.erase(n);
+                               delete n->second;
+                       }
+               }
+               else if (pcnt >= 2)
+               {
+                       /* full form to add a SVSHold */
+                       if (ServerInstance->IsNick(parameters[0]))
+                       {
+                               // parameters[0] = w00t
+                               // parameters[1] = 1h3m2s
+                               // parameters[2] = Registered nickname
+                               
+                               /* Already exists? */
+                               if (HoldMap.find(parameters[0]) != HoldMap.end())
+                               {
+                                       user->WriteServ( "385 %s %s :SVSHOLD already exists", user->nick, parameters[0]);
+                                       return CMD_FAILURE;
+                               }
+
+                               long length = ServerInstance->Duration(parameters[1]);
+                               std::string reason = (pcnt > 2) ? parameters[2] : "No reason supplied";
+                               
+                               SVSHold* S = new SVSHold(parameters[0], user->nick, ServerInstance->Time(), length, reason);
+                               SVSHolds.push_back(S);
+                               HoldMap[parameters[0]] = S;
+
+                               std::sort(SVSHolds.begin(), SVSHolds.end(), SVSHoldComp);
+
+                               if(length > 0)
+                               {
+                                       user->WriteServ( "385 %s %s :Added %lu second SVSHOLD (%s)", user->nick, parameters[0], length, reason.c_str());
+                                       ServerInstance->WriteOpers("*** %s added %lu second SVSHOLD on %s (%s)", user->nick, length, parameters[0], reason.c_str());
+                               }
+                               else
+                               {
+                                       user->WriteServ( "385 %s %s :Added permanent SVSHOLD on %s (%s)", user->nick, parameters[0], parameters[0], reason.c_str());
+                                       ServerInstance->WriteOpers("*** %s added permanent SVSHOLD on %s (%s)", user->nick, parameters[0], reason.c_str());
+                               }
+                       }
+                       else
+                       {
+                               /* as this is primarily a Services command, do not provide an error */
+                               return CMD_FAILURE;
+                       }
+               }
+
+               return CMD_SUCCESS;
+       }
+};
+
+bool SVSHoldComp(const SVSHold* ban1, const SVSHold* ban2)
+{
+       return ((ban1->set_on + ban1->length) < (ban2->set_on + ban2->length));
+}
+
+class ModuleSVSHold : public Module
+{
+       cmd_svshold *mycommand;
+       
+
+ public:
+       ModuleSVSHold(InspIRCd* Me) : Module(Me)
+       {
+               mycommand = new cmd_svshold(Me);
+               ServerInstance->AddCommand(mycommand);
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnUserPreNick] = List[I_OnSyncOtherMetaData] = List[I_OnDecodeMetaData] = List[I_OnStats] = 1;
+       }
+       
+       virtual int OnStats(char symbol, userrec* user, string_list &results)
+       {
+               ExpireBans();
+       
+               if(symbol == 'S')
+               {
+                       for(SVSHoldlist::iterator iter = SVSHolds.begin(); iter != SVSHolds.end(); iter++)
+                       {
+                               unsigned long remaining = ((*iter)->set_on + (*iter)->length) - ServerInstance->Time();
+                               results.push_back(std::string(ServerInstance->Config->ServerName)+" 210 "+user->nick+" "+(*iter)->nickname.c_str()+" "+(*iter)->set_by+" "+ConvToStr((*iter)->set_on)+" "+ConvToStr((*iter)->length)+" "+ConvToStr(remaining)+" :"+(*iter)->reason);
+                       }
+               }
+               
+               return 0;
+       }
+
+       virtual int OnUserPreNick(userrec *user, const std::string &newnick)
+       {
+               ExpireBans();
+       
+               /* check SVSHolds in here, and apply as necessary. */
+               SVSHoldMap::iterator n = HoldMap.find(assign(newnick));
+               if (n != HoldMap.end())
+               {
+                       user->WriteServ( "432 %s %s :Reserved nickname: %s", user->nick, newnick.c_str(), n->second->reason.c_str());
+                       return 1;
+               }
+               return 0;
+       }
+       
+       virtual void OnSyncOtherMetaData(Module* proto, void* opaque, bool displayable)
+       {
+               for(SVSHoldMap::iterator iter = HoldMap.begin(); iter != HoldMap.end(); iter++)
+               {
+                       proto->ProtoSendMetaData(opaque, TYPE_OTHER, NULL, "SVSHold", EncodeSVSHold(iter->second));
+               }
+       }
+
+       virtual void OnDecodeMetaData(int target_type, void* target, const std::string &extname, const std::string &extdata)
+       {
+               if((target_type == TYPE_OTHER) && (extname == "SVSHold"))
+               {
+                       SVSHold* S = DecodeSVSHold(extdata); /* NOTE: Allocates a new SVSHold* */
+                       if (HoldMap.find(assign(S->nickname)) == HoldMap.end())
+                       {
+                               SVSHolds.push_back(S);
+                               HoldMap[assign(S->nickname)] = S;
+                               std::sort(SVSHolds.begin(), SVSHolds.end(), SVSHoldComp);
+                       }
+                       else
+                       {
+                               delete S;
+                       }
+               }
+       }
+
+       virtual ~ModuleSVSHold()
+       {
+       }
+       
+       virtual Version GetVersion()
+       {
+               return Version(1,1,0,1,VF_VENDOR|VF_COMMON,API_VERSION);
+       }
+
+       std::string EncodeSVSHold(const SVSHold* ban)
+       {
+               std::ostringstream stream;      
+               stream << ban->nickname << " " << ban->set_by << " " << ban->set_on << " " << ban->length << " :" << ban->reason;
+               return stream.str();    
+       }
+
+       SVSHold* DecodeSVSHold(const std::string &data)
+       {
+               SVSHold* res = new SVSHold();
+               int set_on;
+               irc::tokenstream tokens(data);
+               tokens.GetToken(res->nickname);
+               tokens.GetToken(res->set_by);
+               tokens.GetToken(set_on);
+               res->set_on = set_on;
+               tokens.GetToken(res->length);
+               tokens.GetToken(res->reason);
+               return res;
+       }
+
+       void ExpireBans()
+       {
+               SVSHoldlist::iterator iter,safeiter;
+               for (iter = SVSHolds.begin(); iter != SVSHolds.end(); iter++)
+               {
+                       /* 0 == permanent, don't mess with them! -- w00t */
+                       if ((*iter)->length != 0)
+                       {
+                               if ((*iter)->set_on + (*iter)->length <= ServerInstance->Time())
+                               {
+                                       ServerInstance->Log(DEBUG, "m_svshold.so: hold on %s expired, removing...", (*iter)->nickname.c_str());
+                                       ServerInstance->WriteOpers("*** %li second SVSHOLD on %s (%s) set %u seconds ago expired", (*iter)->length, (*iter)->nickname.c_str(), (*iter)->reason.c_str(), ServerInstance->Time() - (*iter)->set_on);
+                                       HoldMap.erase(assign((*iter)->nickname));
+                                       delete *iter;
+                                       safeiter = iter;
+                                       --iter;
+                                       SVSHolds.erase(safeiter);
+                               }
+                       }
+               }
+       }
+};
+
+MODULE_INIT(ModuleSVSHold)
index 5df5fe4eb56b17aa1aaf87d28ed242ff1d59bc32..d635654a524fd1229b02031dc35f95f05dc3d677 100644 (file)
@@ -1 +1,267 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r\r/* $ModDesc: Provides the SWHOIS command which allows setting of arbitary WHOIS lines */\r\r/** Handle /SWHOIS\r */\rclass cmd_swhois : public command_t\r{\r       \r public:\r      cmd_swhois (InspIRCd* Instance) : command_t(Instance,"SWHOIS",'o',2)\r   {\r              this->source = "m_swhois.so";\r          syntax = "<nick> <swhois>";\r    }\r\r     CmdResult Handle(const char** parameters, int pcnt, userrec* user)\r     {\r              userrec* dest = ServerInstance->FindNick(parameters[0]);\r               \r               if (!dest)\r             {\r                      user->WriteServ("401 %s %s :No such nick/channel", user->nick, parameters[0]);\r                 return CMD_FAILURE;\r            }\r\r             if (!*parameters[1])\r           {\r                      user->WriteServ("NOTICE %s :*** SWHOIS: Whois line must be specified", user->nick);\r                    return CMD_FAILURE;\r            }\r              \r               std::string line;\r              for (int i = 1; i < pcnt; i++)\r         {\r                      if (i != 1)\r                            line.append(" ");\r                              \r                       line.append(parameters[i]);\r            }\r              \r               std::string* text;\r             dest->GetExt("swhois", text);\r\r         if (text)\r              {\r                      // We already had it set...\r                    \r                       if (!ServerInstance->ULine(user->server))\r                              // Ulines set SWHOISes silently\r                                ServerInstance->WriteOpers("*** %s used SWHOIS to set %s's extra whois from '%s' to '%s'", user->nick, dest->nick, text->c_str(), line.c_str());\r                       \r                       dest->Shrink("swhois");\r                        DELETE(text);\r          }\r              else if (!ServerInstance->ULine(user->server))\r         {\r                      // Ulines set SWHOISes silently\r                        ServerInstance->WriteOpers("*** %s used SWHOIS to set %s's extra whois to '%s'", user->nick, dest->nick, line.c_str());\r                }\r              \r               text = new std::string(line);\r          dest->Extend("swhois", text);\r\r         return CMD_SUCCESS;\r    }\r\r};\r\rclass ModuleSWhois : public Module\r{\r    cmd_swhois* mycommand;\r \r       ConfigReader* Conf;\r    \r public:\r      ModuleSWhois(InspIRCd* Me) : Module(Me)\r        {\r              \r               Conf = new ConfigReader(ServerInstance);\r               mycommand = new cmd_swhois(ServerInstance);\r            ServerInstance->AddCommand(mycommand);\r }\r\r     void OnRehash(userrec* user, const std::string &parameter)\r     {\r              DELETE(Conf);\r          Conf = new ConfigReader(ServerInstance);\r       }\r\r     void Implements(char* List)\r    {\r              List[I_OnDecodeMetaData] = List[I_OnWhoisLine] = List[I_OnSyncUserMetaData] = List[I_OnUserQuit] = List[I_OnCleanup] = List[I_OnRehash] = List[I_OnPostCommand] = 1;\r   }\r\r     // :kenny.chatspike.net 320 Brain Azhrarn :is getting paid to play games.\r      int OnWhoisLine(userrec* user, userrec* dest, int &numeric, std::string &text)\r {\r              /* We use this and not OnWhois because this triggers for remote, too */\r                if (numeric == 312)\r            {\r                      /* Insert our numeric before 312 */\r                    std::string* swhois;\r                   dest->GetExt("swhois", swhois);\r                        if (swhois)\r                    {\r                              ServerInstance->SendWhoisLine(user, dest, 320, "%s %s :%s",user->nick,dest->nick,swhois->c_str());\r                     }\r              }\r              /* Dont block anything */\r              return 0;\r      }\r\r     // Whenever the linking module wants to send out data, but doesnt know what the data\r   // represents (e.g. it is metadata, added to a userrec or chanrec by a module) then\r    // this method is called. We should use the ProtoSendMetaData function after we've\r     // corrected decided how the data should look, to send the metadata on its way if\r      // it is ours.\r virtual void OnSyncUserMetaData(userrec* user, Module* proto, void* opaque, const std::string &extname, bool displayable)\r      {\r              // check if the linking module wants to know about OUR metadata\r                if (extname == "swhois")\r               {\r                      // check if this user has an swhois field to send\r                      std::string* swhois;\r                   user->GetExt("swhois", swhois);\r                        if (swhois)\r                    {\r                              // call this function in the linking module, let it format the data how it\r                             // sees fit, and send it on its way. We dont need or want to know how.\r                         proto->ProtoSendMetaData(opaque,TYPE_USER,user,extname,*swhois);\r                       }\r              }\r      }\r\r     // when a user quits, tidy up their metadata\r   virtual void OnUserQuit(userrec* user, const std::string &message, const std::string &oper_message)\r    {\r              std::string* swhois;\r           user->GetExt("swhois", swhois);\r                if (swhois)\r            {\r                      user->Shrink("swhois");\r                        DELETE(swhois);\r                }\r      }\r\r     // if the module is unloaded, tidy up all our dangling metadata\r        virtual void OnCleanup(int target_type, void* item)\r    {\r              if (target_type == TYPE_USER)\r          {\r                      userrec* user = (userrec*)item;\r                        std::string* swhois;\r                   user->GetExt("swhois", swhois);\r                        if (swhois)\r                    {\r                              user->Shrink("swhois");\r                                DELETE(swhois);\r                        }\r              }\r      }\r\r     // Whenever the linking module receives metadata from another server and doesnt know what\r      // to do with it (of course, hence the 'meta') it calls this method, and it is up to each\r      // module in turn to figure out if this metadata key belongs to them, and what they want\r       // to do with it.\r      // In our case we're only sending a single string around, so we just construct a std::string.\r  // Some modules will probably get much more complex and format more detailed structs and classes\r       // in a textual way for sending over the link.\r virtual void OnDecodeMetaData(int target_type, void* target, const std::string &extname, const std::string &extdata)\r   {\r              // check if its our metadata key, and its associated with a user\r               if ((target_type == TYPE_USER) && (extname == "swhois"))\r               {\r                      userrec* dest = (userrec*)target;\r                      // if they dont already have an swhois field, accept the remote server's\r                       std::string* text;\r                     if (!dest->GetExt("swhois", text))\r                     {\r                              std::string* text = new std::string(extdata);\r                          dest->Extend("swhois",text);\r                   }\r              }\r      }\r      \r       virtual void OnPostCommand(const std::string &command, const char **params, int pcnt, userrec *user, CmdResult result, const std::string &original_line)\r       {\r              if ((command != "OPER") || (result != CMD_SUCCESS))\r                    return;\r                \r               std::string swhois;\r            \r               for (int i = 0; i < Conf->Enumerate("oper"); i++)\r              {\r                      std::string name = Conf->ReadValue("oper", "name", i);\r                 \r                       if (name == params[0])\r                 {\r                              swhois = Conf->ReadValue("oper", "swhois", i);\r                         break;\r                 }\r              }\r              \r               if (!swhois.length())\r          {\r                      for (int i = 0; i < Conf->Enumerate("type"); i++)\r                      {\r                              std::string type = Conf->ReadValue("type", "name", i);\r                         \r                               if (type == user->oper)\r                                {\r                                      swhois = Conf->ReadValue("type", "swhois", i);\r                                 break;\r                         }\r                      }\r              }\r\r             std::string *old;\r              if (user->GetExt("swhois", old))\r               {\r                      user->Shrink("swhois");\r                        DELETE(old);\r           }\r              \r               if (!swhois.length())\r                  return;\r                \r               std::string *text = new std::string(swhois);\r           user->Extend("swhois", text);\r          std::deque<std::string>* metadata = new std::deque<std::string>;\r               metadata->push_back(user->nick);\r               metadata->push_back("swhois");          // The metadata id\r             metadata->push_back(*text);             // The value to send\r           Event event((char*)metadata,(Module*)this,"send_metadata");\r            event.Send(ServerInstance);\r            delete metadata;\r       }\r\r     virtual ~ModuleSWhois()\r        {\r              DELETE(Conf);\r  }\r      \r       virtual Version GetVersion()\r   {\r              return Version(1,1,0,0,VF_VENDOR,API_VERSION);\r }\r};\r\rMODULE_INIT(ModuleSWhois)\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+
+/* $ModDesc: Provides the SWHOIS command which allows setting of arbitary WHOIS lines */
+
+/** Handle /SWHOIS
+ */
+class cmd_swhois : public command_t
+{
+       
+ public:
+       cmd_swhois (InspIRCd* Instance) : command_t(Instance,"SWHOIS",'o',2)
+       {
+               this->source = "m_swhois.so";
+               syntax = "<nick> <swhois>";
+       }
+
+       CmdResult Handle(const char** parameters, int pcnt, userrec* user)
+       {
+               userrec* dest = ServerInstance->FindNick(parameters[0]);
+               
+               if (!dest)
+               {
+                       user->WriteServ("401 %s %s :No such nick/channel", user->nick, parameters[0]);
+                       return CMD_FAILURE;
+               }
+
+               if (!*parameters[1])
+               {
+                       user->WriteServ("NOTICE %s :*** SWHOIS: Whois line must be specified", user->nick);
+                       return CMD_FAILURE;
+               }
+               
+               std::string line;
+               for (int i = 1; i < pcnt; i++)
+               {
+                       if (i != 1)
+                               line.append(" ");
+                               
+                       line.append(parameters[i]);
+               }
+               
+               std::string* text;
+               dest->GetExt("swhois", text);
+
+               if (text)
+               {
+                       // We already had it set...
+                       
+                       if (!ServerInstance->ULine(user->server))
+                               // Ulines set SWHOISes silently
+                               ServerInstance->WriteOpers("*** %s used SWHOIS to set %s's extra whois from '%s' to '%s'", user->nick, dest->nick, text->c_str(), line.c_str());
+                       
+                       dest->Shrink("swhois");
+                       DELETE(text);
+               }
+               else if (!ServerInstance->ULine(user->server))
+               {
+                       // Ulines set SWHOISes silently
+                       ServerInstance->WriteOpers("*** %s used SWHOIS to set %s's extra whois to '%s'", user->nick, dest->nick, line.c_str());
+               }
+               
+               text = new std::string(line);
+               dest->Extend("swhois", text);
+
+               return CMD_SUCCESS;
+       }
+
+};
+
+class ModuleSWhois : public Module
+{
+       cmd_swhois* mycommand;
+       
+       ConfigReader* Conf;
+       
+ public:
+       ModuleSWhois(InspIRCd* Me) : Module(Me)
+       {
+               
+               Conf = new ConfigReader(ServerInstance);
+               mycommand = new cmd_swhois(ServerInstance);
+               ServerInstance->AddCommand(mycommand);
+       }
+
+       void OnRehash(userrec* user, const std::string &parameter)
+       {
+               DELETE(Conf);
+               Conf = new ConfigReader(ServerInstance);
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnDecodeMetaData] = List[I_OnWhoisLine] = List[I_OnSyncUserMetaData] = List[I_OnUserQuit] = List[I_OnCleanup] = List[I_OnRehash] = List[I_OnPostCommand] = 1;
+       }
+
+       // :kenny.chatspike.net 320 Brain Azhrarn :is getting paid to play games.
+       int OnWhoisLine(userrec* user, userrec* dest, int &numeric, std::string &text)
+       {
+               /* We use this and not OnWhois because this triggers for remote, too */
+               if (numeric == 312)
+               {
+                       /* Insert our numeric before 312 */
+                       std::string* swhois;
+                       dest->GetExt("swhois", swhois);
+                       if (swhois)
+                       {
+                               ServerInstance->SendWhoisLine(user, dest, 320, "%s %s :%s",user->nick,dest->nick,swhois->c_str());
+                       }
+               }
+               /* Dont block anything */
+               return 0;
+       }
+
+       // Whenever the linking module wants to send out data, but doesnt know what the data
+       // represents (e.g. it is metadata, added to a userrec or chanrec by a module) then
+       // this method is called. We should use the ProtoSendMetaData function after we've
+       // corrected decided how the data should look, to send the metadata on its way if
+       // it is ours.
+       virtual void OnSyncUserMetaData(userrec* user, Module* proto, void* opaque, const std::string &extname, bool displayable)
+       {
+               // check if the linking module wants to know about OUR metadata
+               if (extname == "swhois")
+               {
+                       // check if this user has an swhois field to send
+                       std::string* swhois;
+                       user->GetExt("swhois", swhois);
+                       if (swhois)
+                       {
+                               // call this function in the linking module, let it format the data how it
+                               // sees fit, and send it on its way. We dont need or want to know how.
+                               proto->ProtoSendMetaData(opaque,TYPE_USER,user,extname,*swhois);
+                       }
+               }
+       }
+
+       // when a user quits, tidy up their metadata
+       virtual void OnUserQuit(userrec* user, const std::string &message, const std::string &oper_message)
+       {
+               std::string* swhois;
+               user->GetExt("swhois", swhois);
+               if (swhois)
+               {
+                       user->Shrink("swhois");
+                       DELETE(swhois);
+               }
+       }
+
+       // if the module is unloaded, tidy up all our dangling metadata
+       virtual void OnCleanup(int target_type, void* item)
+       {
+               if (target_type == TYPE_USER)
+               {
+                       userrec* user = (userrec*)item;
+                       std::string* swhois;
+                       user->GetExt("swhois", swhois);
+                       if (swhois)
+                       {
+                               user->Shrink("swhois");
+                               DELETE(swhois);
+                       }
+               }
+       }
+
+       // Whenever the linking module receives metadata from another server and doesnt know what
+       // to do with it (of course, hence the 'meta') it calls this method, and it is up to each
+       // module in turn to figure out if this metadata key belongs to them, and what they want
+       // to do with it.
+       // In our case we're only sending a single string around, so we just construct a std::string.
+       // Some modules will probably get much more complex and format more detailed structs and classes
+       // in a textual way for sending over the link.
+       virtual void OnDecodeMetaData(int target_type, void* target, const std::string &extname, const std::string &extdata)
+       {
+               // check if its our metadata key, and its associated with a user
+               if ((target_type == TYPE_USER) && (extname == "swhois"))
+               {
+                       userrec* dest = (userrec*)target;
+                       // if they dont already have an swhois field, accept the remote server's
+                       std::string* text;
+                       if (!dest->GetExt("swhois", text))
+                       {
+                               std::string* text = new std::string(extdata);
+                               dest->Extend("swhois",text);
+                       }
+               }
+       }
+       
+       virtual void OnPostCommand(const std::string &command, const char **params, int pcnt, userrec *user, CmdResult result, const std::string &original_line)
+       {
+               if ((command != "OPER") || (result != CMD_SUCCESS))
+                       return;
+               
+               std::string swhois;
+               
+               for (int i = 0; i < Conf->Enumerate("oper"); i++)
+               {
+                       std::string name = Conf->ReadValue("oper", "name", i);
+                       
+                       if (name == params[0])
+                       {
+                               swhois = Conf->ReadValue("oper", "swhois", i);
+                               break;
+                       }
+               }
+               
+               if (!swhois.length())
+               {
+                       for (int i = 0; i < Conf->Enumerate("type"); i++)
+                       {
+                               std::string type = Conf->ReadValue("type", "name", i);
+                               
+                               if (type == user->oper)
+                               {
+                                       swhois = Conf->ReadValue("type", "swhois", i);
+                                       break;
+                               }
+                       }
+               }
+
+               std::string *old;
+               if (user->GetExt("swhois", old))
+               {
+                       user->Shrink("swhois");
+                       DELETE(old);
+               }
+               
+               if (!swhois.length())
+                       return;
+               
+               std::string *text = new std::string(swhois);
+               user->Extend("swhois", text);
+               std::deque<std::string>* metadata = new std::deque<std::string>;
+               metadata->push_back(user->nick);
+               metadata->push_back("swhois");          // The metadata id
+               metadata->push_back(*text);             // The value to send
+               Event event((char*)metadata,(Module*)this,"send_metadata");
+               event.Send(ServerInstance);
+               delete metadata;
+       }
+
+       virtual ~ModuleSWhois()
+       {
+               DELETE(Conf);
+       }
+       
+       virtual Version GetVersion()
+       {
+               return Version(1,1,0,0,VF_VENDOR,API_VERSION);
+       }
+};
+
+MODULE_INIT(ModuleSWhois)
index edae9ccf67c60e7c56e3f1704899321b198a8402..79dc8e23feeb616e68a2229e996b82e36b0ce4ce 100644 (file)
@@ -1 +1,99 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r\r/* $ModDesc: Provides the /TAXONOMY command, used to view all metadata attached to a user */\r\r/** Handle /WOOT\r */\rclass cmd_taxonomy : public command_t\r{\r   Module* Creator;\r       bool& claimed;\r public:\r        /* Command 'taxonomy', takes no parameters and needs no special modes */\r       cmd_taxonomy (InspIRCd* Instance, Module* maker, bool &claim) : command_t(Instance,"TAXONOMY", 'o', 1), Creator(maker), claimed(claim)\r {\r              this->source = "m_taxonomy.so";\r        }\r\r     CmdResult Handle (const char** parameters, int pcnt, userrec *user)\r    {\r              userrec* dest = ServerInstance->FindNick(parameters[0]);\r               if (dest)\r              {\r                      std::deque<std::string> list;\r                  list.clear();\r                  user->GetExtList(list);\r                        user->WriteServ("304 " + std::string(user->nick) + ":TAXONOMY ITEMS " + std::string(dest->nick) + " " +ConvToStr(list.size()));\r                        for (unsigned int j = 0; j < list.size(); j++)\r                 {\r                              claimed = false;\r                               FOREACH_MOD(I_OnSyncUserMetaData, OnSyncUserMetaData(user, Creator, dest, list[j], true));\r                             if (!claimed)\r                          {\r                                      user->WriteServ("304 " + std::string(user->nick) + ":TAXONOMY METADATA " + list[j] + " = <unknown>");\r                          }\r                      }\r                      user->WriteServ("304 " + std::string(user->nick) + ":TAXONOMY END");\r           }\r              return CMD_FAILURE;\r    }\r};\r\rclass ModuleTaxonomy : public Module\r{\r   cmd_taxonomy* newcommand;\r      bool claimed;\r public:\r ModuleTaxonomy(InspIRCd* Me)\r           : Module(Me)\r   {\r              \r               // Create a new command\r                newcommand = new cmd_taxonomy(ServerInstance, this, claimed);\r          ServerInstance->AddCommand(newcommand);\r        }\r\r     void Implements(char* List)\r    {\r              List[I_ProtoSendMetaData] = 1;\r }\r\r     void ProtoSendMetaData(void* opaque, int target_type, void* target, const std::string &extname, const std::string &extdata)\r    {\r              if (target_type == TYPE_USER)\r          {\r                      userrec* spool = (userrec*)opaque;\r                     std::string taxstr = "304 " + std::string(spool->nick) + ":TAXONOMY METADATA "+extname+" = "+extdata;\r                  spool->WriteServ(taxstr);\r                      claimed = true;\r                }\r      }\r\r     virtual ~ModuleTaxonomy()\r      {\r      }\r\r     virtual Version GetVersion()\r   {\r              return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION);\r    }\r};\r\rMODULE_INIT(ModuleTaxonomy)\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+
+/* $ModDesc: Provides the /TAXONOMY command, used to view all metadata attached to a user */
+
+/** Handle /WOOT
+ */
+class cmd_taxonomy : public command_t
+{
+       Module* Creator;
+       bool& claimed;
+ public:
+       /* Command 'taxonomy', takes no parameters and needs no special modes */
+       cmd_taxonomy (InspIRCd* Instance, Module* maker, bool &claim) : command_t(Instance,"TAXONOMY", 'o', 1), Creator(maker), claimed(claim)
+       {
+               this->source = "m_taxonomy.so";
+       }
+
+       CmdResult Handle (const char** parameters, int pcnt, userrec *user)
+       {
+               userrec* dest = ServerInstance->FindNick(parameters[0]);
+               if (dest)
+               {
+                       std::deque<std::string> list;
+                       list.clear();
+                       user->GetExtList(list);
+                       user->WriteServ("304 " + std::string(user->nick) + ":TAXONOMY ITEMS " + std::string(dest->nick) + " " +ConvToStr(list.size()));
+                       for (unsigned int j = 0; j < list.size(); j++)
+                       {
+                               claimed = false;
+                               FOREACH_MOD(I_OnSyncUserMetaData, OnSyncUserMetaData(user, Creator, dest, list[j], true));
+                               if (!claimed)
+                               {
+                                       user->WriteServ("304 " + std::string(user->nick) + ":TAXONOMY METADATA " + list[j] + " = <unknown>");
+                               }
+                       }
+                       user->WriteServ("304 " + std::string(user->nick) + ":TAXONOMY END");
+               }
+               return CMD_FAILURE;
+       }
+};
+
+class ModuleTaxonomy : public Module
+{
+       cmd_taxonomy* newcommand;
+       bool claimed;
+ public:
+       ModuleTaxonomy(InspIRCd* Me)
+               : Module(Me)
+       {
+               
+               // Create a new command
+               newcommand = new cmd_taxonomy(ServerInstance, this, claimed);
+               ServerInstance->AddCommand(newcommand);
+       }
+
+       void Implements(char* List)
+       {
+               List[I_ProtoSendMetaData] = 1;
+       }
+
+       void ProtoSendMetaData(void* opaque, int target_type, void* target, const std::string &extname, const std::string &extdata)
+       {
+               if (target_type == TYPE_USER)
+               {
+                       userrec* spool = (userrec*)opaque;
+                       std::string taxstr = "304 " + std::string(spool->nick) + ":TAXONOMY METADATA "+extname+" = "+extdata;
+                       spool->WriteServ(taxstr);
+                       claimed = true;
+               }
+       }
+
+       virtual ~ModuleTaxonomy()
+       {
+       }
+
+       virtual Version GetVersion()
+       {
+               return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION);
+       }
+};
+
+MODULE_INIT(ModuleTaxonomy)
+
index 0733fd0f06e56202562a2b4f4a7e233740cc5fc9..6ec197eb69487bbf618992b92540e69e05da678b 100644 (file)
@@ -1 +1,67 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r\r/* $ModDesc: Provides a pointless /dalinfo command, demo module */\r\r/** Handle /DALINFO\r */\rclass cmd_dalinfo : public command_t\r{\r public:\r  /* Command 'dalinfo', takes no parameters and needs no special modes */\r        cmd_dalinfo (InspIRCd* Instance) : command_t(Instance,"DALINFO", 0, 0)\r {\r              this->source = "m_testcommand.so";\r     }\r\r     CmdResult Handle (const char** parameters, int pcnt, userrec *user)\r    {\r              user->WriteServ("NOTICE %s :*** DALNet had nothing to do with it.", user->nick);\r               return CMD_FAILURE;\r    }\r};\r\rclass ModuleTestCommand : public Module\r{\r        cmd_dalinfo* newcommand;\r public:\r      ModuleTestCommand(InspIRCd* Me)\r                : Module(Me)\r   {\r              // Create a new command\r                newcommand = new cmd_dalinfo(ServerInstance);\r          ServerInstance->AddCommand(newcommand);\r        }\r\r     void Implements(char* List)\r    {\r      }\r\r     virtual ~ModuleTestCommand()\r   {\r              delete newcommand;\r     }\r\r     virtual Version GetVersion()\r   {\r              return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION);\r    }\r};\r\rMODULE_INIT(ModuleTestCommand)\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+
+/* $ModDesc: Provides a pointless /dalinfo command, demo module */
+
+/** Handle /DALINFO
+ */
+class cmd_dalinfo : public command_t
+{
+ public:
+       /* Command 'dalinfo', takes no parameters and needs no special modes */
+       cmd_dalinfo (InspIRCd* Instance) : command_t(Instance,"DALINFO", 0, 0)
+       {
+               this->source = "m_testcommand.so";
+       }
+
+       CmdResult Handle (const char** parameters, int pcnt, userrec *user)
+       {
+               user->WriteServ("NOTICE %s :*** DALNet had nothing to do with it.", user->nick);
+               return CMD_FAILURE;
+       }
+};
+
+class ModuleTestCommand : public Module
+{
+       cmd_dalinfo* newcommand;
+ public:
+       ModuleTestCommand(InspIRCd* Me)
+               : Module(Me)
+       {
+               // Create a new command
+               newcommand = new cmd_dalinfo(ServerInstance);
+               ServerInstance->AddCommand(newcommand);
+       }
+
+       void Implements(char* List)
+       {
+       }
+
+       virtual ~ModuleTestCommand()
+       {
+               delete newcommand;
+       }
+
+       virtual Version GetVersion()
+       {
+               return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION);
+       }
+};
+
+MODULE_INIT(ModuleTestCommand)
+
index f705a1f95013ceb36a6510f2a5676e71d364537d..ae3da75497ce3c141233b3480a51865cfb79ae37 100644 (file)
@@ -1 +1,204 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *        the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r/* $ModDesc: Adds timed bans */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r#include "hashcomp.h"\r#include "configreader.h"\r\r/** Holds a timed ban\r */\rclass TimedBan : public classbase\r{\r public:\r  std::string channel;\r   std::string mask;\r      time_t expire;\r};\r\rtypedef std::vector<TimedBan> timedbans;\rtimedbans TimedBanList;\r\r/** Handle /TBAN\r */\rclass cmd_tban : public command_t\r{\r public:\r cmd_tban (InspIRCd* Instance) : command_t(Instance,"TBAN", 0, 3)\r       {\r              this->source = "m_timedbans.so";\r               syntax = "<channel> <duration> <banmask>";\r     }\r\r     CmdResult Handle (const char** parameters, int pcnt, userrec *user)\r    {\r              chanrec* channel = ServerInstance->FindChan(parameters[0]);\r            if (channel)\r           {\r                      int cm = channel->GetStatus(user);\r                     if ((cm == STATUS_HOP) || (cm == STATUS_OP))\r                   {\r                              if (!ServerInstance->IsValidMask(parameters[2]))\r                               {\r                                      user->WriteServ("NOTICE "+std::string(user->nick)+" :Invalid ban mask");\r                                       return CMD_FAILURE;\r                            }\r                              for (BanList::iterator i = channel->bans.begin(); i != channel->bans.end(); i++)\r                               {\r                                      if (!strcasecmp(i->data,parameters[2]))\r                                        {\r                                              user->WriteServ("NOTICE "+std::string(user->nick)+" :The ban "+std::string(parameters[2])+" is already on the banlist of "+std::string(parameters[0]));\r                                                return CMD_FAILURE;\r                                    }\r                              }\r                              TimedBan T;\r                            std::string channelname = parameters[0];\r                               long duration = ServerInstance->Duration(parameters[1]);\r                               unsigned long expire = duration + time(NULL);\r                          if (duration < 1)\r                              {\r                                      user->WriteServ("NOTICE "+std::string(user->nick)+" :Invalid ban time");\r                                       return CMD_FAILURE;\r                            }\r                              std::string mask = parameters[2];\r                              const char *setban[32];\r                                setban[0] = parameters[0];\r                             setban[1] = "+b";\r                              setban[2] = parameters[2];\r                             // use CallCommandHandler to make it so that the user sets the mode\r                            // themselves\r                          ServerInstance->CallCommandHandler("MODE",setban,3,user);\r                              /* Check if the ban was actually added (e.g. banlist was NOT full) */\r                          bool was_added = false;\r                                for (BanList::iterator i = channel->bans.begin(); i != channel->bans.end(); i++)\r                                       if (!strcasecmp(i->data,mask.c_str()))\r                                         was_added = true;\r                              if (was_added)\r                         {\r                                      T.channel = channelname;\r                                       T.mask = mask;\r                                 T.expire = expire;\r                                     TimedBanList.push_back(T);\r                                     channel->WriteChannelWithServ(ServerInstance->Config->ServerName, "NOTICE %s :%s added a timed ban on %s lasting for %ld seconds.", channel->name, user->nick, mask.c_str(), duration);\r                                        return CMD_SUCCESS;\r                            }\r                              return CMD_FAILURE;\r                    }\r                      else user->WriteServ("482 %s %s :You must be at least a half-operator to change modes on this channel",user->nick, channel->name);\r                     return CMD_FAILURE;\r            }\r              user->WriteServ("401 %s %s :No such channel",user->nick, parameters[0]);\r               return CMD_FAILURE;\r    }\r};\r\rclass ModuleTimedBans : public Module\r{\r  cmd_tban* mycommand;\r public:\r  ModuleTimedBans(InspIRCd* Me)\r          : Module(Me)\r   {\r              \r               mycommand = new cmd_tban(ServerInstance);\r              ServerInstance->AddCommand(mycommand);\r         TimedBanList.clear();\r  }\r      \r       virtual ~ModuleTimedBans()\r     {\r              TimedBanList.clear();\r  }\r\r     void Implements(char* List)\r    {\r              List[I_OnDelBan] = List[I_OnBackgroundTimer] = 1;\r      }\r\r     virtual int OnDelBan(userrec* source, chanrec* chan, const std::string &banmask)\r       {\r              irc::string listitem = banmask.c_str();\r                irc::string thischan = chan->name;\r             for (timedbans::iterator i = TimedBanList.begin(); i < TimedBanList.end(); i++)\r                {\r                      irc::string target = i->mask.c_str();\r                  irc::string tchan = i->channel.c_str();\r                        if ((listitem == target) && (tchan == thischan))\r                       {\r                              TimedBanList.erase(i);\r                         break;\r                 }\r              }\r              return 0;\r      }\r\r     virtual void OnBackgroundTimer(time_t curtime)\r {\r              bool again = true;\r             while (again)\r          {\r                      again = false;\r                 for (timedbans::iterator i = TimedBanList.begin(); i < TimedBanList.end(); i++)\r                        {\r                              if (curtime > i->expire)\r                               {\r                                      chanrec* cr = ServerInstance->FindChan(i->channel);\r                                    again = true;\r                                  if (cr)\r                                        {\r                                              cr->WriteChannelWithServ(ServerInstance->Config->ServerName, "NOTICE %s :Timed ban on %s expired.", cr->name, i->mask.c_str());\r                                                const char *setban[3];\r                                         setban[0] = i->channel.c_str();\r                                                setban[1] = "-b";\r                                              setban[2] = i->mask.c_str();\r                                           // kludge alert!\r                                               // ::SendMode expects a userrec* to send the numeric replies\r                                           // back to, so we create it a fake user that isnt in the user\r                                          // hash and set its descriptor to FD_MAGIC_NUMBER so the data\r                                          // falls into the abyss :p\r                                             userrec* temp = new userrec(ServerInstance);\r                                           temp->SetFd(FD_MAGIC_NUMBER);\r                                          /* FIX: Send mode remotely*/\r                                           std::deque<std::string> n;\r                                             n.push_back(setban[0]);\r                                                n.push_back("-b");\r                                             n.push_back(setban[2]);\r                                                ServerInstance->SendMode(setban,3,temp);\r                                               Event rmode((char *)&n, NULL, "send_mode");\r                                            rmode.Send(ServerInstance);\r                                            DELETE(temp);\r                                  }\r                                      else\r                                   {\r                                              /* Where the hell did our channel go?! */\r                                              TimedBanList.erase(i);\r                                 }\r                                      // we used to delete the item here, but we dont need to as the servermode above does it for us,\r                                        break;\r                         }\r                      }\r              }\r      }\r      \r       virtual Version GetVersion()\r   {\r              return Version(1,1,0,0,VF_VENDOR,API_VERSION);\r }\r};\r\rMODULE_INIT(ModuleTimedBans)\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *         the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+/* $ModDesc: Adds timed bans */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+#include "hashcomp.h"
+#include "configreader.h"
+
+/** Holds a timed ban
+ */
+class TimedBan : public classbase
+{
+ public:
+       std::string channel;
+       std::string mask;
+       time_t expire;
+};
+
+typedef std::vector<TimedBan> timedbans;
+timedbans TimedBanList;
+
+/** Handle /TBAN
+ */
+class cmd_tban : public command_t
+{
+ public:
+ cmd_tban (InspIRCd* Instance) : command_t(Instance,"TBAN", 0, 3)
+       {
+               this->source = "m_timedbans.so";
+               syntax = "<channel> <duration> <banmask>";
+       }
+
+       CmdResult Handle (const char** parameters, int pcnt, userrec *user)
+       {
+               chanrec* channel = ServerInstance->FindChan(parameters[0]);
+               if (channel)
+               {
+                       int cm = channel->GetStatus(user);
+                       if ((cm == STATUS_HOP) || (cm == STATUS_OP))
+                       {
+                               if (!ServerInstance->IsValidMask(parameters[2]))
+                               {
+                                       user->WriteServ("NOTICE "+std::string(user->nick)+" :Invalid ban mask");
+                                       return CMD_FAILURE;
+                               }
+                               for (BanList::iterator i = channel->bans.begin(); i != channel->bans.end(); i++)
+                               {
+                                       if (!strcasecmp(i->data,parameters[2]))
+                                       {
+                                               user->WriteServ("NOTICE "+std::string(user->nick)+" :The ban "+std::string(parameters[2])+" is already on the banlist of "+std::string(parameters[0]));
+                                               return CMD_FAILURE;
+                                       }
+                               }
+                               TimedBan T;
+                               std::string channelname = parameters[0];
+                               long duration = ServerInstance->Duration(parameters[1]);
+                               unsigned long expire = duration + time(NULL);
+                               if (duration < 1)
+                               {
+                                       user->WriteServ("NOTICE "+std::string(user->nick)+" :Invalid ban time");
+                                       return CMD_FAILURE;
+                               }
+                               std::string mask = parameters[2];
+                               const char *setban[32];
+                               setban[0] = parameters[0];
+                               setban[1] = "+b";
+                               setban[2] = parameters[2];
+                               // use CallCommandHandler to make it so that the user sets the mode
+                               // themselves
+                               ServerInstance->CallCommandHandler("MODE",setban,3,user);
+                               /* Check if the ban was actually added (e.g. banlist was NOT full) */
+                               bool was_added = false;
+                               for (BanList::iterator i = channel->bans.begin(); i != channel->bans.end(); i++)
+                                       if (!strcasecmp(i->data,mask.c_str()))
+                                               was_added = true;
+                               if (was_added)
+                               {
+                                       T.channel = channelname;
+                                       T.mask = mask;
+                                       T.expire = expire;
+                                       TimedBanList.push_back(T);
+                                       channel->WriteChannelWithServ(ServerInstance->Config->ServerName, "NOTICE %s :%s added a timed ban on %s lasting for %ld seconds.", channel->name, user->nick, mask.c_str(), duration);
+                                       return CMD_SUCCESS;
+                               }
+                               return CMD_FAILURE;
+                       }
+                       else user->WriteServ("482 %s %s :You must be at least a half-operator to change modes on this channel",user->nick, channel->name);
+                       return CMD_FAILURE;
+               }
+               user->WriteServ("401 %s %s :No such channel",user->nick, parameters[0]);
+               return CMD_FAILURE;
+       }
+};
+
+class ModuleTimedBans : public Module
+{
+       cmd_tban* mycommand;
+ public:
+       ModuleTimedBans(InspIRCd* Me)
+               : Module(Me)
+       {
+               
+               mycommand = new cmd_tban(ServerInstance);
+               ServerInstance->AddCommand(mycommand);
+               TimedBanList.clear();
+       }
+       
+       virtual ~ModuleTimedBans()
+       {
+               TimedBanList.clear();
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnDelBan] = List[I_OnBackgroundTimer] = 1;
+       }
+
+       virtual int OnDelBan(userrec* source, chanrec* chan, const std::string &banmask)
+       {
+               irc::string listitem = banmask.c_str();
+               irc::string thischan = chan->name;
+               for (timedbans::iterator i = TimedBanList.begin(); i < TimedBanList.end(); i++)
+               {
+                       irc::string target = i->mask.c_str();
+                       irc::string tchan = i->channel.c_str();
+                       if ((listitem == target) && (tchan == thischan))
+                       {
+                               TimedBanList.erase(i);
+                               break;
+                       }
+               }
+               return 0;
+       }
+
+       virtual void OnBackgroundTimer(time_t curtime)
+       {
+               bool again = true;
+               while (again)
+               {
+                       again = false;
+                       for (timedbans::iterator i = TimedBanList.begin(); i < TimedBanList.end(); i++)
+                       {
+                               if (curtime > i->expire)
+                               {
+                                       chanrec* cr = ServerInstance->FindChan(i->channel);
+                                       again = true;
+                                       if (cr)
+                                       {
+                                               cr->WriteChannelWithServ(ServerInstance->Config->ServerName, "NOTICE %s :Timed ban on %s expired.", cr->name, i->mask.c_str());
+                                               const char *setban[3];
+                                               setban[0] = i->channel.c_str();
+                                               setban[1] = "-b";
+                                               setban[2] = i->mask.c_str();
+                                               // kludge alert!
+                                               // ::SendMode expects a userrec* to send the numeric replies
+                                               // back to, so we create it a fake user that isnt in the user
+                                               // hash and set its descriptor to FD_MAGIC_NUMBER so the data
+                                               // falls into the abyss :p
+                                               userrec* temp = new userrec(ServerInstance);
+                                               temp->SetFd(FD_MAGIC_NUMBER);
+                                               /* FIX: Send mode remotely*/
+                                               std::deque<std::string> n;
+                                               n.push_back(setban[0]);
+                                               n.push_back("-b");
+                                               n.push_back(setban[2]);
+                                               ServerInstance->SendMode(setban,3,temp);
+                                               Event rmode((char *)&n, NULL, "send_mode");
+                                               rmode.Send(ServerInstance);
+                                               DELETE(temp);
+                                       }
+                                       else
+                                       {
+                                               /* Where the hell did our channel go?! */
+                                               TimedBanList.erase(i);
+                                       }
+                                       // we used to delete the item here, but we dont need to as the servermode above does it for us,
+                                       break;
+                               }
+                       }
+               }
+       }
+       
+       virtual Version GetVersion()
+       {
+               return Version(1,1,0,0,VF_VENDOR,API_VERSION);
+       }
+};
+
+MODULE_INIT(ModuleTimedBans)
+
index dd13a965cd100c79e32522aa5497e04ee6928092..834cb7f4cf7c4be236fb92e76d88e217fc6f1684 100644 (file)
@@ -1 +1,95 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r#include "wildcard.h"\r\r/* $ModDesc: Provides /tline command used to test who a mask matches */\r\r/** Handle /TLINE\r */ \rclass cmd_tline : public command_t\r{\r public:\r  cmd_tline (InspIRCd* Instance) : command_t(Instance,"TLINE", 'o', 1)\r   {\r              this->source = "m_tline.so";\r           this->syntax = "<mask>";\r       }\r\r     CmdResult Handle (const char** parameters, int pcnt, userrec *user)\r    {\r              float n_counted = 0;\r           float n_matched = 0;\r           float n_match_host = 0;\r                float n_match_ip = 0;\r\r         for (user_hash::const_iterator u = ServerInstance->clientlist->begin(); u != ServerInstance->clientlist->end(); u++)\r           {\r                      n_counted++;\r                   if (match(u->second->GetFullRealHost(),parameters[0]))\r                 {\r                              n_matched++;\r                           n_match_host++;\r                        }\r                      else\r                   {\r                              char host[MAXBUF];\r                             snprintf(host, MAXBUF, "%s@%s", u->second->ident, u->second->GetIPString());\r                           if (match(host, parameters[0], true))\r                          {\r                                      n_matched++;\r                                   n_match_ip++;\r                          }\r                      }\r              }\r              if (n_matched)\r                 user->WriteServ( "NOTICE %s :*** TLINE: Counted %0.0f user(s). Matched '%s' against %0.0f user(s) (%0.2f%% of the userbase). %0.0f by hostname and %0.0f by IP address.",user->nick, n_counted, parameters[0], n_matched, (n_matched/n_counted)*100, n_match_host, n_match_ip);\r                else\r                   user->WriteServ( "NOTICE %s :*** TLINE: Counted %0.0f user(s). Matched '%s' against no user(s).", user->nick, n_counted, parameters[0]);\r\r              return CMD_LOCALONLY;                   \r       }\r};\r\rclass ModuleTLine : public Module\r{\r      cmd_tline* newcommand;\r public:\r        ModuleTLine(InspIRCd* Me)\r              : Module(Me)\r   {\r              \r               newcommand = new cmd_tline(ServerInstance);\r            ServerInstance->AddCommand(newcommand);\r        }\r\r     void Implements(char* List)\r    {\r      }\r\r     virtual ~ModuleTLine()\r {\r      }\r      \r       virtual Version GetVersion()\r   {\r              return Version(1, 1, 0, 0, VF_VENDOR,API_VERSION);\r     }\r};\r\rMODULE_INIT(ModuleTLine)\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+#include "wildcard.h"
+
+/* $ModDesc: Provides /tline command used to test who a mask matches */
+
+/** Handle /TLINE
+ */ 
+class cmd_tline : public command_t
+{
+ public:
+       cmd_tline (InspIRCd* Instance) : command_t(Instance,"TLINE", 'o', 1)
+       {
+               this->source = "m_tline.so";
+               this->syntax = "<mask>";
+       }
+
+       CmdResult Handle (const char** parameters, int pcnt, userrec *user)
+       {
+               float n_counted = 0;
+               float n_matched = 0;
+               float n_match_host = 0;
+               float n_match_ip = 0;
+
+               for (user_hash::const_iterator u = ServerInstance->clientlist->begin(); u != ServerInstance->clientlist->end(); u++)
+               {
+                       n_counted++;
+                       if (match(u->second->GetFullRealHost(),parameters[0]))
+                       {
+                               n_matched++;
+                               n_match_host++;
+                       }
+                       else
+                       {
+                               char host[MAXBUF];
+                               snprintf(host, MAXBUF, "%s@%s", u->second->ident, u->second->GetIPString());
+                               if (match(host, parameters[0], true))
+                               {
+                                       n_matched++;
+                                       n_match_ip++;
+                               }
+                       }
+               }
+               if (n_matched)
+                       user->WriteServ( "NOTICE %s :*** TLINE: Counted %0.0f user(s). Matched '%s' against %0.0f user(s) (%0.2f%% of the userbase). %0.0f by hostname and %0.0f by IP address.",user->nick, n_counted, parameters[0], n_matched, (n_matched/n_counted)*100, n_match_host, n_match_ip);
+               else
+                       user->WriteServ( "NOTICE %s :*** TLINE: Counted %0.0f user(s). Matched '%s' against no user(s).", user->nick, n_counted, parameters[0]);
+
+               return CMD_LOCALONLY;                   
+       }
+};
+
+class ModuleTLine : public Module
+{
+       cmd_tline* newcommand;
+ public:
+       ModuleTLine(InspIRCd* Me)
+               : Module(Me)
+       {
+               
+               newcommand = new cmd_tline(ServerInstance);
+               ServerInstance->AddCommand(newcommand);
+       }
+
+       void Implements(char* List)
+       {
+       }
+
+       virtual ~ModuleTLine()
+       {
+       }
+       
+       virtual Version GetVersion()
+       {
+               return Version(1, 1, 0, 0, VF_VENDOR,API_VERSION);
+       }
+};
+
+MODULE_INIT(ModuleTLine)
+
index 61b58f302c87fae08e909c51c243b6aacaa96d37..6794f46431699501ef2a8854eebd8f7fb86fef48 100644 (file)
@@ -1 +1,98 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r\rstatic const char* dummy = "ON";\r\r/* $ModDesc: Provides aliases of commands. */\r\rclass ModuleUHNames : public Module\r{\r       CUList nl;\r public:\r    \r       ModuleUHNames(InspIRCd* Me)\r            : Module(Me)\r   {\r      }\r\r     void Implements(char* List)\r    {\r              List[I_OnSyncUserMetaData] = List[I_OnPreCommand] = List[I_OnUserList] = List[I_On005Numeric] = 1;\r     }\r\r     virtual ~ModuleUHNames()\r       {\r      }\r\r     void OnSyncUserMetaData(userrec* user, Module* proto,void* opaque, const std::string &extname, bool displayable)\r       {\r              if ((displayable) && (extname == "UHNAMES"))\r                   proto->ProtoSendMetaData(opaque, TYPE_USER, user, extname, "Enabled");\r }\r\r     virtual Version GetVersion()\r   {\r              return Version(1,1,0,1,VF_VENDOR,API_VERSION);\r }\r\r     virtual void On005Numeric(std::string &output)\r {\r              output.append(" UHNAMES");\r     }\r\r     Priority Prioritize()\r  {\r              return (Priority)ServerInstance->PriorityBefore("m_namesx.so");\r        }\r\r     virtual int OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line)\r       {\r              irc::string c = command.c_str();\r               /* We don't actually create a proper command handler class for PROTOCTL,\r                * because other modules might want to have PROTOCTL hooks too.\r                 * Therefore, we just hook its as an unvalidated command therefore we\r           * can capture it even if it doesnt exist! :-)\r          */\r            if (c == "PROTOCTL")\r           {\r                      if ((pcnt) && (!strcasecmp(parameters[0],"UHNAMES")))\r                  {\r                              user->Extend("UHNAMES",dummy);\r                         return 1;\r                      }\r              }\r              return 0;\r      }\r\r     /* IMPORTANT: This must be prioritized above NAMESX! */\r        virtual int OnUserList(userrec* user, chanrec* Ptr, CUList* &ulist)\r    {\r              if (user->GetExt("UHNAMES"))\r           {\r                      if (!ulist)\r                            ulist = Ptr->GetUsers();\r\r                      for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)\r                              i->second = i->first->GetFullHost();\r           }\r              return 0;               \r       }\r};\r\rMODULE_INIT(ModuleUHNames)\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+
+static const char* dummy = "ON";
+
+/* $ModDesc: Provides aliases of commands. */
+
+class ModuleUHNames : public Module
+{
+       CUList nl;
+ public:
+       
+       ModuleUHNames(InspIRCd* Me)
+               : Module(Me)
+       {
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnSyncUserMetaData] = List[I_OnPreCommand] = List[I_OnUserList] = List[I_On005Numeric] = 1;
+       }
+
+       virtual ~ModuleUHNames()
+       {
+       }
+
+       void OnSyncUserMetaData(userrec* user, Module* proto,void* opaque, const std::string &extname, bool displayable)
+       {
+               if ((displayable) && (extname == "UHNAMES"))
+                       proto->ProtoSendMetaData(opaque, TYPE_USER, user, extname, "Enabled");
+       }
+
+       virtual Version GetVersion()
+       {
+               return Version(1,1,0,1,VF_VENDOR,API_VERSION);
+       }
+
+       virtual void On005Numeric(std::string &output)
+       {
+               output.append(" UHNAMES");
+       }
+
+       Priority Prioritize()
+       {
+               return (Priority)ServerInstance->PriorityBefore("m_namesx.so");
+       }
+
+       virtual int OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line)
+       {
+               irc::string c = command.c_str();
+               /* We don't actually create a proper command handler class for PROTOCTL,
+                * because other modules might want to have PROTOCTL hooks too.
+                * Therefore, we just hook its as an unvalidated command therefore we
+                * can capture it even if it doesnt exist! :-)
+                */
+               if (c == "PROTOCTL")
+               {
+                       if ((pcnt) && (!strcasecmp(parameters[0],"UHNAMES")))
+                       {
+                               user->Extend("UHNAMES",dummy);
+                               return 1;
+                       }
+               }
+               return 0;
+       }
+
+       /* IMPORTANT: This must be prioritized above NAMESX! */
+       virtual int OnUserList(userrec* user, chanrec* Ptr, CUList* &ulist)
+       {
+               if (user->GetExt("UHNAMES"))
+               {
+                       if (!ulist)
+                               ulist = Ptr->GetUsers();
+
+                       for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
+                               i->second = i->first->GetFullHost();
+               }
+               return 0;               
+       }
+};
+
+MODULE_INIT(ModuleUHNames)
+
index bcf18b3088ec0e9962416c2d44f74fe9266a4195..ab748663c9c713487d7551e0ef1be7f0236ba17d 100644 (file)
@@ -1 +1,107 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r/* $ModDesc: Provides the UNINVITE command which lets users un-invite other users from channels (!) */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r#include "configreader.h"\r\r/** Handle /UNINVITE\r */     \rclass cmd_uninvite : public command_t\r{\r public:\r     cmd_uninvite (InspIRCd* Instance) : command_t(Instance,"UNINVITE", 0, 2)\r       {\r              this->source = "m_uninvite.so";\r                syntax = "<nick> <channel>";\r   }\r\r     CmdResult Handle (const char** parameters, int pcnt, userrec *user)\r    {\r              userrec* u = ServerInstance->FindNick(parameters[0]);\r          chanrec* c = ServerInstance->FindChan(parameters[1]);\r                   \r              if ((!c) || (!u))\r              {       \r                       if (!c)\r                        {\r                              user->WriteServ("401 %s %s :No such nick/channel",user->nick, parameters[1]);\r                  }\r                      else\r                   {\r                              user->WriteServ("401 %s %s :No such nick/channel",user->nick, parameters[0]);\r                  }\r                              \r                       return CMD_FAILURE;\r            }       \r\r              if (c->modes[CM_INVITEONLY])\r           {\r                      if (c->GetStatus(user) < STATUS_HOP)\r                   {\r                              user->WriteServ("482 %s %s :You must be at least a half-operator to change modes on this channel",user->nick, c->name);\r                                return CMD_FAILURE;\r                    }\r              }\r\r             irc::string xname(c->name);\r\r           if (!u->IsInvited(xname))\r              {\r                      user->WriteServ("491 %s %s %s :Is not invited to channel %s",user->nick,u->nick,c->name,c->name);\r                      return CMD_FAILURE;\r            }\r              if (!c->HasUser(user))\r         {\r                      user->WriteServ("492 %s %s :You're not on that channel!",user->nick, c->name);\r                 return CMD_FAILURE;\r            }\r\r             u->RemoveInvite(xname);\r                user->WriteServ("494 %s %s %s :Uninvited",user->nick,c->name,u->nick);\r         u->WriteServ("493 %s :You were uninvited from %s by %s",u->nick,c->name,user->nick);\r           c->WriteChannelWithServ(ServerInstance->Config->ServerName, "NOTICE %s :*** %s uninvited %s.", c->name, user->nick, u->nick);\r\r         return CMD_SUCCESS;\r    }\r};\r\rclass ModuleUninvite : public Module\r{\r   cmd_uninvite *mycommand;\r\r public:\r\r    ModuleUninvite(InspIRCd* Me) : Module(Me)\r      {\r              \r               mycommand = new cmd_uninvite(ServerInstance);\r          ServerInstance->AddCommand(mycommand);\r }\r      \r       virtual ~ModuleUninvite()\r      {\r      }\r      \r       virtual Version GetVersion()\r   {\r              return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION);\r    }\r};\r\rMODULE_INIT(ModuleUninvite)\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+/* $ModDesc: Provides the UNINVITE command which lets users un-invite other users from channels (!) */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+#include "configreader.h"
+
+/** Handle /UNINVITE
+ */     
+class cmd_uninvite : public command_t
+{
+ public:
+       cmd_uninvite (InspIRCd* Instance) : command_t(Instance,"UNINVITE", 0, 2)
+       {
+               this->source = "m_uninvite.so";
+               syntax = "<nick> <channel>";
+       }
+
+       CmdResult Handle (const char** parameters, int pcnt, userrec *user)
+       {
+               userrec* u = ServerInstance->FindNick(parameters[0]);
+               chanrec* c = ServerInstance->FindChan(parameters[1]);
+                        
+               if ((!c) || (!u))
+               {       
+                       if (!c)
+                       {
+                               user->WriteServ("401 %s %s :No such nick/channel",user->nick, parameters[1]);
+                       }
+                       else
+                       {
+                               user->WriteServ("401 %s %s :No such nick/channel",user->nick, parameters[0]);
+                       }
+                               
+                       return CMD_FAILURE;
+               }       
+
+               if (c->modes[CM_INVITEONLY])
+               {
+                       if (c->GetStatus(user) < STATUS_HOP)
+                       {
+                               user->WriteServ("482 %s %s :You must be at least a half-operator to change modes on this channel",user->nick, c->name);
+                               return CMD_FAILURE;
+                       }
+               }
+
+               irc::string xname(c->name);
+
+               if (!u->IsInvited(xname))
+               {
+                       user->WriteServ("491 %s %s %s :Is not invited to channel %s",user->nick,u->nick,c->name,c->name);
+                       return CMD_FAILURE;
+               }
+               if (!c->HasUser(user))
+               {
+                       user->WriteServ("492 %s %s :You're not on that channel!",user->nick, c->name);
+                       return CMD_FAILURE;
+               }
+
+               u->RemoveInvite(xname);
+               user->WriteServ("494 %s %s %s :Uninvited",user->nick,c->name,u->nick);
+               u->WriteServ("493 %s :You were uninvited from %s by %s",u->nick,c->name,user->nick);
+               c->WriteChannelWithServ(ServerInstance->Config->ServerName, "NOTICE %s :*** %s uninvited %s.", c->name, user->nick, u->nick);
+
+               return CMD_SUCCESS;
+       }
+};
+
+class ModuleUninvite : public Module
+{
+       cmd_uninvite *mycommand;
+
+ public:
+
+       ModuleUninvite(InspIRCd* Me) : Module(Me)
+       {
+               
+               mycommand = new cmd_uninvite(ServerInstance);
+               ServerInstance->AddCommand(mycommand);
+       }
+       
+       virtual ~ModuleUninvite()
+       {
+       }
+       
+       virtual Version GetVersion()
+       {
+               return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION);
+       }
+};
+
+MODULE_INIT(ModuleUninvite)
+
index 979ee6112674c22e87ac04de3137bf39e164b2fe..296d523008dd3f41ef09a561e0dd8c67334dbc97 100644 (file)
@@ -1 +1,86 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r\r/* $ModDesc: Provides support for USERIP command */\r\r/** Handle /USERIP\r */\rclass cmd_userip : public command_t\r{\r public:\r   cmd_userip (InspIRCd* Instance) : command_t(Instance,"USERIP", 'o', 1)\r {\r              this->source = "m_userip.so";\r          syntax = "<nick>{,<nick>}";\r    }\r\r     CmdResult Handle (const char** parameters, int pcnt, userrec *user)\r    {\r              std::string retbuf = std::string("340 ") + user->nick + " :";\r\r         for (int i = 0; i < pcnt; i++)\r         {\r                      userrec *u = ServerInstance->FindNick(parameters[i]);\r                  if ((u) && (u->registered == REG_ALL))\r                 {\r                              retbuf = retbuf + u->nick + (IS_OPER(u) ? "*" : "") + "=+" + u->ident + "@" + u->GetIPString() + " ";\r                  }\r              }\r\r             user->WriteServ(retbuf);\r\r              /* Dont send to the network */\r         return CMD_FAILURE;\r    }\r};\r\rclass ModuleUserIP : public Module\r{\r     cmd_userip* mycommand;\r public:\r        ModuleUserIP(InspIRCd* Me)\r             : Module(Me)\r   {\r              \r               mycommand = new cmd_userip(ServerInstance);\r            ServerInstance->AddCommand(mycommand);\r }\r\r     void Implements(char* List)\r    {\r              List[I_On005Numeric] = 1;\r      }\r\r     virtual void On005Numeric(std::string &output)\r {\r              output = output + std::string(" USERIP");\r      }\r      \r       virtual ~ModuleUserIP()\r        {\r      }\r      \r       virtual Version GetVersion()\r   {\r              return Version(1,1,0,1,VF_VENDOR,API_VERSION);\r }\r      \r};\r\rMODULE_INIT(ModuleUserIP)\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+
+/* $ModDesc: Provides support for USERIP command */
+
+/** Handle /USERIP
+ */
+class cmd_userip : public command_t
+{
+ public:
+       cmd_userip (InspIRCd* Instance) : command_t(Instance,"USERIP", 'o', 1)
+       {
+               this->source = "m_userip.so";
+               syntax = "<nick>{,<nick>}";
+       }
+
+       CmdResult Handle (const char** parameters, int pcnt, userrec *user)
+       {
+               std::string retbuf = std::string("340 ") + user->nick + " :";
+
+               for (int i = 0; i < pcnt; i++)
+               {
+                       userrec *u = ServerInstance->FindNick(parameters[i]);
+                       if ((u) && (u->registered == REG_ALL))
+                       {
+                               retbuf = retbuf + u->nick + (IS_OPER(u) ? "*" : "") + "=+" + u->ident + "@" + u->GetIPString() + " ";
+                       }
+               }
+
+               user->WriteServ(retbuf);
+
+               /* Dont send to the network */
+               return CMD_FAILURE;
+       }
+};
+
+class ModuleUserIP : public Module
+{
+       cmd_userip* mycommand;
+ public:
+       ModuleUserIP(InspIRCd* Me)
+               : Module(Me)
+       {
+               
+               mycommand = new cmd_userip(ServerInstance);
+               ServerInstance->AddCommand(mycommand);
+       }
+
+       void Implements(char* List)
+       {
+               List[I_On005Numeric] = 1;
+       }
+
+       virtual void On005Numeric(std::string &output)
+       {
+               output = output + std::string(" USERIP");
+       }
+       
+       virtual ~ModuleUserIP()
+       {
+       }
+       
+       virtual Version GetVersion()
+       {
+               return Version(1,1,0,1,VF_VENDOR,API_VERSION);
+       }
+       
+};
+
+MODULE_INIT(ModuleUserIP)
+
index 10fc76f050ed263dd1497222164faf14e57e8f2e..c77a3f85f56068937945ddd9adefbc43ac1feee5 100644 (file)
@@ -1 +1,95 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r\r/* $ModDesc: Provides masking of user hostnames via traditional /VHOST command */\r\rstatic ConfigReader* Conf;\r\r/** Handle /VHOST\r */\rclass cmd_vhost : public command_t\r{\r public:\r   cmd_vhost (InspIRCd* Instance) : command_t(Instance,"VHOST", 0, 2)\r     {\r              this->source = "m_vhost.so";\r           syntax = "<username> <password>";\r      }\r\r     CmdResult Handle (const char** parameters, int pcnt, userrec *user)\r    {\r              for (int index = 0; index < Conf->Enumerate("vhost"); index++)\r         {\r                      std::string mask = Conf->ReadValue("vhost","host",index);\r                      std::string username = Conf->ReadValue("vhost","user",index);\r                  std::string pass = Conf->ReadValue("vhost","pass",index);\r                      if ((!strcmp(parameters[0],username.c_str())) && (!strcmp(parameters[1],pass.c_str())))\r                        {\r                              if (!mask.empty())\r                             {\r                                      user->WriteServ("NOTICE "+std::string(user->nick)+" :Setting your VHost: " + mask);\r                                    user->ChangeDisplayedHost(mask.c_str());\r                                       return CMD_FAILURE;\r                            }\r                      }\r              }\r              user->WriteServ("NOTICE "+std::string(user->nick)+" :Invalid username or password.");\r          return CMD_FAILURE;\r    }\r};\r\rclass ModuleVHost : public Module\r{\r private:\r\r   cmd_vhost* mycommand;\r   \r public:\r     ModuleVHost(InspIRCd* Me) : Module(Me)\r {\r              \r               Conf = new ConfigReader(ServerInstance);\r               mycommand = new cmd_vhost(ServerInstance);\r             ServerInstance->AddCommand(mycommand);\r }\r      \r       virtual ~ModuleVHost()\r {\r              DELETE(Conf);\r  }\r\r     void Implements(char* List)\r    {\r              List[I_OnRehash] = 1;\r  }\r\r     virtual void OnRehash(userrec* user, const std::string &parameter)\r     {\r              DELETE(Conf);\r          Conf = new ConfigReader(ServerInstance);\r       }\r      \r       virtual Version GetVersion()\r   {\r              return Version(1,1,0,1,VF_VENDOR,API_VERSION);\r }\r      \r};\r\rMODULE_INIT(ModuleVHost)\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+
+/* $ModDesc: Provides masking of user hostnames via traditional /VHOST command */
+
+static ConfigReader* Conf;
+
+/** Handle /VHOST
+ */
+class cmd_vhost : public command_t
+{
+ public:
+       cmd_vhost (InspIRCd* Instance) : command_t(Instance,"VHOST", 0, 2)
+       {
+               this->source = "m_vhost.so";
+               syntax = "<username> <password>";
+       }
+
+       CmdResult Handle (const char** parameters, int pcnt, userrec *user)
+       {
+               for (int index = 0; index < Conf->Enumerate("vhost"); index++)
+               {
+                       std::string mask = Conf->ReadValue("vhost","host",index);
+                       std::string username = Conf->ReadValue("vhost","user",index);
+                       std::string pass = Conf->ReadValue("vhost","pass",index);
+                       if ((!strcmp(parameters[0],username.c_str())) && (!strcmp(parameters[1],pass.c_str())))
+                       {
+                               if (!mask.empty())
+                               {
+                                       user->WriteServ("NOTICE "+std::string(user->nick)+" :Setting your VHost: " + mask);
+                                       user->ChangeDisplayedHost(mask.c_str());
+                                       return CMD_FAILURE;
+                               }
+                       }
+               }
+               user->WriteServ("NOTICE "+std::string(user->nick)+" :Invalid username or password.");
+               return CMD_FAILURE;
+       }
+};
+
+class ModuleVHost : public Module
+{
+ private:
+
+       cmd_vhost* mycommand;
+        
+ public:
+       ModuleVHost(InspIRCd* Me) : Module(Me)
+       {
+               
+               Conf = new ConfigReader(ServerInstance);
+               mycommand = new cmd_vhost(ServerInstance);
+               ServerInstance->AddCommand(mycommand);
+       }
+       
+       virtual ~ModuleVHost()
+       {
+               DELETE(Conf);
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnRehash] = 1;
+       }
+
+       virtual void OnRehash(userrec* user, const std::string &parameter)
+       {
+               DELETE(Conf);
+               Conf = new ConfigReader(ServerInstance);
+       }
+       
+       virtual Version GetVersion()
+       {
+               return Version(1,1,0,1,VF_VENDOR,API_VERSION);
+       }
+       
+};
+
+MODULE_INIT(ModuleVHost)
+
index 2f847661e80cb77510b19e574634167bd424f4ef..552e3317a51031ff6565f1ebfd3a5562a677f0c8 100644 (file)
@@ -1 +1,472 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r#include "hashcomp.h"\r\r/* $ModDesc: Provides support for the /WATCH command */\r\r/* This module has been refactored to provide a very efficient (in terms of cpu time)\r * implementation of /WATCH.\r *\r * To improve the efficiency of watch, many lists are kept. The first primary list is\r * a hash_map of who's being watched by who. For example:\r *\r * KEY: Brain   --->  Watched by:  Boo, w00t, Om\r * KEY: Boo     --->  Watched by:  Brain, w00t\r * \r * This is used when we want to tell all the users that are watching someone that\r * they are now available or no longer available. For example, if the hash was\r * populated as shown above, then when Brain signs on, messages are sent to Boo, w00t\r * and Om by reading their 'watched by' list. When this occurs, their online status\r * in each of these users lists (see below) is also updated.\r *\r * Each user also has a seperate (smaller) map attached to their userrec whilst they\r * have any watch entries, which is managed by class Extensible. When they add or remove\r * a watch entry from their list, it is inserted here, as well as the main list being\r * maintained. This map also contains the user's online status. For users that are\r * offline, the key points at an empty string, and for users that are online, the key\r * points at a string containing "users-ident users-host users-signon-time". This is\r * stored in this manner so that we don't have to FindUser() to fetch this info, the\r * users signon can populate the field for us.\r *\r * For example, going again on the example above, this would be w00t's watchlist:\r *\r * KEY: Boo    --->  Status: "Boo brains.sexy.babe 535342348"\r * KEY: Brain  --->  Status: ""\r *\r * In this list we can see that Boo is online, and Brain is offline. We can then\r * use this list for 'WATCH L', and 'WATCH S' can be implemented as a combination\r * of the above two data structures, with minimum CPU penalty for doing so.\r *\r * In short, the least efficient this ever gets is O(n), and thats only because\r * there are parts that *must* loop (e.g. telling all users that are watching a\r * nick that the user online), however this is a *major* improvement over the\r * 1.0 implementation, which in places had O(n^n) and worse in it, because this\r * implementation scales based upon the sizes of the watch entries, whereas the\r * old system would scale (or not as the case may be) according to the total number\r * of users using WATCH.\r */\r\r/*\r * Before you start screaming, this definition is only used here, so moving it to a header is pointless.\r * Yes, it's horrid. Blame cl for being different. -- w00t\r */\r#ifdef WINDOWS\rtypedef nspace::hash_map<irc::string, std::deque<userrec*>, nspace::hash_compare<irc::string, less<irc::string> > > watchentries;\r#else\rtypedef nspace::hash_map<irc::string, std::deque<userrec*>, nspace::hash<irc::string> > watchentries;\r#endif\rtypedef std::map<irc::string, std::string> watchlist;\r\r/* Who's watching each nickname.\r * NOTE: We do NOT iterate this to display a user's WATCH list!\r * See the comments above!\r */\rwatchentries* whos_watching_me;\r\r/** Handle /WATCH\r */\rclass cmd_watch : public command_t\r{\r    unsigned int& MAX_WATCH;\r public:\r      CmdResult remove_watch(userrec* user, const char* nick)\r        {\r              // removing an item from the list\r              if (!ServerInstance->IsNick(nick))\r             {\r                      user->WriteServ("942 %s %s :Invalid nickname", user->nick, nick);\r                      return CMD_FAILURE;\r            }\r\r             watchlist* wl;\r         if (user->GetExt("watchlist", wl))\r             {\r                      /* Yup, is on my list */\r                       watchlist::iterator n = wl->find(nick);\r                        if (n != wl->end())\r                    {\r                              if (!n->second.empty())\r                                        user->WriteServ("602 %s %s %s :stopped watching", user->nick, n->first.c_str(), n->second.c_str());\r                            else\r                                   user->WriteServ("602 %s %s * * 0 :stopped watching", user->nick, nick);\r\r                               wl->erase(n);\r                  }\r\r                     if (!wl->size())\r                       {\r                              user->Shrink("watchlist");\r                             delete wl;\r                     }\r\r                     watchentries::iterator x = whos_watching_me->find(nick);\r                       if (x != whos_watching_me->end())\r                      {\r                              /* People are watching this user, am i one of them? */\r                         std::deque<userrec*>::iterator n = std::find(x->second.begin(), x->second.end(), user);\r                                if (n != x->second.end())\r                                      /* I'm no longer watching you... */\r                                    x->second.erase(n);\r\r                           if (!x->second.size())\r                                 whos_watching_me->erase(nick);\r                 }\r              }\r\r             /* This might seem confusing, but we return CMD_FAILURE\r                 * to indicate that this message shouldnt be routed across\r              * the network to other linked servers.\r                 */\r            return CMD_FAILURE;\r    }\r\r     CmdResult add_watch(userrec* user, const char* nick)\r   {\r              if (!ServerInstance->IsNick(nick))\r             {\r                      user->WriteServ("942 %s %s :Invalid nickname",user->nick,nick);\r                        return CMD_FAILURE;\r            }\r\r             watchlist* wl;\r         if (!user->GetExt("watchlist", wl))\r            {\r                      wl = new watchlist();\r                  user->Extend("watchlist", wl);\r         }\r\r             if (wl->size() == MAX_WATCH)\r           {\r                      user->WriteServ("512 %s %s :Too many WATCH entries", user->nick, nick);\r                        return CMD_FAILURE;\r            }\r\r             watchlist::iterator n = wl->find(nick);\r                if (n == wl->end())\r            {\r                      /* Don't already have the user on my watch list, proceed */\r                    watchentries::iterator x = whos_watching_me->find(nick);\r                       if (x != whos_watching_me->end())\r                      {\r                              /* People are watching this user, add myself */\r                                x->second.push_back(user);\r                     }\r                      else\r                   {\r                              std::deque<userrec*> newlist;\r                          newlist.push_back(user);\r                               (*(whos_watching_me))[nick] = newlist;\r                 }\r\r                     userrec* target = ServerInstance->FindNick(nick);\r                      if (target)\r                    {\r                              if (target->Visibility && !target->Visibility->VisibleTo(user))\r                                {\r                                      (*wl)[nick] = "";\r                                      user->WriteServ("605 %s %s * * 0 :is offline",user->nick, nick);\r                                       return CMD_FAILURE;\r                            }\r\r                             (*wl)[nick] = std::string(target->ident).append(" ").append(target->dhost).append(" ").append(ConvToStr(target->age));\r                         user->WriteServ("604 %s %s %s :is online",user->nick, nick, (*wl)[nick].c_str());\r                      }\r                      else\r                   {\r                              (*wl)[nick] = "";\r                              user->WriteServ("605 %s %s * * 0 :is offline",user->nick, nick);\r                       }\r              }\r\r             return CMD_FAILURE;\r    }\r\r     cmd_watch (InspIRCd* Instance, unsigned int &maxwatch) : command_t(Instance,"WATCH",0,0), MAX_WATCH(maxwatch)\r  {\r              this->source = "m_watch.so";\r           syntax = "[C|L|S]|[+|-<nick>]";\r        }\r\r     CmdResult Handle (const char** parameters, int pcnt, userrec *user)\r    {\r              if (!pcnt)\r             {\r                      watchlist* wl;\r                 if (user->GetExt("watchlist", wl))\r                     {\r                              for (watchlist::iterator q = wl->begin(); q != wl->end(); q++)\r                         {\r                                      if (!q->second.empty())\r                                                user->WriteServ("604 %s %s %s :is online", user->nick, q->first.c_str(), q->second.c_str());\r                           }\r                      }\r                      user->WriteServ("607 %s :End of WATCH list",user->nick);\r               }\r              else if (pcnt > 0)\r             {\r                      for (int x = 0; x < pcnt; x++)\r                 {\r                              const char *nick = parameters[x];\r                              if (!strcasecmp(nick,"C"))\r                             {\r                                      // watch clear\r                                 watchlist* wl;\r                                 if (user->GetExt("watchlist", wl))\r                                     {\r                                              for (watchlist::iterator i = wl->begin(); i != wl->end(); i++)\r                                         {\r                                                      watchentries::iterator x = whos_watching_me->find(i->first);\r                                                   if (x != whos_watching_me->end())\r                                                      {\r                                                              /* People are watching this user, am i one of them? */\r                                                         std::deque<userrec*>::iterator n = std::find(x->second.begin(), x->second.end(), user);\r                                                                if (n != x->second.end())\r                                                                      /* I'm no longer watching you... */\r                                                                    x->second.erase(n);\r\r                                                           if (!x->second.size())\r                                                                 whos_watching_me->erase(user->nick);\r                                                   }\r                                              }\r\r                                             delete wl;\r                                             user->Shrink("watchlist");\r                                     }\r                              }\r                              else if (!strcasecmp(nick,"L"))\r                                {\r                                      watchlist* wl;\r                                 if (user->GetExt("watchlist", wl))\r                                     {\r                                              for (watchlist::iterator q = wl->begin(); q != wl->end(); q++)\r                                         {\r                                                      if (!q->second.empty())\r                                                                user->WriteServ("604 %s %s %s :is online", user->nick, q->first.c_str(), q->second.c_str());\r                                                   else\r                                                           user->WriteServ("605 %s %s * * 0 :is offline", user->nick, q->first.c_str());\r                                          }\r                                      }\r                                      user->WriteServ("607 %s :End of WATCH list",user->nick);\r                               }\r                              else if (!strcasecmp(nick,"S"))\r                                {\r                                      watchlist* wl;\r                                 int you_have = 0;\r                                      int youre_on = 0;\r                                      std::string list;\r\r                                     if (user->GetExt("watchlist", wl))\r                                     {\r                                              for (watchlist::iterator q = wl->begin(); q != wl->end(); q++)\r                                                 list.append(q->first.c_str()).append(" ");\r                                             you_have = wl->size();\r                                 }\r\r                                     watchentries::iterator x = whos_watching_me->find(user->nick);\r                                 if (x != whos_watching_me->end())\r                                              youre_on = x->second.size();\r\r                                  user->WriteServ("603 %s :You have %d and are on %d WATCH entries", user->nick, you_have, youre_on);\r                                    user->WriteServ("606 %s :%s",user->nick, list.c_str());\r                                        user->WriteServ("607 %s :End of WATCH S",user->nick);\r                          }\r                              else if (nick[0] == '-')\r                               {\r                                      nick++;\r                                        remove_watch(user, nick);\r                              }\r                              else if (nick[0] == '+')\r                               {\r                                      nick++;\r                                        add_watch(user, nick);\r                         }\r                      }\r              }\r              /* So that spanningtree doesnt pass the WATCH commands to the network! */\r              return CMD_FAILURE;\r    }\r};\r\rclass Modulewatch : public Module\r{\r      cmd_watch* mycommand;\r  unsigned int maxwatch;\r public:\r\r       Modulewatch(InspIRCd* Me)\r              : Module(Me), maxwatch(32)\r     {\r              OnRehash(NULL, "");\r            whos_watching_me = new watchentries();\r         mycommand = new cmd_watch(ServerInstance, maxwatch);\r           ServerInstance->AddCommand(mycommand);\r }\r\r     virtual void OnRehash(userrec* user, const std::string &parameter)\r     {\r              ConfigReader Conf(ServerInstance);\r             maxwatch = Conf.ReadInteger("watch", "maxentries", 0, true);\r           if (!maxwatch)\r                 maxwatch = 32;\r }\r\r     void Implements(char* List)\r    {\r              List[I_OnRehash] = List[I_OnGarbageCollect] = List[I_OnCleanup] = List[I_OnUserQuit] = List[I_OnPostConnect] = List[I_OnUserPostNick] = List[I_On005Numeric] = 1;\r      }\r\r     virtual void OnUserQuit(userrec* user, const std::string &reason, const std::string &oper_message)\r     {\r              watchentries::iterator x = whos_watching_me->find(user->nick);\r         if (x != whos_watching_me->end())\r              {\r                      for (std::deque<userrec*>::iterator n = x->second.begin(); n != x->second.end(); n++)\r                  {\r                              if (!user->Visibility || user->Visibility->VisibleTo(user))\r                                    (*n)->WriteServ("601 %s %s %s %s %lu :went offline", (*n)->nick ,user->nick, user->ident, user->dhost, ServerInstance->Time());\r\r                               watchlist* wl;\r                         if ((*n)->GetExt("watchlist", wl))\r                                     /* We were on somebody's notify list, set ourselves offline */\r                                 (*wl)[user->nick] = "";\r                        }\r              }\r\r             /* Now im quitting, if i have a notify list, im no longer watching anyone */\r           watchlist* wl;\r         if (user->GetExt("watchlist", wl))\r             {\r                      /* Iterate every user on my watch list, and take me out of the whos_watching_me map for each one we're watching */\r                     for (watchlist::iterator i = wl->begin(); i != wl->end(); i++)\r                 {\r                              watchentries::iterator x = whos_watching_me->find(i->first);\r                           if (x != whos_watching_me->end())\r                              {\r                                              /* People are watching this user, am i one of them? */\r                                         std::deque<userrec*>::iterator n = std::find(x->second.begin(), x->second.end(), user);\r                                                if (n != x->second.end())\r                                                      /* I'm no longer watching you... */\r                                                    x->second.erase(n);\r    \r                                               if (!x->second.size())\r                                                 whos_watching_me->erase(user->nick);\r                           }\r                      }\r\r                     /* User's quitting, we're done with this. */\r                   delete wl;\r             }\r      }\r\r     virtual void OnGarbageCollect()\r        {\r              watchentries* old_watch = whos_watching_me;\r            whos_watching_me = new watchentries();\r\r                for (watchentries::const_iterator n = old_watch->begin(); n != old_watch->end(); n++)\r                  whos_watching_me->insert(*n);\r\r         delete old_watch;\r      }\r\r     virtual void OnCleanup(int target_type, void* item)\r    {\r              if (target_type == TYPE_USER)\r          {\r                      watchlist* wl;\r                 userrec* user = (userrec*)item;\r\r                       if (user->GetExt("watchlist", wl))\r                     {\r                              user->Shrink("watchlist");\r                             delete wl;\r                     }\r              }\r      }\r\r     virtual void OnPostConnect(userrec* user)\r      {\r              watchentries::iterator x = whos_watching_me->find(user->nick);\r         if (x != whos_watching_me->end())\r              {\r                      for (std::deque<userrec*>::iterator n = x->second.begin(); n != x->second.end(); n++)\r                  {\r                              if (!user->Visibility || user->Visibility->VisibleTo(user))\r                                    (*n)->WriteServ("600 %s %s %s %s %lu :arrived online", (*n)->nick, user->nick, user->ident, user->dhost, user->age);\r\r                          watchlist* wl;\r                         if ((*n)->GetExt("watchlist", wl))\r                                     /* We were on somebody's notify list, set ourselves online */\r                                  (*wl)[user->nick] = std::string(user->ident).append(" ").append(user->dhost).append(" ").append(ConvToStr(user->age));\r                 }\r              }\r      }\r\r     virtual void OnUserPostNick(userrec* user, const std::string &oldnick)\r {\r              watchentries::iterator new_online = whos_watching_me->find(user->nick);\r                watchentries::iterator new_offline = whos_watching_me->find(assign(oldnick));\r\r         if (new_online != whos_watching_me->end())\r             {\r                      for (std::deque<userrec*>::iterator n = new_online->second.begin(); n != new_online->second.end(); n++)\r                        {\r                              watchlist* wl;\r                         if ((*n)->GetExt("watchlist", wl))\r                             {\r                                      (*wl)[user->nick] = std::string(user->ident).append(" ").append(user->dhost).append(" ").append(ConvToStr(user->age));\r                                 if (!user->Visibility || user->Visibility->VisibleTo(user))\r                                            (*n)->WriteServ("600 %s %s %s :arrived online", (*n)->nick, user->nick, (*wl)[user->nick].c_str());\r                            }\r                      }\r              }\r\r             if (new_offline != whos_watching_me->end())\r            {\r                      for (std::deque<userrec*>::iterator n = new_offline->second.begin(); n != new_offline->second.end(); n++)\r                      {\r                              watchlist* wl;\r                         if ((*n)->GetExt("watchlist", wl))\r                             {\r                                      if (!user->Visibility || user->Visibility->VisibleTo(user))\r                                            (*n)->WriteServ("601 %s %s %s %s %lu :went offline", (*n)->nick, oldnick.c_str(), user->ident, user->dhost, user->age);\r                                        (*wl)[oldnick.c_str()] = "";\r                           }\r                      }\r              }\r      }       \r\r      virtual void On005Numeric(std::string &output)\r {\r              // we don't really have a limit...\r             output = output + " WATCH=" + ConvToStr(maxwatch);\r     }\r      \r       virtual ~Modulewatch()\r {\r              delete whos_watching_me;\r       }\r      \r       virtual Version GetVersion()\r   {\r              return Version(1,1,0,1,VF_VENDOR,API_VERSION);\r }\r};\r\rMODULE_INIT(Modulewatch)\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+#include "hashcomp.h"
+
+/* $ModDesc: Provides support for the /WATCH command */
+
+/* This module has been refactored to provide a very efficient (in terms of cpu time)
+ * implementation of /WATCH.
+ *
+ * To improve the efficiency of watch, many lists are kept. The first primary list is
+ * a hash_map of who's being watched by who. For example:
+ *
+ * KEY: Brain   --->  Watched by:  Boo, w00t, Om
+ * KEY: Boo     --->  Watched by:  Brain, w00t
+ * 
+ * This is used when we want to tell all the users that are watching someone that
+ * they are now available or no longer available. For example, if the hash was
+ * populated as shown above, then when Brain signs on, messages are sent to Boo, w00t
+ * and Om by reading their 'watched by' list. When this occurs, their online status
+ * in each of these users lists (see below) is also updated.
+ *
+ * Each user also has a seperate (smaller) map attached to their userrec whilst they
+ * have any watch entries, which is managed by class Extensible. When they add or remove
+ * a watch entry from their list, it is inserted here, as well as the main list being
+ * maintained. This map also contains the user's online status. For users that are
+ * offline, the key points at an empty string, and for users that are online, the key
+ * points at a string containing "users-ident users-host users-signon-time". This is
+ * stored in this manner so that we don't have to FindUser() to fetch this info, the
+ * users signon can populate the field for us.
+ *
+ * For example, going again on the example above, this would be w00t's watchlist:
+ *
+ * KEY: Boo    --->  Status: "Boo brains.sexy.babe 535342348"
+ * KEY: Brain  --->  Status: ""
+ *
+ * In this list we can see that Boo is online, and Brain is offline. We can then
+ * use this list for 'WATCH L', and 'WATCH S' can be implemented as a combination
+ * of the above two data structures, with minimum CPU penalty for doing so.
+ *
+ * In short, the least efficient this ever gets is O(n), and thats only because
+ * there are parts that *must* loop (e.g. telling all users that are watching a
+ * nick that the user online), however this is a *major* improvement over the
+ * 1.0 implementation, which in places had O(n^n) and worse in it, because this
+ * implementation scales based upon the sizes of the watch entries, whereas the
+ * old system would scale (or not as the case may be) according to the total number
+ * of users using WATCH.
+ */
+
+/*
+ * Before you start screaming, this definition is only used here, so moving it to a header is pointless.
+ * Yes, it's horrid. Blame cl for being different. -- w00t
+ */
+#ifdef WINDOWS
+typedef nspace::hash_map<irc::string, std::deque<userrec*>, nspace::hash_compare<irc::string, less<irc::string> > > watchentries;
+#else
+typedef nspace::hash_map<irc::string, std::deque<userrec*>, nspace::hash<irc::string> > watchentries;
+#endif
+typedef std::map<irc::string, std::string> watchlist;
+
+/* Who's watching each nickname.
+ * NOTE: We do NOT iterate this to display a user's WATCH list!
+ * See the comments above!
+ */
+watchentries* whos_watching_me;
+
+/** Handle /WATCH
+ */
+class cmd_watch : public command_t
+{
+       unsigned int& MAX_WATCH;
+ public:
+       CmdResult remove_watch(userrec* user, const char* nick)
+       {
+               // removing an item from the list
+               if (!ServerInstance->IsNick(nick))
+               {
+                       user->WriteServ("942 %s %s :Invalid nickname", user->nick, nick);
+                       return CMD_FAILURE;
+               }
+
+               watchlist* wl;
+               if (user->GetExt("watchlist", wl))
+               {
+                       /* Yup, is on my list */
+                       watchlist::iterator n = wl->find(nick);
+                       if (n != wl->end())
+                       {
+                               if (!n->second.empty())
+                                       user->WriteServ("602 %s %s %s :stopped watching", user->nick, n->first.c_str(), n->second.c_str());
+                               else
+                                       user->WriteServ("602 %s %s * * 0 :stopped watching", user->nick, nick);
+
+                               wl->erase(n);
+                       }
+
+                       if (!wl->size())
+                       {
+                               user->Shrink("watchlist");
+                               delete wl;
+                       }
+
+                       watchentries::iterator x = whos_watching_me->find(nick);
+                       if (x != whos_watching_me->end())
+                       {
+                               /* People are watching this user, am i one of them? */
+                               std::deque<userrec*>::iterator n = std::find(x->second.begin(), x->second.end(), user);
+                               if (n != x->second.end())
+                                       /* I'm no longer watching you... */
+                                       x->second.erase(n);
+
+                               if (!x->second.size())
+                                       whos_watching_me->erase(nick);
+                       }
+               }
+
+               /* This might seem confusing, but we return CMD_FAILURE
+                * to indicate that this message shouldnt be routed across
+                * the network to other linked servers.
+                */
+               return CMD_FAILURE;
+       }
+
+       CmdResult add_watch(userrec* user, const char* nick)
+       {
+               if (!ServerInstance->IsNick(nick))
+               {
+                       user->WriteServ("942 %s %s :Invalid nickname",user->nick,nick);
+                       return CMD_FAILURE;
+               }
+
+               watchlist* wl;
+               if (!user->GetExt("watchlist", wl))
+               {
+                       wl = new watchlist();
+                       user->Extend("watchlist", wl);
+               }
+
+               if (wl->size() == MAX_WATCH)
+               {
+                       user->WriteServ("512 %s %s :Too many WATCH entries", user->nick, nick);
+                       return CMD_FAILURE;
+               }
+
+               watchlist::iterator n = wl->find(nick);
+               if (n == wl->end())
+               {
+                       /* Don't already have the user on my watch list, proceed */
+                       watchentries::iterator x = whos_watching_me->find(nick);
+                       if (x != whos_watching_me->end())
+                       {
+                               /* People are watching this user, add myself */
+                               x->second.push_back(user);
+                       }
+                       else
+                       {
+                               std::deque<userrec*> newlist;
+                               newlist.push_back(user);
+                               (*(whos_watching_me))[nick] = newlist;
+                       }
+
+                       userrec* target = ServerInstance->FindNick(nick);
+                       if (target)
+                       {
+                               if (target->Visibility && !target->Visibility->VisibleTo(user))
+                               {
+                                       (*wl)[nick] = "";
+                                       user->WriteServ("605 %s %s * * 0 :is offline",user->nick, nick);
+                                       return CMD_FAILURE;
+                               }
+
+                               (*wl)[nick] = std::string(target->ident).append(" ").append(target->dhost).append(" ").append(ConvToStr(target->age));
+                               user->WriteServ("604 %s %s %s :is online",user->nick, nick, (*wl)[nick].c_str());
+                       }
+                       else
+                       {
+                               (*wl)[nick] = "";
+                               user->WriteServ("605 %s %s * * 0 :is offline",user->nick, nick);
+                       }
+               }
+
+               return CMD_FAILURE;
+       }
+
+       cmd_watch (InspIRCd* Instance, unsigned int &maxwatch) : command_t(Instance,"WATCH",0,0), MAX_WATCH(maxwatch)
+       {
+               this->source = "m_watch.so";
+               syntax = "[C|L|S]|[+|-<nick>]";
+       }
+
+       CmdResult Handle (const char** parameters, int pcnt, userrec *user)
+       {
+               if (!pcnt)
+               {
+                       watchlist* wl;
+                       if (user->GetExt("watchlist", wl))
+                       {
+                               for (watchlist::iterator q = wl->begin(); q != wl->end(); q++)
+                               {
+                                       if (!q->second.empty())
+                                               user->WriteServ("604 %s %s %s :is online", user->nick, q->first.c_str(), q->second.c_str());
+                               }
+                       }
+                       user->WriteServ("607 %s :End of WATCH list",user->nick);
+               }
+               else if (pcnt > 0)
+               {
+                       for (int x = 0; x < pcnt; x++)
+                       {
+                               const char *nick = parameters[x];
+                               if (!strcasecmp(nick,"C"))
+                               {
+                                       // watch clear
+                                       watchlist* wl;
+                                       if (user->GetExt("watchlist", wl))
+                                       {
+                                               for (watchlist::iterator i = wl->begin(); i != wl->end(); i++)
+                                               {
+                                                       watchentries::iterator x = whos_watching_me->find(i->first);
+                                                       if (x != whos_watching_me->end())
+                                                       {
+                                                               /* People are watching this user, am i one of them? */
+                                                               std::deque<userrec*>::iterator n = std::find(x->second.begin(), x->second.end(), user);
+                                                               if (n != x->second.end())
+                                                                       /* I'm no longer watching you... */
+                                                                       x->second.erase(n);
+
+                                                               if (!x->second.size())
+                                                                       whos_watching_me->erase(user->nick);
+                                                       }
+                                               }
+
+                                               delete wl;
+                                               user->Shrink("watchlist");
+                                       }
+                               }
+                               else if (!strcasecmp(nick,"L"))
+                               {
+                                       watchlist* wl;
+                                       if (user->GetExt("watchlist", wl))
+                                       {
+                                               for (watchlist::iterator q = wl->begin(); q != wl->end(); q++)
+                                               {
+                                                       if (!q->second.empty())
+                                                               user->WriteServ("604 %s %s %s :is online", user->nick, q->first.c_str(), q->second.c_str());
+                                                       else
+                                                               user->WriteServ("605 %s %s * * 0 :is offline", user->nick, q->first.c_str());
+                                               }
+                                       }
+                                       user->WriteServ("607 %s :End of WATCH list",user->nick);
+                               }
+                               else if (!strcasecmp(nick,"S"))
+                               {
+                                       watchlist* wl;
+                                       int you_have = 0;
+                                       int youre_on = 0;
+                                       std::string list;
+
+                                       if (user->GetExt("watchlist", wl))
+                                       {
+                                               for (watchlist::iterator q = wl->begin(); q != wl->end(); q++)
+                                                       list.append(q->first.c_str()).append(" ");
+                                               you_have = wl->size();
+                                       }
+
+                                       watchentries::iterator x = whos_watching_me->find(user->nick);
+                                       if (x != whos_watching_me->end())
+                                               youre_on = x->second.size();
+
+                                       user->WriteServ("603 %s :You have %d and are on %d WATCH entries", user->nick, you_have, youre_on);
+                                       user->WriteServ("606 %s :%s",user->nick, list.c_str());
+                                       user->WriteServ("607 %s :End of WATCH S",user->nick);
+                               }
+                               else if (nick[0] == '-')
+                               {
+                                       nick++;
+                                       remove_watch(user, nick);
+                               }
+                               else if (nick[0] == '+')
+                               {
+                                       nick++;
+                                       add_watch(user, nick);
+                               }
+                       }
+               }
+               /* So that spanningtree doesnt pass the WATCH commands to the network! */
+               return CMD_FAILURE;
+       }
+};
+
+class Modulewatch : public Module
+{
+       cmd_watch* mycommand;
+       unsigned int maxwatch;
+ public:
+
+       Modulewatch(InspIRCd* Me)
+               : Module(Me), maxwatch(32)
+       {
+               OnRehash(NULL, "");
+               whos_watching_me = new watchentries();
+               mycommand = new cmd_watch(ServerInstance, maxwatch);
+               ServerInstance->AddCommand(mycommand);
+       }
+
+       virtual void OnRehash(userrec* user, const std::string &parameter)
+       {
+               ConfigReader Conf(ServerInstance);
+               maxwatch = Conf.ReadInteger("watch", "maxentries", 0, true);
+               if (!maxwatch)
+                       maxwatch = 32;
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnRehash] = List[I_OnGarbageCollect] = List[I_OnCleanup] = List[I_OnUserQuit] = List[I_OnPostConnect] = List[I_OnUserPostNick] = List[I_On005Numeric] = 1;
+       }
+
+       virtual void OnUserQuit(userrec* user, const std::string &reason, const std::string &oper_message)
+       {
+               watchentries::iterator x = whos_watching_me->find(user->nick);
+               if (x != whos_watching_me->end())
+               {
+                       for (std::deque<userrec*>::iterator n = x->second.begin(); n != x->second.end(); n++)
+                       {
+                               if (!user->Visibility || user->Visibility->VisibleTo(user))
+                                       (*n)->WriteServ("601 %s %s %s %s %lu :went offline", (*n)->nick ,user->nick, user->ident, user->dhost, ServerInstance->Time());
+
+                               watchlist* wl;
+                               if ((*n)->GetExt("watchlist", wl))
+                                       /* We were on somebody's notify list, set ourselves offline */
+                                       (*wl)[user->nick] = "";
+                       }
+               }
+
+               /* Now im quitting, if i have a notify list, im no longer watching anyone */
+               watchlist* wl;
+               if (user->GetExt("watchlist", wl))
+               {
+                       /* Iterate every user on my watch list, and take me out of the whos_watching_me map for each one we're watching */
+                       for (watchlist::iterator i = wl->begin(); i != wl->end(); i++)
+                       {
+                               watchentries::iterator x = whos_watching_me->find(i->first);
+                               if (x != whos_watching_me->end())
+                               {
+                                               /* People are watching this user, am i one of them? */
+                                               std::deque<userrec*>::iterator n = std::find(x->second.begin(), x->second.end(), user);
+                                               if (n != x->second.end())
+                                                       /* I'm no longer watching you... */
+                                                       x->second.erase(n);
+       
+                                               if (!x->second.size())
+                                                       whos_watching_me->erase(user->nick);
+                               }
+                       }
+
+                       /* User's quitting, we're done with this. */
+                       delete wl;
+               }
+       }
+
+       virtual void OnGarbageCollect()
+       {
+               watchentries* old_watch = whos_watching_me;
+               whos_watching_me = new watchentries();
+
+               for (watchentries::const_iterator n = old_watch->begin(); n != old_watch->end(); n++)
+                       whos_watching_me->insert(*n);
+
+               delete old_watch;
+       }
+
+       virtual void OnCleanup(int target_type, void* item)
+       {
+               if (target_type == TYPE_USER)
+               {
+                       watchlist* wl;
+                       userrec* user = (userrec*)item;
+
+                       if (user->GetExt("watchlist", wl))
+                       {
+                               user->Shrink("watchlist");
+                               delete wl;
+                       }
+               }
+       }
+
+       virtual void OnPostConnect(userrec* user)
+       {
+               watchentries::iterator x = whos_watching_me->find(user->nick);
+               if (x != whos_watching_me->end())
+               {
+                       for (std::deque<userrec*>::iterator n = x->second.begin(); n != x->second.end(); n++)
+                       {
+                               if (!user->Visibility || user->Visibility->VisibleTo(user))
+                                       (*n)->WriteServ("600 %s %s %s %s %lu :arrived online", (*n)->nick, user->nick, user->ident, user->dhost, user->age);
+
+                               watchlist* wl;
+                               if ((*n)->GetExt("watchlist", wl))
+                                       /* We were on somebody's notify list, set ourselves online */
+                                       (*wl)[user->nick] = std::string(user->ident).append(" ").append(user->dhost).append(" ").append(ConvToStr(user->age));
+                       }
+               }
+       }
+
+       virtual void OnUserPostNick(userrec* user, const std::string &oldnick)
+       {
+               watchentries::iterator new_online = whos_watching_me->find(user->nick);
+               watchentries::iterator new_offline = whos_watching_me->find(assign(oldnick));
+
+               if (new_online != whos_watching_me->end())
+               {
+                       for (std::deque<userrec*>::iterator n = new_online->second.begin(); n != new_online->second.end(); n++)
+                       {
+                               watchlist* wl;
+                               if ((*n)->GetExt("watchlist", wl))
+                               {
+                                       (*wl)[user->nick] = std::string(user->ident).append(" ").append(user->dhost).append(" ").append(ConvToStr(user->age));
+                                       if (!user->Visibility || user->Visibility->VisibleTo(user))
+                                               (*n)->WriteServ("600 %s %s %s :arrived online", (*n)->nick, user->nick, (*wl)[user->nick].c_str());
+                               }
+                       }
+               }
+
+               if (new_offline != whos_watching_me->end())
+               {
+                       for (std::deque<userrec*>::iterator n = new_offline->second.begin(); n != new_offline->second.end(); n++)
+                       {
+                               watchlist* wl;
+                               if ((*n)->GetExt("watchlist", wl))
+                               {
+                                       if (!user->Visibility || user->Visibility->VisibleTo(user))
+                                               (*n)->WriteServ("601 %s %s %s %s %lu :went offline", (*n)->nick, oldnick.c_str(), user->ident, user->dhost, user->age);
+                                       (*wl)[oldnick.c_str()] = "";
+                               }
+                       }
+               }
+       }       
+
+       virtual void On005Numeric(std::string &output)
+       {
+               // we don't really have a limit...
+               output = output + " WATCH=" + ConvToStr(maxwatch);
+       }
+       
+       virtual ~Modulewatch()
+       {
+               delete whos_watching_me;
+       }
+       
+       virtual Version GetVersion()
+       {
+               return Version(1,1,0,1,VF_VENDOR,API_VERSION);
+       }
+};
+
+MODULE_INIT(Modulewatch)
+
index 12da3762ef01527edaf175eb75c1afa1d4c2a53f..7f37f66c91dcb1a75366c79463bb825da517d470 100644 (file)
@@ -1 +1,170 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r#include "hashcomp.h"\r\r/* $ModDesc: Provides XMLSocket support for clients */\r\rclass ModuleXMLSocket : public Module\r{\r        ConfigReader* Conf;\r    std::vector<int> listenports;\r\r public:\r\r       ModuleXMLSocket(InspIRCd* Me)\r          : Module(Me)\r   {\r              OnRehash(NULL,"");\r     }\r\r     virtual void OnRehash(userrec* user, const std::string &param)\r {\r\r             Conf = new ConfigReader(ServerInstance);\r\r              for (unsigned int i = 0; i < listenports.size(); i++)\r          {\r                      ServerInstance->Config->DelIOHook(listenports[i]);\r             }\r\r             listenports.clear();\r\r          for (int i = 0; i < Conf->Enumerate("bind"); i++)\r              {\r                      // For each <bind> tag\r                 std::string x = Conf->ReadValue("bind", "type", i);\r                    if (((x.empty()) || (x == "clients")) && (Conf->ReadFlag("bind", "xmlsocket", i)))\r                     {\r                              // Get the port we're meant to be listening on with SSL\r                                std::string port = Conf->ReadValue("bind", "port", i);\r                         irc::portparser portrange(port, false);\r                                long portno = -1;\r                              while ((portno = portrange.GetToken()))\r                                {\r                                      try\r                                    {\r                                              if (ServerInstance->Config->AddIOHook(portno, this))\r                                           {\r                                                      listenports.push_back(portno);\r                                                         for (size_t i = 0; i < ServerInstance->Config->ports.size(); i++)\r                                                              if (ServerInstance->Config->ports[i]->GetPort() == portno)\r                                                                     ServerInstance->Config->ports[i]->SetDescription("xml");\r                                               }\r                                              else\r                                           {\r                                                      ServerInstance->Log(DEFAULT, "m_xmlsocket.so: FAILED to enable XMLSocket on port %d, maybe you have another similar module loaded?", portno);\r                                          }\r                                      }\r                                      catch (ModuleException &e)\r                                     {\r                                              ServerInstance->Log(DEFAULT, "m_xmlsocket.so: FAILED to enable XMLSocket on port %d: %s. Maybe it's already hooked by the same port on a different IP, or you have another similar module loaded?", portno, e.GetReason());\r                                    }\r                              }\r                      }\r              }\r\r             DELETE(Conf);\r  }\r\r     virtual ~ModuleXMLSocket()\r     {\r      }\r\r     virtual void OnUnloadModule(Module* mod, const std::string &name)\r      {\r              if (mod == this)\r               {\r                      for(unsigned int i = 0; i < listenports.size(); i++)\r                   {\r                              ServerInstance->Config->DelIOHook(listenports[i]);\r                             for (size_t j = 0; j < ServerInstance->Config->ports.size(); j++)\r                                      if (ServerInstance->Config->ports[j]->GetPort() == listenports[i])\r                                             ServerInstance->Config->ports[j]->SetDescription("plaintext");\r                 }\r              }\r      }\r\r     virtual Version GetVersion()\r   {\r              return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION);\r    }\r\r     void Implements(char* List)\r    {\r              List[I_OnUnloadModule] = List[I_OnRawSocketRead] = List[I_OnRawSocketWrite] = List[I_OnRehash] = 1;\r    }\r\r     virtual int OnRawSocketRead(int fd, char* buffer, unsigned int count, int &readresult)\r {\r              userrec* user = dynamic_cast<userrec*>(ServerInstance->FindDescriptor(fd));\r\r           if (user == NULL)\r                      return -1;\r\r            int result = user->ReadData(buffer, count);\r\r           if ((result == -1) && (errno == EAGAIN))\r                       return -1;\r             else if (result < 1)\r                   return 0;\r\r             /* XXX: The core is more than happy to split lines purely on an \n\r              * rather than a \r\n. This is good for us as it means that the size\r            * of data we are receiving is exactly the same as the size of data\r             * we asked for, and we dont need to re-implement our own socket\r                * buffering (See below)\r                */\r            for (int n = 0; n < result; n++)\r                       if (buffer[n] == 0)\r                            buffer[n] = '\n';\r\r             readresult = result;\r           return result;\r }\r\r     virtual int OnRawSocketWrite(int fd, const char* buffer, int count)\r    {\r              userrec* user = dynamic_cast<userrec*>(ServerInstance->FindDescriptor(fd));\r\r           if (user == NULL)\r                      return -1;\r\r            /* We want to alter the buffer, so we have to make a copy */\r           char * tmpbuffer = new char[count + 1];\r                memcpy(tmpbuffer, buffer, count);\r\r             /* XXX: This will actually generate lines "looking\0\0like\0\0this"\r             * rather than lines "looking\0like\0this". This shouldnt be a problem\r          * to the client, but it saves us a TON of processing and the need\r              * to re-implement socket buffering, as the data we are sending is\r              * exactly the same length as the data we are receiving.\r                */\r            for (int n = 0; n < count; n++)\r                        if ((tmpbuffer[n] == '\r') || (tmpbuffer[n] == '\n'))\r                          tmpbuffer[n] = 0;\r\r             user->AddWriteBuf(std::string(tmpbuffer,count));\r               delete [] tmpbuffer;\r\r          return 1;\r      }\r\r};\r\rMODULE_INIT(ModuleXMLSocket)\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+#include "hashcomp.h"
+
+/* $ModDesc: Provides XMLSocket support for clients */
+
+class ModuleXMLSocket : public Module
+{
+       ConfigReader* Conf;
+       std::vector<int> listenports;
+
+ public:
+
+       ModuleXMLSocket(InspIRCd* Me)
+               : Module(Me)
+       {
+               OnRehash(NULL,"");
+       }
+
+       virtual void OnRehash(userrec* user, const std::string &param)
+       {
+
+               Conf = new ConfigReader(ServerInstance);
+
+               for (unsigned int i = 0; i < listenports.size(); i++)
+               {
+                       ServerInstance->Config->DelIOHook(listenports[i]);
+               }
+
+               listenports.clear();
+
+               for (int i = 0; i < Conf->Enumerate("bind"); i++)
+               {
+                       // For each <bind> tag
+                       std::string x = Conf->ReadValue("bind", "type", i);
+                       if (((x.empty()) || (x == "clients")) && (Conf->ReadFlag("bind", "xmlsocket", i)))
+                       {
+                               // Get the port we're meant to be listening on with SSL
+                               std::string port = Conf->ReadValue("bind", "port", i);
+                               irc::portparser portrange(port, false);
+                               long portno = -1;
+                               while ((portno = portrange.GetToken()))
+                               {
+                                       try
+                                       {
+                                               if (ServerInstance->Config->AddIOHook(portno, this))
+                                               {
+                                                       listenports.push_back(portno);
+                                                               for (size_t i = 0; i < ServerInstance->Config->ports.size(); i++)
+                                                               if (ServerInstance->Config->ports[i]->GetPort() == portno)
+                                                                       ServerInstance->Config->ports[i]->SetDescription("xml");
+                                               }
+                                               else
+                                               {
+                                                       ServerInstance->Log(DEFAULT, "m_xmlsocket.so: FAILED to enable XMLSocket on port %d, maybe you have another similar module loaded?", portno);
+                                               }
+                                       }
+                                       catch (ModuleException &e)
+                                       {
+                                               ServerInstance->Log(DEFAULT, "m_xmlsocket.so: FAILED to enable XMLSocket on port %d: %s. Maybe it's already hooked by the same port on a different IP, or you have another similar module loaded?", portno, e.GetReason());
+                                       }
+                               }
+                       }
+               }
+
+               DELETE(Conf);
+       }
+
+       virtual ~ModuleXMLSocket()
+       {
+       }
+
+       virtual void OnUnloadModule(Module* mod, const std::string &name)
+       {
+               if (mod == this)
+               {
+                       for(unsigned int i = 0; i < listenports.size(); i++)
+                       {
+                               ServerInstance->Config->DelIOHook(listenports[i]);
+                               for (size_t j = 0; j < ServerInstance->Config->ports.size(); j++)
+                                       if (ServerInstance->Config->ports[j]->GetPort() == listenports[i])
+                                               ServerInstance->Config->ports[j]->SetDescription("plaintext");
+                       }
+               }
+       }
+
+       virtual Version GetVersion()
+       {
+               return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION);
+       }
+
+       void Implements(char* List)
+       {
+               List[I_OnUnloadModule] = List[I_OnRawSocketRead] = List[I_OnRawSocketWrite] = List[I_OnRehash] = 1;
+       }
+
+       virtual int OnRawSocketRead(int fd, char* buffer, unsigned int count, int &readresult)
+       {
+               userrec* user = dynamic_cast<userrec*>(ServerInstance->FindDescriptor(fd));
+
+               if (user == NULL)
+                       return -1;
+
+               int result = user->ReadData(buffer, count);
+
+               if ((result == -1) && (errno == EAGAIN))
+                       return -1;
+               else if (result < 1)
+                       return 0;
+
+               /* XXX: The core is more than happy to split lines purely on an \n
+                * rather than a \r\n. This is good for us as it means that the size
+                * of data we are receiving is exactly the same as the size of data
+                * we asked for, and we dont need to re-implement our own socket
+                * buffering (See below)
+                */
+               for (int n = 0; n < result; n++)
+                       if (buffer[n] == 0)
+                               buffer[n] = '\n';
+
+               readresult = result;
+               return result;
+       }
+
+       virtual int OnRawSocketWrite(int fd, const char* buffer, int count)
+       {
+               userrec* user = dynamic_cast<userrec*>(ServerInstance->FindDescriptor(fd));
+
+               if (user == NULL)
+                       return -1;
+
+               /* We want to alter the buffer, so we have to make a copy */
+               char * tmpbuffer = new char[count + 1];
+               memcpy(tmpbuffer, buffer, count);
+
+               /* XXX: This will actually generate lines "looking\0\0like\0\0this"
+                * rather than lines "looking\0like\0this". This shouldnt be a problem
+                * to the client, but it saves us a TON of processing and the need
+                * to re-implement socket buffering, as the data we are sending is
+                * exactly the same length as the data we are receiving.
+                */
+               for (int n = 0; n < count; n++)
+                       if ((tmpbuffer[n] == '\r') || (tmpbuffer[n] == '\n'))
+                               tmpbuffer[n] = 0;
+
+               user->AddWriteBuf(std::string(tmpbuffer,count));
+               delete [] tmpbuffer;
+
+               return 1;
+       }
+
+};
+
+MODULE_INIT(ModuleXMLSocket)
+
index d92cf0376901d2df96e9d935b3cbc47fe8d5bd7c..ba8e3973be88048cc95fd376e0b37539a7c4b943 100644 (file)
@@ -1 +1,231 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __TRANSPORT_H__\r#define __TRANSPORT_H__\r\r#include <map>\r#include <string>\r\r/** A generic container for certificate data\r */\rtypedef std::map<std::string,std::string> ssl_data;\r\r/** A shorthand way of representing an iterator into ssl_data\r */\rtypedef ssl_data::iterator ssl_data_iter;\r\r/** ssl_cert is a class which abstracts SSL certificate\r * and key information.\r *\r * Because gnutls and openssl represent key information in\r * wildly different ways, this class allows it to be accessed\r * in a unified manner. These classes are attached to ssl-\r * connected local users using Extensible::Extend() and the\r * key 'ssl_cert'.\r */\rclass ssl_cert\r{\r  /** Always contains an empty string\r     */\r    const std::string empty;\r\r public:\r     /** The data for this certificate\r       */\r    ssl_data data;\r\r        /** Default constructor, initializes 'empty'\r    */\r    ssl_cert() : empty("")\r {\r      }\r      \r       /** Get certificate distinguished name\r  * @return Certificate DN\r       */\r    const std::string& GetDN()\r     {\r              ssl_data_iter ssldi = data.find("dn");\r\r                if (ssldi != data.end())\r                       return ssldi->second;\r          else\r                   return empty;\r  }\r\r     /** Get Certificate issuer\r      * @return Certificate issuer\r   */\r    const std::string& GetIssuer()\r {\r              ssl_data_iter ssldi = data.find("issuer");\r\r            if (ssldi != data.end())\r                       return ssldi->second;\r          else\r                   return empty;\r  }\r\r     /** Get error string if an error has occured\r    * @return The error associated with this users certificate,\r    * or an empty string if there is no error.\r     */\r    const std::string& GetError()\r  {\r              ssl_data_iter ssldi = data.find("error");\r\r             if (ssldi != data.end())\r                       return ssldi->second;\r          else\r                   return empty;\r  }\r\r     /** Get key fingerprint.\r        * @return The key fingerprint as a hex string.\r         */\r    const std::string& GetFingerprint()\r    {\r              ssl_data_iter ssldi = data.find("fingerprint");\r\r               if (ssldi != data.end())\r                       return ssldi->second;\r          else\r                   return empty;\r  }\r\r     /** Get trust status\r    * @return True if this is a trusted certificate\r        * (the certificate chain validates)\r    */\r    bool IsTrusted()\r       {\r              ssl_data_iter ssldi = data.find("trusted");\r\r           if (ssldi != data.end())\r                       return (ssldi->second == "1");\r         else\r                   return false;\r  }\r\r     /** Get validity status\r         * @return True if the certificate itself is\r    * correctly formed.\r    */\r    bool IsInvalid()\r       {\r              ssl_data_iter ssldi = data.find("invalid");\r\r           if (ssldi != data.end())\r                       return (ssldi->second == "1");\r         else\r                   return false;\r  }\r\r     /** Get signer status\r   * @return True if the certificate appears to be\r        * self-signed.\r         */\r    bool IsUnknownSigner()\r {\r              ssl_data_iter ssldi = data.find("unknownsigner");\r\r             if (ssldi != data.end())\r                       return (ssldi->second == "1");\r         else\r                   return false;\r  }\r\r     /** Get revokation status.\r      * @return True if the certificate is revoked.\r  * Note that this only works properly for GnuTLS\r        * right now.\r   */\r    bool IsRevoked()\r       {\r              ssl_data_iter ssldi = data.find("revoked");\r\r           if (ssldi != data.end())\r                       return (ssldi->second == "1");\r         else\r                   return false;\r  }\r};\r\r/** Used to represent a request to a transport provider module\r */\rclass ISHRequest : public Request\r{\r public:\r  InspSocket* Sock;\r\r     ISHRequest(Module* Me, Module* Target, const char* rtype, InspSocket* sock) : Request(Me, Target, rtype), Sock(sock)\r   {\r      }\r};\r\r/** Used to represent a request to attach a cert to an InspSocket\r */\rclass InspSocketAttachCertRequest : public ISHRequest\r{\r public:\r   /** Initialize the request as an attach cert message */\r        InspSocketAttachCertRequest(InspSocket* is, Module* Me, Module* Target) : ISHRequest(Me, Target, "IS_ATTACH", is)\r      {\r      }\r};\r\r/** Used to check if a handshake is complete on an InspSocket yet\r */\rclass InspSocketHSCompleteRequest : public ISHRequest\r{\r public:\r   /** Initialize the request as a 'handshake complete?' message */\r       InspSocketHSCompleteRequest(InspSocket* is, Module* Me, Module* Target) : ISHRequest(Me, Target, "IS_HSDONE", is)\r      {\r      }\r};\r\r/** Used to hook a transport provider to an InspSocket\r */\rclass InspSocketHookRequest : public ISHRequest\r{\r public:\r    /** Initialize request as a hook message */\r    InspSocketHookRequest(InspSocket* is, Module* Me, Module* Target) : ISHRequest(Me, Target, "IS_HOOK", is)\r      {\r      }\r};\r\r/** Used to unhook a transport provider from an InspSocket\r */\rclass InspSocketUnhookRequest : public ISHRequest\r{\r public:\r      /** Initialize request as an unhook message */\r InspSocketUnhookRequest(InspSocket* is, Module* Me, Module* Target) : ISHRequest(Me, Target, "IS_UNHOOK", is)\r  {\r      }\r};\r\rclass InspSocketNameRequest : public ISHRequest\r{\r public:\r       /** Initialize request as a get name message */\r        InspSocketNameRequest(Module* Me, Module* Target) : ISHRequest(Me, Target, "IS_NAME", NULL)\r    {\r      }\r};\r\r#endif\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __TRANSPORT_H__
+#define __TRANSPORT_H__
+
+#include <map>
+#include <string>
+
+/** A generic container for certificate data
+ */
+typedef std::map<std::string,std::string> ssl_data;
+
+/** A shorthand way of representing an iterator into ssl_data
+ */
+typedef ssl_data::iterator ssl_data_iter;
+
+/** ssl_cert is a class which abstracts SSL certificate
+ * and key information.
+ *
+ * Because gnutls and openssl represent key information in
+ * wildly different ways, this class allows it to be accessed
+ * in a unified manner. These classes are attached to ssl-
+ * connected local users using Extensible::Extend() and the
+ * key 'ssl_cert'.
+ */
+class ssl_cert
+{
+       /** Always contains an empty string
+        */
+       const std::string empty;
+
+ public:
+       /** The data for this certificate
+        */
+       ssl_data data;
+
+       /** Default constructor, initializes 'empty'
+        */
+       ssl_cert() : empty("")
+       {
+       }
+       
+       /** Get certificate distinguished name
+        * @return Certificate DN
+        */
+       const std::string& GetDN()
+       {
+               ssl_data_iter ssldi = data.find("dn");
+
+               if (ssldi != data.end())
+                       return ssldi->second;
+               else
+                       return empty;
+       }
+
+       /** Get Certificate issuer
+        * @return Certificate issuer
+        */
+       const std::string& GetIssuer()
+       {
+               ssl_data_iter ssldi = data.find("issuer");
+
+               if (ssldi != data.end())
+                       return ssldi->second;
+               else
+                       return empty;
+       }
+
+       /** Get error string if an error has occured
+        * @return The error associated with this users certificate,
+        * or an empty string if there is no error.
+        */
+       const std::string& GetError()
+       {
+               ssl_data_iter ssldi = data.find("error");
+
+               if (ssldi != data.end())
+                       return ssldi->second;
+               else
+                       return empty;
+       }
+
+       /** Get key fingerprint.
+        * @return The key fingerprint as a hex string.
+        */
+       const std::string& GetFingerprint()
+       {
+               ssl_data_iter ssldi = data.find("fingerprint");
+
+               if (ssldi != data.end())
+                       return ssldi->second;
+               else
+                       return empty;
+       }
+
+       /** Get trust status
+        * @return True if this is a trusted certificate
+        * (the certificate chain validates)
+        */
+       bool IsTrusted()
+       {
+               ssl_data_iter ssldi = data.find("trusted");
+
+               if (ssldi != data.end())
+                       return (ssldi->second == "1");
+               else
+                       return false;
+       }
+
+       /** Get validity status
+        * @return True if the certificate itself is
+        * correctly formed.
+        */
+       bool IsInvalid()
+       {
+               ssl_data_iter ssldi = data.find("invalid");
+
+               if (ssldi != data.end())
+                       return (ssldi->second == "1");
+               else
+                       return false;
+       }
+
+       /** Get signer status
+        * @return True if the certificate appears to be
+        * self-signed.
+        */
+       bool IsUnknownSigner()
+       {
+               ssl_data_iter ssldi = data.find("unknownsigner");
+
+               if (ssldi != data.end())
+                       return (ssldi->second == "1");
+               else
+                       return false;
+       }
+
+       /** Get revokation status.
+        * @return True if the certificate is revoked.
+        * Note that this only works properly for GnuTLS
+        * right now.
+        */
+       bool IsRevoked()
+       {
+               ssl_data_iter ssldi = data.find("revoked");
+
+               if (ssldi != data.end())
+                       return (ssldi->second == "1");
+               else
+                       return false;
+       }
+};
+
+/** Used to represent a request to a transport provider module
+ */
+class ISHRequest : public Request
+{
+ public:
+       InspSocket* Sock;
+
+       ISHRequest(Module* Me, Module* Target, const char* rtype, InspSocket* sock) : Request(Me, Target, rtype), Sock(sock)
+       {
+       }
+};
+
+/** Used to represent a request to attach a cert to an InspSocket
+ */
+class InspSocketAttachCertRequest : public ISHRequest
+{
+ public:
+       /** Initialize the request as an attach cert message */
+       InspSocketAttachCertRequest(InspSocket* is, Module* Me, Module* Target) : ISHRequest(Me, Target, "IS_ATTACH", is)
+       {
+       }
+};
+
+/** Used to check if a handshake is complete on an InspSocket yet
+ */
+class InspSocketHSCompleteRequest : public ISHRequest
+{
+ public:
+       /** Initialize the request as a 'handshake complete?' message */
+       InspSocketHSCompleteRequest(InspSocket* is, Module* Me, Module* Target) : ISHRequest(Me, Target, "IS_HSDONE", is)
+       {
+       }
+};
+
+/** Used to hook a transport provider to an InspSocket
+ */
+class InspSocketHookRequest : public ISHRequest
+{
+ public:
+       /** Initialize request as a hook message */
+       InspSocketHookRequest(InspSocket* is, Module* Me, Module* Target) : ISHRequest(Me, Target, "IS_HOOK", is)
+       {
+       }
+};
+
+/** Used to unhook a transport provider from an InspSocket
+ */
+class InspSocketUnhookRequest : public ISHRequest
+{
+ public:
+       /** Initialize request as an unhook message */
+       InspSocketUnhookRequest(InspSocket* is, Module* Me, Module* Target) : ISHRequest(Me, Target, "IS_UNHOOK", is)
+       {
+       }
+};
+
+class InspSocketNameRequest : public ISHRequest
+{
+ public:
+       /** Initialize request as a get name message */
+       InspSocketNameRequest(Module* Me, Module* Target) : ISHRequest(Me, Target, "IS_NAME", NULL)
+       {
+       }
+};
+
+#endif
+
index 05571ce590933afa5aeec6d7ba91e55606c572f1..ba6d3d7d53148b7d9b70760324bfc1d819dc273b 100644 (file)
@@ -1 +1,102 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include <stdarg.h>\r#include "configreader.h"\r#include "users.h"\r#include "snomasks.h"\r\rSnomaskManager::SnomaskManager(InspIRCd* Instance) : ServerInstance(Instance)\r{\r     SnoMasks.clear();\r      this->SetupDefaults();\r}\r\rSnomaskManager::~SnomaskManager()\r{\r}\r\rbool SnomaskManager::EnableSnomask(char letter, const std::string &type)\r{\r    if (SnoMasks.find(letter) == SnoMasks.end())\r   {\r              SnoMasks[letter] = type;\r               return true;\r   }\r      return false;\r}\r\rbool SnomaskManager::DisableSnomask(char letter)\r{\r    SnoList::iterator n = SnoMasks.find(letter);\r   if (n != SnoMasks.end())\r       {\r              SnoMasks.erase(n);\r             return true;\r   }\r      return false;\r}\r\rvoid SnomaskManager::WriteToSnoMask(char letter, const std::string &text)\r{\r   /* Only send to snomask chars which are enabled */\r     SnoList::iterator n = SnoMasks.find(letter);\r   if (n != SnoMasks.end())\r       {\r              /* Only opers can receive snotices, so we iterate the oper list */\r             for (std::vector<userrec*>::iterator i = ServerInstance->all_opers.begin(); i != ServerInstance->all_opers.end(); i++)\r         {\r                      userrec* a = *i;\r                       if (IS_LOCAL(a) && a->modes[UM_SERVERNOTICE] && a->modes[UM_SNOMASK] && a->IsNoticeMaskSet(n->first))\r                  {\r                              /* send server notices to all with +ns */\r                              a->WriteServ("NOTICE %s :*** %s: %s",a->nick, n->second.c_str(), text.c_str());\r                        }\r              }\r      }\r}\r\rvoid SnomaskManager::WriteToSnoMask(char letter, const char* text, ...)\r{\r char textbuffer[MAXBUF];\r       va_list argsPtr;\r\r      va_start(argsPtr, text);\r       vsnprintf(textbuffer, MAXBUF, text, argsPtr);\r  va_end(argsPtr);\r\r      this->WriteToSnoMask(letter, std::string(textbuffer));\r}\r\rbool SnomaskManager::IsEnabled(char letter)\r{\r        return (SnoMasks.find(letter) != SnoMasks.end());\r}\r\rvoid SnomaskManager::SetupDefaults()\r{\r    this->EnableSnomask('c',"CONNECT");                     /* Local connect notices */\r    this->EnableSnomask('C',"REMOTECONNECT");       /* Remote connect notices */\r   this->EnableSnomask('q',"QUIT");                        /* Local quit notices */\r       this->EnableSnomask('Q',"REMOTEQUIT");          /* Remote quit notices */\r      this->EnableSnomask('k',"KILL");                        /* Kill notices */\r     this->EnableSnomask('K',"REMOTEKILL");          /* Remote kill notices */\r      this->EnableSnomask('l',"LINK");                        /* Link notices */\r     this->EnableSnomask('o',"OPER");                        /* Oper up/down notices */\r     this->EnableSnomask('d',"DEBUG");                       /* Debug notices */\r    this->EnableSnomask('x',"XLINE");                       /* Xline notice (g/z/q/k/e) */\r this->EnableSnomask('t',"STATS");                       /* Local or remote stats request */\r    this->EnableSnomask('f',"FLOOD");                       /* Flooding notices */\r}\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include <stdarg.h>
+#include "configreader.h"
+#include "users.h"
+#include "snomasks.h"
+
+SnomaskManager::SnomaskManager(InspIRCd* Instance) : ServerInstance(Instance)
+{
+       SnoMasks.clear();
+       this->SetupDefaults();
+}
+
+SnomaskManager::~SnomaskManager()
+{
+}
+
+bool SnomaskManager::EnableSnomask(char letter, const std::string &type)
+{
+       if (SnoMasks.find(letter) == SnoMasks.end())
+       {
+               SnoMasks[letter] = type;
+               return true;
+       }
+       return false;
+}
+
+bool SnomaskManager::DisableSnomask(char letter)
+{
+       SnoList::iterator n = SnoMasks.find(letter);
+       if (n != SnoMasks.end())
+       {
+               SnoMasks.erase(n);
+               return true;
+       }
+       return false;
+}
+
+void SnomaskManager::WriteToSnoMask(char letter, const std::string &text)
+{
+       /* Only send to snomask chars which are enabled */
+       SnoList::iterator n = SnoMasks.find(letter);
+       if (n != SnoMasks.end())
+       {
+               /* Only opers can receive snotices, so we iterate the oper list */
+               for (std::vector<userrec*>::iterator i = ServerInstance->all_opers.begin(); i != ServerInstance->all_opers.end(); i++)
+               {
+                       userrec* a = *i;
+                       if (IS_LOCAL(a) && a->modes[UM_SERVERNOTICE] && a->modes[UM_SNOMASK] && a->IsNoticeMaskSet(n->first))
+                       {
+                               /* send server notices to all with +ns */
+                               a->WriteServ("NOTICE %s :*** %s: %s",a->nick, n->second.c_str(), text.c_str());
+                       }
+               }
+       }
+}
+
+void SnomaskManager::WriteToSnoMask(char letter, const char* text, ...)
+{
+       char textbuffer[MAXBUF];
+       va_list argsPtr;
+
+       va_start(argsPtr, text);
+       vsnprintf(textbuffer, MAXBUF, text, argsPtr);
+       va_end(argsPtr);
+
+       this->WriteToSnoMask(letter, std::string(textbuffer));
+}
+
+bool SnomaskManager::IsEnabled(char letter)
+{
+       return (SnoMasks.find(letter) != SnoMasks.end());
+}
+
+void SnomaskManager::SetupDefaults()
+{
+       this->EnableSnomask('c',"CONNECT");                     /* Local connect notices */
+       this->EnableSnomask('C',"REMOTECONNECT");       /* Remote connect notices */
+       this->EnableSnomask('q',"QUIT");                        /* Local quit notices */
+       this->EnableSnomask('Q',"REMOTEQUIT");          /* Remote quit notices */
+       this->EnableSnomask('k',"KILL");                        /* Kill notices */
+       this->EnableSnomask('K',"REMOTEKILL");          /* Remote kill notices */
+       this->EnableSnomask('l',"LINK");                        /* Link notices */
+       this->EnableSnomask('o',"OPER");                        /* Oper up/down notices */
+       this->EnableSnomask('d',"DEBUG");                       /* Debug notices */
+       this->EnableSnomask('x',"XLINE");                       /* Xline notice (g/z/q/k/e) */
+       this->EnableSnomask('t',"STATS");                       /* Local or remote stats request */
+       this->EnableSnomask('f',"FLOOD");                       /* Flooding notices */
+}
+
index d400a03230eff1a731fefadc77e5b69cd2738c28..31fbffb617cfe5fa99dcae6907d7a63fbba408b6 100644 (file)
@@ -1 +1,568 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include <string>\r#include "configreader.h"\r#include "socket.h"\r#include "socketengine.h"\r#include "wildcard.h"\r\rusing namespace irc::sockets;\r\r/* Used when comparing CIDR masks for the modulus bits left over.\r * A lot of ircd's seem to do this:\r * ((-1) << (8 - (mask % 8)))\r * But imho, it sucks in comparison to a nice neat lookup table.\r */\rconst unsigned char inverted_bits[8] = {    0x00, /* 00000000 - 0 bits - never actually used */\r                            0x80, /* 10000000 - 1 bits */\r                          0xC0, /* 11000000 - 2 bits */\r                          0xE0, /* 11100000 - 3 bits */\r                          0xF0, /* 11110000 - 4 bits */\r                          0xF8, /* 11111000 - 5 bits */\r                          0xFC, /* 11111100 - 6 bits */\r                          0xFE  /* 11111110 - 7 bits */\r};\r\r\rListenSocket::ListenSocket(InspIRCd* Instance, int port, char* addr) : ServerInstance(Instance), desc("plaintext"), bind_addr(addr), bind_port(port)\r{\r      this->SetFd(OpenTCPSocket(addr));\r      if (this->GetFd() > -1)\r        {\r              if (!Instance->BindSocket(this->fd,port,addr))\r                 this->fd = -1;\r#ifdef IPV6\r             if ((!*addr) || (strchr(addr,':')))\r                    this->family = AF_INET6;\r               else\r#endif\r            this->family = AF_INET;\r                Instance->SE->AddFd(this);\r     }\r}\r\rListenSocket::~ListenSocket()\r{\r   if (this->GetFd() > -1)\r        {\r              ServerInstance->SE->DelFd(this);\r               ServerInstance->Log(DEBUG,"Shut down listener on fd %d", this->fd);\r            if (shutdown(this->fd, 2) || close(this->fd))\r                  ServerInstance->Log(DEBUG,"Failed to cancel listener: %s", strerror(errno));\r           this->fd = -1;\r }\r}\r\rvoid ListenSocket::HandleEvent(EventType et, int errornum)\r{\r      sockaddr* sock_us = new sockaddr[2];    // our port number\r     sockaddr* client = new sockaddr[2];\r    socklen_t uslen, length;                // length of our port number\r   int incomingSockfd, in_port;\r\r#ifdef IPV6\r      if (this->family == AF_INET6)\r  {\r              uslen = sizeof(sockaddr_in6);\r          length = sizeof(sockaddr_in6);\r }\r      else\r#endif\r    {\r              uslen = sizeof(sockaddr_in);\r           length = sizeof(sockaddr_in);\r  }\r\r     incomingSockfd = _accept (this->GetFd(), (sockaddr*)client, &length);\r\r if ((incomingSockfd > -1) && (!_getsockname(incomingSockfd, sock_us, &uslen)))\r {\r              char buf[MAXBUF];\r#ifdef IPV6\r          if (this->family == AF_INET6)\r          {\r                      inet_ntop(AF_INET6, &((const sockaddr_in6*)client)->sin6_addr, buf, sizeof(buf));\r                      in_port = ntohs(((sockaddr_in6*)sock_us)->sin6_port);\r          }\r              else\r#endif\r            {\r                      inet_ntop(AF_INET, &((const sockaddr_in*)client)->sin_addr, buf, sizeof(buf));\r                 in_port = ntohs(((sockaddr_in*)sock_us)->sin_port);\r            }\r\r             NonBlocking(incomingSockfd);\r           if (ServerInstance->Config->GetIOHook(in_port))\r                {\r                      try\r                    {\r                              ServerInstance->Config->GetIOHook(in_port)->OnRawSocketAccept(incomingSockfd, buf, in_port);\r                   }\r                      catch (CoreException& modexcept)\r                       {\r                              ServerInstance->Log(DEBUG,"%s threw an exception: %s", modexcept.GetSource(), modexcept.GetReason());\r                  }\r              }\r              ServerInstance->stats->statsAccept++;\r          userrec::AddClient(ServerInstance, incomingSockfd, in_port, false, this->family, client);\r      }\r      else\r   {\r              shutdown(incomingSockfd,2);\r            close(incomingSockfd);\r         ServerInstance->stats->statsRefused++;\r }\r      delete[] client;\r       delete[] sock_us;\r}\r\r/* Match raw bytes using CIDR bit matching, used by higher level MatchCIDR() */\rbool irc::sockets::MatchCIDRBits(unsigned char* address, unsigned char* mask, unsigned int mask_bits)\r{\r   unsigned int modulus = mask_bits % 8; /* Number of whole bytes in the mask */\r  unsigned int divisor = mask_bits / 8; /* Remaining bits in the mask after whole bytes are dealt with */\r\r       /* First compare the whole bytes, if they dont match, return false */\r  if (memcmp(address, mask, divisor))\r            return false;\r\r /* Now if there are any remainder bits, we compare them with logic AND */\r      if (modulus)\r           if ((address[divisor] & inverted_bits[modulus]) != (mask[divisor] & inverted_bits[modulus]))\r                   /* If they dont match, return false */\r                 return false;\r\r /* The address matches the mask, to mask_bits bits of mask */\r  return true;\r}\r\r/* Match CIDR, but dont attempt to match() against leading *!*@ sections */\rbool irc::sockets::MatchCIDR(const char* address, const char* cidr_mask)\r{\r return MatchCIDR(address, cidr_mask, false);\r}\r\r/* Match CIDR strings, e.g. 127.0.0.1 to 127.0.0.0/8 or 3ffe:1:5:6::8 to 3ffe:1::0/32\r * If you have a lot of hosts to match, youre probably better off building your mask once\r * and then using the lower level MatchCIDRBits directly.\r *\r * This will also attempt to match any leading usernames or nicknames on the mask, using\r * match(), when match_with_username is true.\r */\rbool irc::sockets::MatchCIDR(const char* address, const char* cidr_mask, bool match_with_username)\r{\r   unsigned char addr_raw[16];\r    unsigned char mask_raw[16];\r    unsigned int bits = 0;\r char* mask = NULL;\r\r    /* The caller is trying to match ident@<mask>/bits.\r     * Chop off the ident@ portion, use match() on it\r       * seperately.\r  */\r    if (match_with_username)\r       {\r              /* Duplicate the strings, and try to find the position\r          * of the @ symbol in each */\r          char* address_dupe = strdup(address);\r          char* cidr_dupe = strdup(cidr_mask);\r   \r               /* Use strchr not strrchr, because its going to be nearer to the left */\r               char* username_mask_pos = strrchr(cidr_dupe, '@');\r             char* username_addr_pos = strrchr(address_dupe, '@');\r\r         /* Both strings have an @ symbol in them */\r            if (username_mask_pos && username_addr_pos)\r            {\r                      /* Zero out the location of the @ symbol */\r                    *username_mask_pos = *username_addr_pos = 0;\r\r                  /* Try and match() the strings before the @\r                     * symbols, and recursively call MatchCIDR without\r                      * username matching enabled to match the host part.\r                    */\r                    bool result = (match(address_dupe, cidr_dupe) && MatchCIDR(username_addr_pos + 1, username_mask_pos + 1, false));\r\r                     /* Free the stuff we created */\r                        free(address_dupe);\r                    free(cidr_dupe);\r\r                      /* Return a result */\r                  return result;\r         }\r              else\r           {\r                      /* One or both didnt have an @ in,\r                      * just match as CIDR\r                   */\r                    free(address_dupe);\r                    free(cidr_dupe);\r                       mask = strdup(cidr_mask);\r              }\r      }\r      else\r   {\r              /* Make a copy of the cidr mask string,\r                 * we're going to change it\r             */\r            mask = strdup(cidr_mask);\r      }\r\r     in_addr  address_in4;\r  in_addr  mask_in4;\r\r\r   /* Use strrchr for this, its nearer to the right */\r    char* bits_chars = strrchr(mask,'/');\r\r if (bits_chars)\r        {\r              bits = atoi(bits_chars + 1);\r           *bits_chars = 0;\r       }\r      else\r   {\r              /* No 'number of bits' field! */\r               free(mask);\r            return false;\r  }\r\r#ifdef SUPPORT_IP6LINKS\r     in6_addr address_in6;\r  in6_addr mask_in6;\r\r    if (inet_pton(AF_INET6, address, &address_in6) > 0)\r    {\r              if (inet_pton(AF_INET6, mask, &mask_in6) > 0)\r          {\r                      memcpy(&addr_raw, &address_in6.s6_addr, 16);\r                   memcpy(&mask_raw, &mask_in6.s6_addr, 16);\r\r                     if (bits > 128)\r                                bits = 128;\r            }\r              else\r           {\r                      /* The address was valid ipv6, but the mask\r                     * that goes with it wasnt.\r                     */\r                    free(mask);\r                    return false;\r          }\r      }\r      else\r#endif\r    if (inet_pton(AF_INET, address, &address_in4) > 0)\r     {\r              if (inet_pton(AF_INET, mask, &mask_in4) > 0)\r           {\r                      memcpy(&addr_raw, &address_in4.s_addr, 4);\r                     memcpy(&mask_raw, &mask_in4.s_addr, 4);\r\r                       if (bits > 32)\r                         bits = 32;\r             }\r              else\r           {\r                      /* The address was valid ipv4,\r                  * but the mask that went with it wasnt.\r                        */\r                    free(mask);\r                    return false;\r          }\r      }\r      else\r   {\r              /* The address was neither ipv4 or ipv6 */\r             free(mask);\r            return false;\r  }\r\r     /* Low-level-match the bits in the raw data */\r free(mask);\r    return MatchCIDRBits(addr_raw, mask_raw, bits);\r}\r\rvoid irc::sockets::Blocking(int s)\r{\r#ifndef WIN32\r  int flags = fcntl(s, F_GETFL, 0);\r      fcntl(s, F_SETFL, flags ^ O_NONBLOCK);\r#else\r   unsigned long opt = 0;\r ioctlsocket(s, FIONBIO, &opt);\r#endif\r}\r\rvoid irc::sockets::NonBlocking(int s)\r{\r#ifndef WIN32\r int flags = fcntl(s, F_GETFL, 0);\r      fcntl(s, F_SETFL, flags | O_NONBLOCK);\r#else\r   unsigned long opt = 1;\r ioctlsocket(s, FIONBIO, &opt);\r#endif\r}\r\r/** This will bind a socket to a port. It works for UDP/TCP.\r * It can only bind to IP addresses, if you wish to bind to hostnames\r * you should first resolve them using class 'Resolver'.\r */ \rbool InspIRCd::BindSocket(int sockfd, int port, char* addr, bool dolisten)\r{\r /* We allocate 2 of these, because sockaddr_in6 is larger than sockaddr (ugh, hax) */\r  sockaddr* server = new sockaddr[2];\r    memset(server,0,sizeof(sockaddr)*2);\r\r  int ret, size;\r\r        if (*addr == '*')\r              *addr = 0;\r\r#ifdef IPV6\r        if (*addr)\r     {\r              /* There is an address here. Is it ipv6? */\r            if (strchr(addr,':'))\r          {\r                      /* Yes it is */\r                        in6_addr addy;\r                 if (inet_pton(AF_INET6, addr, &addy) < 1)\r                      {\r                              delete[] server;\r                               return false;\r                  }\r\r                     ((sockaddr_in6*)server)->sin6_family = AF_INET6;\r                       memcpy(&(((sockaddr_in6*)server)->sin6_addr), &addy, sizeof(in6_addr));\r                        ((sockaddr_in6*)server)->sin6_port = htons(port);\r                      size = sizeof(sockaddr_in6);\r           }\r              else\r           {\r                      /* No, its not */\r                      in_addr addy;\r                  if (inet_pton(AF_INET, addr, &addy) < 1)\r                       {\r                              delete[] server;\r                               return false;\r                  }\r\r                     ((sockaddr_in*)server)->sin_family = AF_INET;\r                  ((sockaddr_in*)server)->sin_addr = addy;\r                       ((sockaddr_in*)server)->sin_port = htons(port);\r                        size = sizeof(sockaddr_in);\r            }\r      }\r      else\r   {\r              if (port == -1)\r                {\r                      /* Port -1: Means UDP IPV4 port binding - Special case\r                  * used by DNS engine.\r                  */\r                    ((sockaddr_in*)server)->sin_family = AF_INET;\r                  ((sockaddr_in*)server)->sin_addr.s_addr = htonl(INADDR_ANY);\r                   ((sockaddr_in*)server)->sin_port = 0;\r                  size = sizeof(sockaddr_in);\r            }\r              else\r           {\r                      /* Theres no address here, default to ipv6 bind to all */\r                      ((sockaddr_in6*)server)->sin6_family = AF_INET6;\r                       memset(&(((sockaddr_in6*)server)->sin6_addr), 0, sizeof(in6_addr));\r                    ((sockaddr_in6*)server)->sin6_port = htons(port);\r                      size = sizeof(sockaddr_in6);\r           }\r      }\r#else\r        /* If we aren't built with ipv6, the choice becomes simple */\r  ((sockaddr_in*)server)->sin_family = AF_INET;\r  if (*addr)\r     {\r              /* There is an address here. */\r                in_addr addy;\r          if (inet_pton(AF_INET, addr, &addy) < 1)\r               {\r                      delete[] server;\r                       return false;\r          }\r              ((sockaddr_in*)server)->sin_addr = addy;\r       }\r      else\r   {\r              /* Bind ipv4 to all */\r         ((sockaddr_in*)server)->sin_addr.s_addr = htonl(INADDR_ANY);\r   }\r      /* Bind ipv4 port number */\r    ((sockaddr_in*)server)->sin_port = htons(port);\r        size = sizeof(sockaddr_in);\r#endif\r     ret = bind(sockfd, server, size);\r      delete[] server;\r\r      if (ret < 0)\r   {\r              return false;\r  }\r      else\r   {\r              if (dolisten)\r          {\r                      if (listen(sockfd, Config->MaxConn) == -1)\r                     {\r                              this->Log(DEFAULT,"ERROR in listen(): %s",strerror(errno));\r                            return false;\r                  }\r                      else\r                   {\r                              this->Log(DEBUG,"New socket binding for %d with listen: %s:%d", sockfd, addr, port);\r                           NonBlocking(sockfd);\r                           return true;\r                   }\r              }\r              else\r           {\r                      this->Log(DEBUG,"New socket binding for %d without listen: %s:%d", sockfd, addr, port);\r                        return true;\r           }\r      }\r}\r\r// Open a TCP Socket\rint irc::sockets::OpenTCPSocket(char* addr, int socktype)\r{\r  int sockfd;\r    int on = 1;\r    struct linger linger = { 0 };\r#ifdef IPV6\r      if (strchr(addr,':') || (!*addr))\r              sockfd = socket (PF_INET6, socktype, 0);\r       else\r           sockfd = socket (PF_INET, socktype, 0);\r        if (sockfd < 0)\r#else\r  if ((sockfd = socket (PF_INET, socktype, 0)) < 0)\r#endif\r       {\r              return ERROR;\r  }\r      else\r   {\r              setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char*)&on, sizeof(on));\r          /* This is BSD compatible, setting l_onoff to 0 is *NOT* http://web.irc.org/mla/ircd-dev/msg02259.html */\r              linger.l_onoff = 1;\r            linger.l_linger = 1;\r           setsockopt(sockfd, SOL_SOCKET, SO_LINGER, (char*)&linger,sizeof(linger));\r              return (sockfd);\r       }\r}\r\r/* XXX: Probably belongs in class InspIRCd */\rint InspIRCd::BindPorts(bool bail, int &ports_found, FailedPortList &failed_ports)\r{\r        char configToken[MAXBUF], Addr[MAXBUF], Type[MAXBUF];\r  int bound = 0;\r bool started_with_nothing = (Config->ports.size() == 0);\r       std::vector<std::pair<std::string, int> > old_ports;\r\r  /* XXX: Make a copy of the old ip/port pairs here */\r   for (std::vector<ListenSocket*>::iterator o = Config->ports.begin(); o != Config->ports.end(); ++o)\r            old_ports.push_back(make_pair((*o)->GetIP(), (*o)->GetPort()));\r\r       for (int count = 0; count < Config->ConfValueEnum(Config->config_data, "bind"); count++)\r       {\r              Config->ConfValue(Config->config_data, "bind", "port", count, configToken, MAXBUF);\r            Config->ConfValue(Config->config_data, "bind", "address", count, Addr, MAXBUF);\r                Config->ConfValue(Config->config_data, "bind", "type", count, Type, MAXBUF);\r\r          if ((!*Type) || (!strcmp(Type,"clients")))\r             {\r                      irc::portparser portrange(configToken, false);\r                 int portno = -1;\r                       while ((portno = portrange.GetToken()))\r                        {\r                              if (*Addr == '*')\r                                      *Addr = 0;\r\r                            bool skip = false;\r                             for (std::vector<ListenSocket*>::iterator n = Config->ports.begin(); n != Config->ports.end(); ++n)\r                            {\r                                      if (((*n)->GetIP() == Addr) && ((*n)->GetPort() == portno))\r                                    {\r                                              skip = true;\r                                           /* XXX: Here, erase from our copy of the list */\r                                               for (std::vector<std::pair<std::string, int> >::iterator k = old_ports.begin(); k != old_ports.end(); ++k)\r                                             {\r                                                      if ((k->first == Addr) && (k->second == portno))\r                                                       {\r                                                              old_ports.erase(k);\r                                                            break;\r                                                 }\r                                              }\r                                      }\r                              }\r                              if (!skip)\r                             {\r                                      ListenSocket* ll = new ListenSocket(this, portno, Addr);\r                                       if (ll->GetFd() > -1)\r                                  {\r                                              bound++;\r                                               Config->ports.push_back(ll);\r                                   }\r                                      else\r                                   {\r                                              failed_ports.push_back(std::make_pair(Addr, portno));\r                                  }\r                                      ports_found++;\r                         }\r                      }\r              }\r      }\r\r     /* XXX: Here, anything left in our copy list, close as removed */\r      if (!started_with_nothing)\r     {\r              for (size_t k = 0; k < old_ports.size(); ++k)\r          {\r                      for (std::vector<ListenSocket*>::iterator n = Config->ports.begin(); n != Config->ports.end(); ++n)\r                    {\r                              if (((*n)->GetIP() == old_ports[k].first) && ((*n)->GetPort() == old_ports[k].second))\r                         {\r                                      this->Log(DEFAULT,"Port binding %s:%d was removed from the config file, closing.", old_ports[k].first.c_str(), old_ports[k].second);\r                                   delete *n;\r                                     Config->ports.erase(n);\r                                        break;\r                         }\r                      }\r              }\r      }\r\r     return bound;\r}\r\rconst char* irc::sockets::insp_ntoa(insp_inaddr n)\r{\r  static char buf[1024];\r inet_ntop(AF_FAMILY, &n, buf, sizeof(buf));\r    return buf;\r}\r\rint irc::sockets::insp_aton(const char* a, insp_inaddr* n)\r{\r    return inet_pton(AF_FAMILY, a, n);\r}\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include <string>
+#include "configreader.h"
+#include "socket.h"
+#include "socketengine.h"
+#include "wildcard.h"
+
+using namespace irc::sockets;
+
+/* Used when comparing CIDR masks for the modulus bits left over.
+ * A lot of ircd's seem to do this:
+ * ((-1) << (8 - (mask % 8)))
+ * But imho, it sucks in comparison to a nice neat lookup table.
+ */
+const unsigned char inverted_bits[8] = {       0x00, /* 00000000 - 0 bits - never actually used */
+                               0x80, /* 10000000 - 1 bits */
+                               0xC0, /* 11000000 - 2 bits */
+                               0xE0, /* 11100000 - 3 bits */
+                               0xF0, /* 11110000 - 4 bits */
+                               0xF8, /* 11111000 - 5 bits */
+                               0xFC, /* 11111100 - 6 bits */
+                               0xFE  /* 11111110 - 7 bits */
+};
+
+
+ListenSocket::ListenSocket(InspIRCd* Instance, int port, char* addr) : ServerInstance(Instance), desc("plaintext"), bind_addr(addr), bind_port(port)
+{
+       this->SetFd(OpenTCPSocket(addr));
+       if (this->GetFd() > -1)
+       {
+               if (!Instance->BindSocket(this->fd,port,addr))
+                       this->fd = -1;
+#ifdef IPV6
+               if ((!*addr) || (strchr(addr,':')))
+                       this->family = AF_INET6;
+               else
+#endif
+               this->family = AF_INET;
+               Instance->SE->AddFd(this);
+       }
+}
+
+ListenSocket::~ListenSocket()
+{
+       if (this->GetFd() > -1)
+       {
+               ServerInstance->SE->DelFd(this);
+               ServerInstance->Log(DEBUG,"Shut down listener on fd %d", this->fd);
+               if (shutdown(this->fd, 2) || close(this->fd))
+                       ServerInstance->Log(DEBUG,"Failed to cancel listener: %s", strerror(errno));
+               this->fd = -1;
+       }
+}
+
+void ListenSocket::HandleEvent(EventType et, int errornum)
+{
+       sockaddr* sock_us = new sockaddr[2];    // our port number
+       sockaddr* client = new sockaddr[2];
+       socklen_t uslen, length;                // length of our port number
+       int incomingSockfd, in_port;
+
+#ifdef IPV6
+       if (this->family == AF_INET6)
+       {
+               uslen = sizeof(sockaddr_in6);
+               length = sizeof(sockaddr_in6);
+       }
+       else
+#endif
+       {
+               uslen = sizeof(sockaddr_in);
+               length = sizeof(sockaddr_in);
+       }
+
+       incomingSockfd = _accept (this->GetFd(), (sockaddr*)client, &length);
+
+       if ((incomingSockfd > -1) && (!_getsockname(incomingSockfd, sock_us, &uslen)))
+       {
+               char buf[MAXBUF];
+#ifdef IPV6
+               if (this->family == AF_INET6)
+               {
+                       inet_ntop(AF_INET6, &((const sockaddr_in6*)client)->sin6_addr, buf, sizeof(buf));
+                       in_port = ntohs(((sockaddr_in6*)sock_us)->sin6_port);
+               }
+               else
+#endif
+               {
+                       inet_ntop(AF_INET, &((const sockaddr_in*)client)->sin_addr, buf, sizeof(buf));
+                       in_port = ntohs(((sockaddr_in*)sock_us)->sin_port);
+               }
+
+               NonBlocking(incomingSockfd);
+               if (ServerInstance->Config->GetIOHook(in_port))
+               {
+                       try
+                       {
+                               ServerInstance->Config->GetIOHook(in_port)->OnRawSocketAccept(incomingSockfd, buf, in_port);
+                       }
+                       catch (CoreException& modexcept)
+                       {
+                               ServerInstance->Log(DEBUG,"%s threw an exception: %s", modexcept.GetSource(), modexcept.GetReason());
+                       }
+               }
+               ServerInstance->stats->statsAccept++;
+               userrec::AddClient(ServerInstance, incomingSockfd, in_port, false, this->family, client);
+       }
+       else
+       {
+               shutdown(incomingSockfd,2);
+               close(incomingSockfd);
+               ServerInstance->stats->statsRefused++;
+       }
+       delete[] client;
+       delete[] sock_us;
+}
+
+/* Match raw bytes using CIDR bit matching, used by higher level MatchCIDR() */
+bool irc::sockets::MatchCIDRBits(unsigned char* address, unsigned char* mask, unsigned int mask_bits)
+{
+       unsigned int modulus = mask_bits % 8; /* Number of whole bytes in the mask */
+       unsigned int divisor = mask_bits / 8; /* Remaining bits in the mask after whole bytes are dealt with */
+
+       /* First compare the whole bytes, if they dont match, return false */
+       if (memcmp(address, mask, divisor))
+               return false;
+
+       /* Now if there are any remainder bits, we compare them with logic AND */
+       if (modulus)
+               if ((address[divisor] & inverted_bits[modulus]) != (mask[divisor] & inverted_bits[modulus]))
+                       /* If they dont match, return false */
+                       return false;
+
+       /* The address matches the mask, to mask_bits bits of mask */
+       return true;
+}
+
+/* Match CIDR, but dont attempt to match() against leading *!*@ sections */
+bool irc::sockets::MatchCIDR(const char* address, const char* cidr_mask)
+{
+       return MatchCIDR(address, cidr_mask, false);
+}
+
+/* Match CIDR strings, e.g. 127.0.0.1 to 127.0.0.0/8 or 3ffe:1:5:6::8 to 3ffe:1::0/32
+ * If you have a lot of hosts to match, youre probably better off building your mask once
+ * and then using the lower level MatchCIDRBits directly.
+ *
+ * This will also attempt to match any leading usernames or nicknames on the mask, using
+ * match(), when match_with_username is true.
+ */
+bool irc::sockets::MatchCIDR(const char* address, const char* cidr_mask, bool match_with_username)
+{
+       unsigned char addr_raw[16];
+       unsigned char mask_raw[16];
+       unsigned int bits = 0;
+       char* mask = NULL;
+
+       /* The caller is trying to match ident@<mask>/bits.
+        * Chop off the ident@ portion, use match() on it
+        * seperately.
+        */
+       if (match_with_username)
+       {
+               /* Duplicate the strings, and try to find the position
+                * of the @ symbol in each */
+               char* address_dupe = strdup(address);
+               char* cidr_dupe = strdup(cidr_mask);
+       
+               /* Use strchr not strrchr, because its going to be nearer to the left */
+               char* username_mask_pos = strrchr(cidr_dupe, '@');
+               char* username_addr_pos = strrchr(address_dupe, '@');
+
+               /* Both strings have an @ symbol in them */
+               if (username_mask_pos && username_addr_pos)
+               {
+                       /* Zero out the location of the @ symbol */
+                       *username_mask_pos = *username_addr_pos = 0;
+
+                       /* Try and match() the strings before the @
+                        * symbols, and recursively call MatchCIDR without
+                        * username matching enabled to match the host part.
+                        */
+                       bool result = (match(address_dupe, cidr_dupe) && MatchCIDR(username_addr_pos + 1, username_mask_pos + 1, false));
+
+                       /* Free the stuff we created */
+                       free(address_dupe);
+                       free(cidr_dupe);
+
+                       /* Return a result */
+                       return result;
+               }
+               else
+               {
+                       /* One or both didnt have an @ in,
+                        * just match as CIDR
+                        */
+                       free(address_dupe);
+                       free(cidr_dupe);
+                       mask = strdup(cidr_mask);
+               }
+       }
+       else
+       {
+               /* Make a copy of the cidr mask string,
+                * we're going to change it
+                */
+               mask = strdup(cidr_mask);
+       }
+
+       in_addr  address_in4;
+       in_addr  mask_in4;
+
+
+       /* Use strrchr for this, its nearer to the right */
+       char* bits_chars = strrchr(mask,'/');
+
+       if (bits_chars)
+       {
+               bits = atoi(bits_chars + 1);
+               *bits_chars = 0;
+       }
+       else
+       {
+               /* No 'number of bits' field! */
+               free(mask);
+               return false;
+       }
+
+#ifdef SUPPORT_IP6LINKS
+       in6_addr address_in6;
+       in6_addr mask_in6;
+
+       if (inet_pton(AF_INET6, address, &address_in6) > 0)
+       {
+               if (inet_pton(AF_INET6, mask, &mask_in6) > 0)
+               {
+                       memcpy(&addr_raw, &address_in6.s6_addr, 16);
+                       memcpy(&mask_raw, &mask_in6.s6_addr, 16);
+
+                       if (bits > 128)
+                               bits = 128;
+               }
+               else
+               {
+                       /* The address was valid ipv6, but the mask
+                        * that goes with it wasnt.
+                        */
+                       free(mask);
+                       return false;
+               }
+       }
+       else
+#endif
+       if (inet_pton(AF_INET, address, &address_in4) > 0)
+       {
+               if (inet_pton(AF_INET, mask, &mask_in4) > 0)
+               {
+                       memcpy(&addr_raw, &address_in4.s_addr, 4);
+                       memcpy(&mask_raw, &mask_in4.s_addr, 4);
+
+                       if (bits > 32)
+                               bits = 32;
+               }
+               else
+               {
+                       /* The address was valid ipv4,
+                        * but the mask that went with it wasnt.
+                        */
+                       free(mask);
+                       return false;
+               }
+       }
+       else
+       {
+               /* The address was neither ipv4 or ipv6 */
+               free(mask);
+               return false;
+       }
+
+       /* Low-level-match the bits in the raw data */
+       free(mask);
+       return MatchCIDRBits(addr_raw, mask_raw, bits);
+}
+
+void irc::sockets::Blocking(int s)
+{
+#ifndef WIN32
+       int flags = fcntl(s, F_GETFL, 0);
+       fcntl(s, F_SETFL, flags ^ O_NONBLOCK);
+#else
+       unsigned long opt = 0;
+       ioctlsocket(s, FIONBIO, &opt);
+#endif
+}
+
+void irc::sockets::NonBlocking(int s)
+{
+#ifndef WIN32
+       int flags = fcntl(s, F_GETFL, 0);
+       fcntl(s, F_SETFL, flags | O_NONBLOCK);
+#else
+       unsigned long opt = 1;
+       ioctlsocket(s, FIONBIO, &opt);
+#endif
+}
+
+/** This will bind a socket to a port. It works for UDP/TCP.
+ * It can only bind to IP addresses, if you wish to bind to hostnames
+ * you should first resolve them using class 'Resolver'.
+ */ 
+bool InspIRCd::BindSocket(int sockfd, int port, char* addr, bool dolisten)
+{
+       /* We allocate 2 of these, because sockaddr_in6 is larger than sockaddr (ugh, hax) */
+       sockaddr* server = new sockaddr[2];
+       memset(server,0,sizeof(sockaddr)*2);
+
+       int ret, size;
+
+       if (*addr == '*')
+               *addr = 0;
+
+#ifdef IPV6
+       if (*addr)
+       {
+               /* There is an address here. Is it ipv6? */
+               if (strchr(addr,':'))
+               {
+                       /* Yes it is */
+                       in6_addr addy;
+                       if (inet_pton(AF_INET6, addr, &addy) < 1)
+                       {
+                               delete[] server;
+                               return false;
+                       }
+
+                       ((sockaddr_in6*)server)->sin6_family = AF_INET6;
+                       memcpy(&(((sockaddr_in6*)server)->sin6_addr), &addy, sizeof(in6_addr));
+                       ((sockaddr_in6*)server)->sin6_port = htons(port);
+                       size = sizeof(sockaddr_in6);
+               }
+               else
+               {
+                       /* No, its not */
+                       in_addr addy;
+                       if (inet_pton(AF_INET, addr, &addy) < 1)
+                       {
+                               delete[] server;
+                               return false;
+                       }
+
+                       ((sockaddr_in*)server)->sin_family = AF_INET;
+                       ((sockaddr_in*)server)->sin_addr = addy;
+                       ((sockaddr_in*)server)->sin_port = htons(port);
+                       size = sizeof(sockaddr_in);
+               }
+       }
+       else
+       {
+               if (port == -1)
+               {
+                       /* Port -1: Means UDP IPV4 port binding - Special case
+                        * used by DNS engine.
+                        */
+                       ((sockaddr_in*)server)->sin_family = AF_INET;
+                       ((sockaddr_in*)server)->sin_addr.s_addr = htonl(INADDR_ANY);
+                       ((sockaddr_in*)server)->sin_port = 0;
+                       size = sizeof(sockaddr_in);
+               }
+               else
+               {
+                       /* Theres no address here, default to ipv6 bind to all */
+                       ((sockaddr_in6*)server)->sin6_family = AF_INET6;
+                       memset(&(((sockaddr_in6*)server)->sin6_addr), 0, sizeof(in6_addr));
+                       ((sockaddr_in6*)server)->sin6_port = htons(port);
+                       size = sizeof(sockaddr_in6);
+               }
+       }
+#else
+       /* If we aren't built with ipv6, the choice becomes simple */
+       ((sockaddr_in*)server)->sin_family = AF_INET;
+       if (*addr)
+       {
+               /* There is an address here. */
+               in_addr addy;
+               if (inet_pton(AF_INET, addr, &addy) < 1)
+               {
+                       delete[] server;
+                       return false;
+               }
+               ((sockaddr_in*)server)->sin_addr = addy;
+       }
+       else
+       {
+               /* Bind ipv4 to all */
+               ((sockaddr_in*)server)->sin_addr.s_addr = htonl(INADDR_ANY);
+       }
+       /* Bind ipv4 port number */
+       ((sockaddr_in*)server)->sin_port = htons(port);
+       size = sizeof(sockaddr_in);
+#endif
+       ret = bind(sockfd, server, size);
+       delete[] server;
+
+       if (ret < 0)
+       {
+               return false;
+       }
+       else
+       {
+               if (dolisten)
+               {
+                       if (listen(sockfd, Config->MaxConn) == -1)
+                       {
+                               this->Log(DEFAULT,"ERROR in listen(): %s",strerror(errno));
+                               return false;
+                       }
+                       else
+                       {
+                               this->Log(DEBUG,"New socket binding for %d with listen: %s:%d", sockfd, addr, port);
+                               NonBlocking(sockfd);
+                               return true;
+                       }
+               }
+               else
+               {
+                       this->Log(DEBUG,"New socket binding for %d without listen: %s:%d", sockfd, addr, port);
+                       return true;
+               }
+       }
+}
+
+// Open a TCP Socket
+int irc::sockets::OpenTCPSocket(char* addr, int socktype)
+{
+       int sockfd;
+       int on = 1;
+       struct linger linger = { 0 };
+#ifdef IPV6
+       if (strchr(addr,':') || (!*addr))
+               sockfd = socket (PF_INET6, socktype, 0);
+       else
+               sockfd = socket (PF_INET, socktype, 0);
+       if (sockfd < 0)
+#else
+       if ((sockfd = socket (PF_INET, socktype, 0)) < 0)
+#endif
+       {
+               return ERROR;
+       }
+       else
+       {
+               setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char*)&on, sizeof(on));
+               /* This is BSD compatible, setting l_onoff to 0 is *NOT* http://web.irc.org/mla/ircd-dev/msg02259.html */
+               linger.l_onoff = 1;
+               linger.l_linger = 1;
+               setsockopt(sockfd, SOL_SOCKET, SO_LINGER, (char*)&linger,sizeof(linger));
+               return (sockfd);
+       }
+}
+
+/* XXX: Probably belongs in class InspIRCd */
+int InspIRCd::BindPorts(bool bail, int &ports_found, FailedPortList &failed_ports)
+{
+       char configToken[MAXBUF], Addr[MAXBUF], Type[MAXBUF];
+       int bound = 0;
+       bool started_with_nothing = (Config->ports.size() == 0);
+       std::vector<std::pair<std::string, int> > old_ports;
+
+       /* XXX: Make a copy of the old ip/port pairs here */
+       for (std::vector<ListenSocket*>::iterator o = Config->ports.begin(); o != Config->ports.end(); ++o)
+               old_ports.push_back(make_pair((*o)->GetIP(), (*o)->GetPort()));
+
+       for (int count = 0; count < Config->ConfValueEnum(Config->config_data, "bind"); count++)
+       {
+               Config->ConfValue(Config->config_data, "bind", "port", count, configToken, MAXBUF);
+               Config->ConfValue(Config->config_data, "bind", "address", count, Addr, MAXBUF);
+               Config->ConfValue(Config->config_data, "bind", "type", count, Type, MAXBUF);
+
+               if ((!*Type) || (!strcmp(Type,"clients")))
+               {
+                       irc::portparser portrange(configToken, false);
+                       int portno = -1;
+                       while ((portno = portrange.GetToken()))
+                       {
+                               if (*Addr == '*')
+                                       *Addr = 0;
+
+                               bool skip = false;
+                               for (std::vector<ListenSocket*>::iterator n = Config->ports.begin(); n != Config->ports.end(); ++n)
+                               {
+                                       if (((*n)->GetIP() == Addr) && ((*n)->GetPort() == portno))
+                                       {
+                                               skip = true;
+                                               /* XXX: Here, erase from our copy of the list */
+                                               for (std::vector<std::pair<std::string, int> >::iterator k = old_ports.begin(); k != old_ports.end(); ++k)
+                                               {
+                                                       if ((k->first == Addr) && (k->second == portno))
+                                                       {
+                                                               old_ports.erase(k);
+                                                               break;
+                                                       }
+                                               }
+                                       }
+                               }
+                               if (!skip)
+                               {
+                                       ListenSocket* ll = new ListenSocket(this, portno, Addr);
+                                       if (ll->GetFd() > -1)
+                                       {
+                                               bound++;
+                                               Config->ports.push_back(ll);
+                                       }
+                                       else
+                                       {
+                                               failed_ports.push_back(std::make_pair(Addr, portno));
+                                       }
+                                       ports_found++;
+                               }
+                       }
+               }
+       }
+
+       /* XXX: Here, anything left in our copy list, close as removed */
+       if (!started_with_nothing)
+       {
+               for (size_t k = 0; k < old_ports.size(); ++k)
+               {
+                       for (std::vector<ListenSocket*>::iterator n = Config->ports.begin(); n != Config->ports.end(); ++n)
+                       {
+                               if (((*n)->GetIP() == old_ports[k].first) && ((*n)->GetPort() == old_ports[k].second))
+                               {
+                                       this->Log(DEFAULT,"Port binding %s:%d was removed from the config file, closing.", old_ports[k].first.c_str(), old_ports[k].second);
+                                       delete *n;
+                                       Config->ports.erase(n);
+                                       break;
+                               }
+                       }
+               }
+       }
+
+       return bound;
+}
+
+const char* irc::sockets::insp_ntoa(insp_inaddr n)
+{
+       static char buf[1024];
+       inet_ntop(AF_FAMILY, &n, buf, sizeof(buf));
+       return buf;
+}
+
+int irc::sockets::insp_aton(const char* a, insp_inaddr* n)
+{
+       return inet_pton(AF_FAMILY, a, n);
+}
+
index 6a4e653db1bfe0a385f1088a9fc0532642d52979..48f7e11bf611d7e2f05df7af0d2e2dd7260c59b7 100644 (file)
@@ -1 +1,93 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "socketengine.h"\r\rint EventHandler::GetFd()\r{\r      return this->fd;\r}\r\rvoid EventHandler::SetFd(int FD)\r{\r this->fd = FD;\r}\r\rbool EventHandler::Readable()\r{\r      return true;\r}\r\rbool EventHandler::Writeable()\r{\r       return false;\r}\r\rvoid SocketEngine::WantWrite(EventHandler* eh)\r{\r}\r\rSocketEngine::SocketEngine(InspIRCd* Instance) : ServerInstance(Instance)\r{\r       memset(ref, 0, sizeof(ref));\r}\r\rSocketEngine::~SocketEngine()\r{\r}\r\rbool SocketEngine::AddFd(EventHandler* eh)\r{\r        return true;\r}\r\rbool SocketEngine::HasFd(int fd)\r{\r     if ((fd < 0) || (fd > MAX_DESCRIPTORS))\r                return false;\r  return ref[fd];\r}\r\rEventHandler* SocketEngine::GetRef(int fd)\r{\r        if ((fd < 0) || (fd > MAX_DESCRIPTORS))\r                return 0;\r      return ref[fd];\r}\r\rbool SocketEngine::DelFd(EventHandler* eh, bool force)\r{\r    return true;\r}\r\rint SocketEngine::GetMaxFds()\r{\r        return 0;\r}\r\rint SocketEngine::GetRemainingFds()\r{\r     return 0;\r}\r\rint SocketEngine::DispatchEvents()\r{\r      return 0;\r}\r\rstd::string SocketEngine::GetName()\r{\r     return "misconfigured";\r}\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "socketengine.h"
+
+int EventHandler::GetFd()
+{
+       return this->fd;
+}
+
+void EventHandler::SetFd(int FD)
+{
+       this->fd = FD;
+}
+
+bool EventHandler::Readable()
+{
+       return true;
+}
+
+bool EventHandler::Writeable()
+{
+       return false;
+}
+
+void SocketEngine::WantWrite(EventHandler* eh)
+{
+}
+
+SocketEngine::SocketEngine(InspIRCd* Instance) : ServerInstance(Instance)
+{
+       memset(ref, 0, sizeof(ref));
+}
+
+SocketEngine::~SocketEngine()
+{
+}
+
+bool SocketEngine::AddFd(EventHandler* eh)
+{
+       return true;
+}
+
+bool SocketEngine::HasFd(int fd)
+{
+       if ((fd < 0) || (fd > MAX_DESCRIPTORS))
+               return false;
+       return ref[fd];
+}
+
+EventHandler* SocketEngine::GetRef(int fd)
+{
+       if ((fd < 0) || (fd > MAX_DESCRIPTORS))
+               return 0;
+       return ref[fd];
+}
+
+bool SocketEngine::DelFd(EventHandler* eh, bool force)
+{
+       return true;
+}
+
+int SocketEngine::GetMaxFds()
+{
+       return 0;
+}
+
+int SocketEngine::GetRemainingFds()
+{
+       return 0;
+}
+
+int SocketEngine::DispatchEvents()
+{
+       return 0;
+}
+
+std::string SocketEngine::GetName()
+{
+       return "misconfigured";
+}
+
index 7a7f46d1b21e7db1e8ce56bd9beef057114ed2e3..4ed68ca57a1f913aadfb0cb85e86fe5d9b3136cd 100644 (file)
@@ -1 +1,157 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "exitcodes.h"\r#include <sys/epoll.h>\r#include "socketengine_epoll.h"\r\rEPollEngine::EPollEngine(InspIRCd* Instance) : SocketEngine(Instance)\r{\r      EngineHandle = epoll_create(MAX_DESCRIPTORS);\r\r if (EngineHandle == -1)\r        {\r              ServerInstance->Log(SPARSE,"ERROR: Could not initialize socket engine: %s", strerror(errno));\r          ServerInstance->Log(SPARSE,"ERROR: Your kernel probably does not have the proper features. This is a fatal error, exiting now.");\r              printf("ERROR: Could not initialize socket engine: %s\n", strerror(errno));\r            printf("ERROR: Your kernel probably does not have the proper features. This is a fatal error, exiting now.\n");\r                InspIRCd::Exit(EXIT_STATUS_SOCKETENGINE);\r      }\r      CurrentSetSize = 0;\r}\r\rEPollEngine::~EPollEngine()\r{\r   close(EngineHandle);\r}\r\rbool EPollEngine::AddFd(EventHandler* eh)\r{\r    int fd = eh->GetFd();\r  if ((fd < 0) || (fd > MAX_DESCRIPTORS))\r                return false;\r\r if (GetRemainingFds() <= 1)\r            return false;\r\r if (ref[fd])\r           return false;\r\r ref[fd] = eh;\r  struct epoll_event ev;\r memset(&ev,0,sizeof(struct epoll_event));\r      eh->Readable() ? ev.events = EPOLLIN : ev.events = EPOLLOUT;\r   ev.data.fd = fd;\r       int i = epoll_ctl(EngineHandle, EPOLL_CTL_ADD, fd, &ev);\r       if (i < 0)\r     {\r              return false;\r  }\r\r     ServerInstance->Log(DEBUG,"New file descriptor: %d", fd);\r      CurrentSetSize++;\r      return true;\r}\r\rvoid EPollEngine::WantWrite(EventHandler* eh)\r{\r        /** Use oneshot so that the system removes the writeable\r        * status for us and saves us a call.\r   */\r    struct epoll_event ev;\r memset(&ev,0,sizeof(struct epoll_event));\r      ev.events = EPOLLOUT;\r  ev.data.fd = eh->GetFd();\r      epoll_ctl(EngineHandle, EPOLL_CTL_MOD, eh->GetFd(), &ev);\r}\r\rbool EPollEngine::DelFd(EventHandler* eh, bool force)\r{\r   int fd = eh->GetFd();\r  if ((fd < 0) || (fd > MAX_DESCRIPTORS))\r                return false;\r\r struct epoll_event ev;\r memset(&ev,0,sizeof(struct epoll_event));\r      eh->Readable() ? ev.events = EPOLLIN : ev.events = EPOLLOUT;\r   ev.data.fd = fd;\r       int i = epoll_ctl(EngineHandle, EPOLL_CTL_DEL, fd, &ev);\r\r      if (i < 0 && !force)\r           return false;\r\r CurrentSetSize--;\r      ref[fd] = NULL;\r\r       ServerInstance->Log(DEBUG,"Remove file descriptor: %d", fd);\r   return true;\r}\r\rint EPollEngine::GetMaxFds()\r{\r return MAX_DESCRIPTORS;\r}\r\rint EPollEngine::GetRemainingFds()\r{\r        return MAX_DESCRIPTORS - CurrentSetSize;\r}\r\rint EPollEngine::DispatchEvents()\r{\r        socklen_t codesize;\r    int errcode;\r   int i = epoll_wait(EngineHandle, events, MAX_DESCRIPTORS, 1000);\r       for (int j = 0; j < i; j++)\r    {\r              if (events[j].events & EPOLLHUP)\r               {\r                      if (ref[events[j].data.fd])\r                            ref[events[j].data.fd]->HandleEvent(EVENT_ERROR, 0);\r                   continue;\r              }\r              if (events[j].events & EPOLLERR)\r               {\r                      /* Get error number */\r                 if (getsockopt(events[j].data.fd, SOL_SOCKET, SO_ERROR, &errcode, &codesize) < 0)\r                              errcode = errno;\r                       if (ref[events[j].data.fd])\r                            ref[events[j].data.fd]->HandleEvent(EVENT_ERROR, errcode);\r                     continue;\r              }\r              if (events[j].events & EPOLLOUT)\r               {\r                      struct epoll_event ev;\r                 memset(&ev,0,sizeof(struct epoll_event));\r                      ev.events = EPOLLIN;\r                   ev.data.fd = events[j].data.fd;\r                        epoll_ctl(EngineHandle, EPOLL_CTL_MOD, events[j].data.fd, &ev);\r                        if (ref[events[j].data.fd])\r                            ref[events[j].data.fd]->HandleEvent(EVENT_WRITE);\r              }\r              else\r           {\r                      if (ref[events[j].data.fd])\r                            ref[events[j].data.fd]->HandleEvent(EVENT_READ);\r               }\r      }\r\r     return i;\r}\r\rstd::string EPollEngine::GetName()\r{\r      return "epoll";\r}\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "exitcodes.h"
+#include <sys/epoll.h>
+#include "socketengine_epoll.h"
+
+EPollEngine::EPollEngine(InspIRCd* Instance) : SocketEngine(Instance)
+{
+       EngineHandle = epoll_create(MAX_DESCRIPTORS);
+
+       if (EngineHandle == -1)
+       {
+               ServerInstance->Log(SPARSE,"ERROR: Could not initialize socket engine: %s", strerror(errno));
+               ServerInstance->Log(SPARSE,"ERROR: Your kernel probably does not have the proper features. This is a fatal error, exiting now.");
+               printf("ERROR: Could not initialize socket engine: %s\n", strerror(errno));
+               printf("ERROR: Your kernel probably does not have the proper features. This is a fatal error, exiting now.\n");
+               InspIRCd::Exit(EXIT_STATUS_SOCKETENGINE);
+       }
+       CurrentSetSize = 0;
+}
+
+EPollEngine::~EPollEngine()
+{
+       close(EngineHandle);
+}
+
+bool EPollEngine::AddFd(EventHandler* eh)
+{
+       int fd = eh->GetFd();
+       if ((fd < 0) || (fd > MAX_DESCRIPTORS))
+               return false;
+
+       if (GetRemainingFds() <= 1)
+               return false;
+
+       if (ref[fd])
+               return false;
+
+       ref[fd] = eh;
+       struct epoll_event ev;
+       memset(&ev,0,sizeof(struct epoll_event));
+       eh->Readable() ? ev.events = EPOLLIN : ev.events = EPOLLOUT;
+       ev.data.fd = fd;
+       int i = epoll_ctl(EngineHandle, EPOLL_CTL_ADD, fd, &ev);
+       if (i < 0)
+       {
+               return false;
+       }
+
+       ServerInstance->Log(DEBUG,"New file descriptor: %d", fd);
+       CurrentSetSize++;
+       return true;
+}
+
+void EPollEngine::WantWrite(EventHandler* eh)
+{
+       /** Use oneshot so that the system removes the writeable
+        * status for us and saves us a call.
+        */
+       struct epoll_event ev;
+       memset(&ev,0,sizeof(struct epoll_event));
+       ev.events = EPOLLOUT;
+       ev.data.fd = eh->GetFd();
+       epoll_ctl(EngineHandle, EPOLL_CTL_MOD, eh->GetFd(), &ev);
+}
+
+bool EPollEngine::DelFd(EventHandler* eh, bool force)
+{
+       int fd = eh->GetFd();
+       if ((fd < 0) || (fd > MAX_DESCRIPTORS))
+               return false;
+
+       struct epoll_event ev;
+       memset(&ev,0,sizeof(struct epoll_event));
+       eh->Readable() ? ev.events = EPOLLIN : ev.events = EPOLLOUT;
+       ev.data.fd = fd;
+       int i = epoll_ctl(EngineHandle, EPOLL_CTL_DEL, fd, &ev);
+
+       if (i < 0 && !force)
+               return false;
+
+       CurrentSetSize--;
+       ref[fd] = NULL;
+
+       ServerInstance->Log(DEBUG,"Remove file descriptor: %d", fd);
+       return true;
+}
+
+int EPollEngine::GetMaxFds()
+{
+       return MAX_DESCRIPTORS;
+}
+
+int EPollEngine::GetRemainingFds()
+{
+       return MAX_DESCRIPTORS - CurrentSetSize;
+}
+
+int EPollEngine::DispatchEvents()
+{
+       socklen_t codesize;
+       int errcode;
+       int i = epoll_wait(EngineHandle, events, MAX_DESCRIPTORS, 1000);
+       for (int j = 0; j < i; j++)
+       {
+               if (events[j].events & EPOLLHUP)
+               {
+                       if (ref[events[j].data.fd])
+                               ref[events[j].data.fd]->HandleEvent(EVENT_ERROR, 0);
+                       continue;
+               }
+               if (events[j].events & EPOLLERR)
+               {
+                       /* Get error number */
+                       if (getsockopt(events[j].data.fd, SOL_SOCKET, SO_ERROR, &errcode, &codesize) < 0)
+                               errcode = errno;
+                       if (ref[events[j].data.fd])
+                               ref[events[j].data.fd]->HandleEvent(EVENT_ERROR, errcode);
+                       continue;
+               }
+               if (events[j].events & EPOLLOUT)
+               {
+                       struct epoll_event ev;
+                       memset(&ev,0,sizeof(struct epoll_event));
+                       ev.events = EPOLLIN;
+                       ev.data.fd = events[j].data.fd;
+                       epoll_ctl(EngineHandle, EPOLL_CTL_MOD, events[j].data.fd, &ev);
+                       if (ref[events[j].data.fd])
+                               ref[events[j].data.fd]->HandleEvent(EVENT_WRITE);
+               }
+               else
+               {
+                       if (ref[events[j].data.fd])
+                               ref[events[j].data.fd]->HandleEvent(EVENT_READ);
+               }
+       }
+
+       return i;
+}
+
+std::string EPollEngine::GetName()
+{
+       return "epoll";
+}
+
index 833bc097fba44cbb24886287a2803b2d2b7fcb18..89fd8717f8057271c12c8686e6c303f54df9231e 100644 (file)
@@ -1 +1,376 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "socketengine_iocp.h"\r#include <mswsock.h>\r\rIOCPEngine::IOCPEngine(InspIRCd * Instance) : SocketEngine(Instance)\r{\r       /* Create completion port */\r   m_completionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, (ULONG_PTR)0, 0);\r\r       /* Null variables out. */\r      CurrentSetSize = 0;\r    EngineHandle = 0;\r      memset(ref, 0, sizeof(EventHandler*) * MAX_DESCRIPTORS);\r}\r\rIOCPEngine::~IOCPEngine()\r{\r        CloseHandle(m_completionPort);\r}\r\rbool IOCPEngine::AddFd(EventHandler* eh)\r{\r   int fake_fd = GenerateFd(eh->GetFd());\r int is_accept = 0;\r     int opt_len = sizeof(int);\r     if(fake_fd < 0)\r                return false;\r\r /* are we a listen socket? */\r  getsockopt(eh->GetFd(), SOL_SOCKET, SO_ACCEPTCONN, (char*)&is_accept, &opt_len);\r\r      /* set up the read event so the socket can actually receive data :P */\r eh->m_internalFd = fake_fd;\r    eh->m_writeEvent = 0;\r  eh->m_acceptEvent = 0;\r\r        unsigned long completion_key = (ULONG_PTR)eh->m_internalFd;\r    /* assign the socket to the completion port */\r if(!CreateIoCompletionPort((HANDLE)eh->GetFd(), m_completionPort, completion_key, 0))\r          return false;\r\r /* set up binding, increase set size */\r        ref[fake_fd] = eh;\r     ++CurrentSetSize;\r\r     /* setup initial events */\r     if(is_accept)\r          PostAcceptEvent(eh);\r   else\r           PostReadEvent(eh);\r\r    /* log message */\r      ServerInstance->Log(DEBUG, "New fake fd: %u, real fd: %u, address 0x%p", fake_fd, eh->GetFd(), eh);\r\r   /* post a write event if there is data to be written */\r        if(eh->Writeable())\r            WantWrite(eh);\r\r        /* we're all good =) */\r        try\r    {\r              m_binding.insert( map<int, EventHandler*>::value_type( eh->GetFd(), eh ) );\r    }\r      catch (...)\r    {\r              /* Ohshi-, map::insert failed :/ */\r            return false;\r  }\r\r     return true;\r}\r\rbool IOCPEngine::DelFd(EventHandler* eh, bool force /* = false */)\r{\r   int fake_fd = eh->m_internalFd;\r        int fd = eh->GetFd();\r  \r       if(ref[fake_fd] == 0)\r          return false;\r\r ServerInstance->Log(DEBUG, "Removing fake fd %u, real fd %u, address 0x%p", fake_fd, eh->GetFd(), eh);\r\r        /* Cancel pending i/o operations. */\r   if (CancelIo((HANDLE)fd) == FALSE)\r             return false;\r\r /* Free the buffer, and delete the event. */\r   if(eh->m_readEvent != 0)\r       {\r              if(((Overlapped*)eh->m_readEvent)->m_params != 0)\r                      delete ((udp_overlap*)((Overlapped*)eh->m_readEvent)->m_params);\r\r              delete ((Overlapped*)eh->m_readEvent);\r }\r\r     if(eh->m_writeEvent != 0)\r              delete ((Overlapped*)eh->m_writeEvent);\r\r       if(eh->m_acceptEvent != 0)\r     {\r              delete ((accept_overlap*)((Overlapped*)eh->m_acceptEvent)->m_params);\r          delete ((Overlapped*)eh->m_acceptEvent);\r       }\r\r     /* Clear binding */\r    ref[fake_fd] = 0;\r      m_binding.erase(eh->GetFd());\r\r /* decrement set size */\r       --CurrentSetSize;\r      \r       /* success */\r  return true;\r}\r\rvoid IOCPEngine::WantWrite(EventHandler* eh)\r{\r /* Post event - write begin */\r if(!eh->m_writeEvent)\r  {\r              ULONG_PTR completion_key = (ULONG_PTR)eh->m_internalFd;\r                Overlapped * ov = new Overlapped(SOCKET_IO_EVENT_WRITE_READY, 0);\r              eh->m_writeEvent = (void*)ov;\r          PostQueuedCompletionStatus(m_completionPort, 0, completion_key, &ov->m_overlap);\r       }\r}\r\rbool IOCPEngine::PostCompletionEvent(EventHandler * eh, SocketIOEvent type, int param)\r{\r  Overlapped * ov = new Overlapped(type, param);\r ULONG_PTR completion_key = (ULONG_PTR)eh->m_internalFd;\r        return PostQueuedCompletionStatus(m_completionPort, 0, completion_key, &ov->m_overlap);\r}\r\rvoid IOCPEngine::PostReadEvent(EventHandler * eh)\r{\r Overlapped * ov = new Overlapped(SOCKET_IO_EVENT_READ_READY, 0);\r       DWORD flags = 0;\r       DWORD r_length = 0;\r    WSABUF buf;\r\r   /* by passing a null buffer pointer, we can have this working in the same way as epoll..\r        * its slower, but it saves modifying all network code.\r         */\r    buf.buf = 0;\r   buf.len = 0;\r\r  /* determine socket type. */\r   DWORD sock_type;\r       int sock_len = sizeof(DWORD);\r  if(getsockopt(eh->GetFd(), SOL_SOCKET, SO_TYPE, (char*)&sock_type, &sock_len) == -1)\r   {\r              /* wtfhax? */\r          PostCompletionEvent(eh, SOCKET_IO_EVENT_ERROR, 0);\r             delete ov;\r             return;\r        }\r      switch(sock_type)\r      {\r              case SOCK_DGRAM:                        /* UDP Socket */\r               {\r                      udp_overlap * uv = new udp_overlap;\r                    uv->udp_sockaddr_len = sizeof(sockaddr);\r                       buf.buf = (char*)uv->udp_buffer;\r                       buf.len = sizeof(uv->udp_buffer);\r                      ov->m_params = (unsigned long)uv;\r                      if(WSARecvFrom(eh->GetFd(), &buf, 1, &uv->udp_len, &flags, uv->udp_sockaddr, (LPINT)&uv->udp_sockaddr_len, &ov->m_overlap, 0))\r                 {\r                              int err = WSAGetLastError();\r                           if(err != WSA_IO_PENDING)\r                              {\r                                      delete ov;\r                                     PostCompletionEvent(eh, SOCKET_IO_EVENT_ERROR, 0);\r                                     return;\r                                }\r                      }\r              }\r              break;\r\r                case SOCK_STREAM:                       /* TCP Socket */\r               {\r                      if(WSARecv(eh->GetFd(), &buf, 1, &r_length, &flags, &ov->m_overlap, 0) == SOCKET_ERROR)\r                        {\r                              if(WSAGetLastError() != WSA_IO_PENDING)\r                                {\r                                      delete ov;\r                                     PostCompletionEvent(eh, SOCKET_IO_EVENT_ERROR, 0);\r                                     return;\r                                }\r                      }\r              }\r              break;\r\r                default:\r               {\r                      printf("unknwon socket type: %u\n", sock_type);\r                        return;\r                }\r              break;\r }\r      eh->m_readEvent = (void*)ov;\r}\r\rint IOCPEngine::DispatchEvents()\r{\r     DWORD len;\r     LPOVERLAPPED overlap;\r  Overlapped * ov;\r       EventHandler * eh;\r     ULONG_PTR intfd;\r       int ret;\r       unsigned long bytes_recv;\r\r     while(GetQueuedCompletionStatus(m_completionPort, &len, &intfd, &overlap, 1000))\r       {\r              // woot, we got an event on a socket :P\r                eh = ref[intfd];\r               ov = CONTAINING_RECORD(overlap, Overlapped, m_overlap);\r                if(eh == 0) continue;\r          switch(ov->m_event)\r            {\r                      case SOCKET_IO_EVENT_WRITE_READY:\r                      {\r                              eh->m_writeEvent = 0;\r                          eh->HandleEvent(EVENT_WRITE, 0);\r                       }\r                      break;\r\r                        case SOCKET_IO_EVENT_READ_READY:\r                       {\r                              if(ov->m_params)\r                               {\r                                      // if we had params, it means we are a udp socket with a udp_overlap pointer in this long.\r                                     udp_overlap * uv = (udp_overlap*)ov->m_params;\r                                 uv->udp_len = len;\r                                     this->udp_ov = uv;\r                                     eh->m_readEvent = 0;\r                                   eh->HandleEvent(EVENT_READ, 0);\r                                        this->udp_ov = 0;\r                                      delete uv;\r                                     PostReadEvent(eh);\r                             }\r                              else\r                           {\r                                      ret = ioctlsocket(eh->GetFd(), FIONREAD, &bytes_recv);\r                                 eh->m_readEvent = 0;\r                                   if(ret != 0 || bytes_recv == 0)\r                                        {\r                                              /* end of file */\r                                              PostCompletionEvent(eh, SOCKET_IO_EVENT_ERROR, EIO); /* Old macdonald had an error, EIEIO. */\r                                  }\r                                      else\r                                   {\r                                              eh->HandleEvent(EVENT_READ, 0);\r                                                PostReadEvent(eh);\r                                     }\r                              }\r                      }\r                      break;\r         \r                       case SOCKET_IO_EVENT_ACCEPT:\r                   {\r                              /* this is kinda messy.. :/ */\r                         eh->HandleEvent(EVENT_READ, ov->m_params);\r                             delete ((accept_overlap*)ov->m_params);\r                                eh->m_acceptEvent = 0;\r                         PostAcceptEvent(eh);\r                   }\r                      break;\r\r                        case SOCKET_IO_EVENT_ERROR:\r                    {\r                              eh->HandleEvent(EVENT_ERROR, ov->m_params);\r                    }\r                      break;\r         }\r              \r               delete ov;\r     }\r\r     return 0;\r}\r\rvoid IOCPEngine::PostAcceptEvent(EventHandler * eh)\r{\r     int fd = WSASocket(AF_INET, SOCK_STREAM, 0, 0, 0, WSA_FLAG_OVERLAPPED);\r        int len = sizeof(sockaddr_in) + 16;\r    DWORD dwBytes;\r accept_overlap* ao = new accept_overlap;\r       memset(ao->buf, 0, 1024);\r      ao->socket = fd;\r\r      Overlapped* ov = new Overlapped(SOCKET_IO_EVENT_ACCEPT, (int)ao);\r      eh->m_acceptEvent = (void*)ov;\r\r        if(AcceptEx(eh->GetFd(), fd, ao->buf, 0, len, len, &dwBytes, &ov->m_overlap) == FALSE)\r {\r              int err = WSAGetLastError();\r           if(err != WSA_IO_PENDING)\r              {\r                      printf("PostAcceptEvent err: %d\n", err);\r              }\r      }\r}\r\r\rstd::string IOCPEngine::GetName()\r{\r      return "iocp";\r}\r\rint __accept_socket(SOCKET s, sockaddr * addr, int * addrlen, void * acceptevent)\r{\r  Overlapped* ovl = (Overlapped*)acceptevent;\r    accept_overlap* ov = (accept_overlap*)ovl->m_params;\r\r  sockaddr_in* server_address = (sockaddr_in*)&ov->buf[10];\r      sockaddr_in* client_address = (sockaddr_in*)&ov->buf[38];\r\r     memcpy(addr, client_address, sizeof(sockaddr_in));\r     *addrlen = sizeof(sockaddr_in);\r\r       return ov->socket;\r}\r\rint __getsockname(SOCKET s, sockaddr * name, int * namelen, void * acceptevent)\r{\r        Overlapped* ovl = (Overlapped*)acceptevent;\r    accept_overlap* ov = (accept_overlap*)ovl->m_params;\r\r  sockaddr_in* server_address = (sockaddr_in*)&ov->buf[10];\r      sockaddr_in* client_address = (sockaddr_in*)&ov->buf[38];\r\r     memcpy(name, server_address, sizeof(sockaddr_in));\r     *namelen = sizeof(sockaddr_in);\r\r       return 0;\r}\r\rint __recvfrom(SOCKET s, char * buf, int len, int flags, struct sockaddr * from, int * fromlen, udp_overlap * ov)\r{\r       memcpy(buf, ov->udp_buffer, ov->udp_len);\r      memcpy(from, ov->udp_sockaddr, *fromlen);\r      return ov->udp_len;\r}\r\rEventHandler * IOCPEngine::GetRef(int fd)\r{\r     map<int, EventHandler*>::iterator itr = m_binding.find(fd);\r    return (itr == m_binding.end()) ? 0 : itr->second;\r}\r\rbool IOCPEngine::HasFd(int fd)\r{\r return (GetRef(fd) != 0);\r}\r\rEventHandler * IOCPEngine::GetIntRef(int fd)\r{\r    if(fd < 0 || fd > MAX_DESCRIPTORS)\r             return 0;\r      return ref[fd];\r}\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "socketengine_iocp.h"
+#include <mswsock.h>
+
+IOCPEngine::IOCPEngine(InspIRCd * Instance) : SocketEngine(Instance)
+{
+       /* Create completion port */
+       m_completionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, (ULONG_PTR)0, 0);
+
+       /* Null variables out. */
+       CurrentSetSize = 0;
+       EngineHandle = 0;
+       memset(ref, 0, sizeof(EventHandler*) * MAX_DESCRIPTORS);
+}
+
+IOCPEngine::~IOCPEngine()
+{
+       CloseHandle(m_completionPort);
+}
+
+bool IOCPEngine::AddFd(EventHandler* eh)
+{
+       int fake_fd = GenerateFd(eh->GetFd());
+       int is_accept = 0;
+       int opt_len = sizeof(int);
+       if(fake_fd < 0)
+               return false;
+
+       /* are we a listen socket? */
+       getsockopt(eh->GetFd(), SOL_SOCKET, SO_ACCEPTCONN, (char*)&is_accept, &opt_len);
+
+       /* set up the read event so the socket can actually receive data :P */
+       eh->m_internalFd = fake_fd;
+       eh->m_writeEvent = 0;
+       eh->m_acceptEvent = 0;
+
+       unsigned long completion_key = (ULONG_PTR)eh->m_internalFd;
+       /* assign the socket to the completion port */
+       if(!CreateIoCompletionPort((HANDLE)eh->GetFd(), m_completionPort, completion_key, 0))
+               return false;
+
+       /* set up binding, increase set size */
+       ref[fake_fd] = eh;
+       ++CurrentSetSize;
+
+       /* setup initial events */
+       if(is_accept)
+               PostAcceptEvent(eh);
+       else
+               PostReadEvent(eh);
+
+       /* log message */
+       ServerInstance->Log(DEBUG, "New fake fd: %u, real fd: %u, address 0x%p", fake_fd, eh->GetFd(), eh);
+
+       /* post a write event if there is data to be written */
+       if(eh->Writeable())
+               WantWrite(eh);
+
+       /* we're all good =) */
+       try
+       {
+               m_binding.insert( map<int, EventHandler*>::value_type( eh->GetFd(), eh ) );
+       }
+       catch (...)
+       {
+               /* Ohshi-, map::insert failed :/ */
+               return false;
+       }
+
+       return true;
+}
+
+bool IOCPEngine::DelFd(EventHandler* eh, bool force /* = false */)
+{
+       int fake_fd = eh->m_internalFd;
+       int fd = eh->GetFd();
+       
+       if(ref[fake_fd] == 0)
+               return false;
+
+       ServerInstance->Log(DEBUG, "Removing fake fd %u, real fd %u, address 0x%p", fake_fd, eh->GetFd(), eh);
+
+       /* Cancel pending i/o operations. */
+       if (CancelIo((HANDLE)fd) == FALSE)
+               return false;
+
+       /* Free the buffer, and delete the event. */
+       if(eh->m_readEvent != 0)
+       {
+               if(((Overlapped*)eh->m_readEvent)->m_params != 0)
+                       delete ((udp_overlap*)((Overlapped*)eh->m_readEvent)->m_params);
+
+               delete ((Overlapped*)eh->m_readEvent);
+       }
+
+       if(eh->m_writeEvent != 0)
+               delete ((Overlapped*)eh->m_writeEvent);
+
+       if(eh->m_acceptEvent != 0)
+       {
+               delete ((accept_overlap*)((Overlapped*)eh->m_acceptEvent)->m_params);
+               delete ((Overlapped*)eh->m_acceptEvent);
+       }
+
+       /* Clear binding */
+       ref[fake_fd] = 0;
+       m_binding.erase(eh->GetFd());
+
+       /* decrement set size */
+       --CurrentSetSize;
+       
+       /* success */
+       return true;
+}
+
+void IOCPEngine::WantWrite(EventHandler* eh)
+{
+       /* Post event - write begin */
+       if(!eh->m_writeEvent)
+       {
+               ULONG_PTR completion_key = (ULONG_PTR)eh->m_internalFd;
+               Overlapped * ov = new Overlapped(SOCKET_IO_EVENT_WRITE_READY, 0);
+               eh->m_writeEvent = (void*)ov;
+               PostQueuedCompletionStatus(m_completionPort, 0, completion_key, &ov->m_overlap);
+       }
+}
+
+bool IOCPEngine::PostCompletionEvent(EventHandler * eh, SocketIOEvent type, int param)
+{
+       Overlapped * ov = new Overlapped(type, param);
+       ULONG_PTR completion_key = (ULONG_PTR)eh->m_internalFd;
+       return PostQueuedCompletionStatus(m_completionPort, 0, completion_key, &ov->m_overlap);
+}
+
+void IOCPEngine::PostReadEvent(EventHandler * eh)
+{
+       Overlapped * ov = new Overlapped(SOCKET_IO_EVENT_READ_READY, 0);
+       DWORD flags = 0;
+       DWORD r_length = 0;
+       WSABUF buf;
+
+       /* by passing a null buffer pointer, we can have this working in the same way as epoll..
+        * its slower, but it saves modifying all network code.
+        */
+       buf.buf = 0;
+       buf.len = 0;
+
+       /* determine socket type. */
+       DWORD sock_type;
+       int sock_len = sizeof(DWORD);
+       if(getsockopt(eh->GetFd(), SOL_SOCKET, SO_TYPE, (char*)&sock_type, &sock_len) == -1)
+       {
+               /* wtfhax? */
+               PostCompletionEvent(eh, SOCKET_IO_EVENT_ERROR, 0);
+               delete ov;
+               return;
+       }
+       switch(sock_type)
+       {
+               case SOCK_DGRAM:                        /* UDP Socket */
+               {
+                       udp_overlap * uv = new udp_overlap;
+                       uv->udp_sockaddr_len = sizeof(sockaddr);
+                       buf.buf = (char*)uv->udp_buffer;
+                       buf.len = sizeof(uv->udp_buffer);
+                       ov->m_params = (unsigned long)uv;
+                       if(WSARecvFrom(eh->GetFd(), &buf, 1, &uv->udp_len, &flags, uv->udp_sockaddr, (LPINT)&uv->udp_sockaddr_len, &ov->m_overlap, 0))
+                       {
+                               int err = WSAGetLastError();
+                               if(err != WSA_IO_PENDING)
+                               {
+                                       delete ov;
+                                       PostCompletionEvent(eh, SOCKET_IO_EVENT_ERROR, 0);
+                                       return;
+                               }
+                       }
+               }
+               break;
+
+               case SOCK_STREAM:                       /* TCP Socket */
+               {
+                       if(WSARecv(eh->GetFd(), &buf, 1, &r_length, &flags, &ov->m_overlap, 0) == SOCKET_ERROR)
+                       {
+                               if(WSAGetLastError() != WSA_IO_PENDING)
+                               {
+                                       delete ov;
+                                       PostCompletionEvent(eh, SOCKET_IO_EVENT_ERROR, 0);
+                                       return;
+                               }
+                       }
+               }
+               break;
+
+               default:
+               {
+                       printf("unknwon socket type: %u\n", sock_type);
+                       return;
+               }
+               break;
+       }
+       eh->m_readEvent = (void*)ov;
+}
+
+int IOCPEngine::DispatchEvents()
+{
+       DWORD len;
+       LPOVERLAPPED overlap;
+       Overlapped * ov;
+       EventHandler * eh;
+       ULONG_PTR intfd;
+       int ret;
+       unsigned long bytes_recv;
+
+       while(GetQueuedCompletionStatus(m_completionPort, &len, &intfd, &overlap, 1000))
+       {
+               // woot, we got an event on a socket :P
+               eh = ref[intfd];
+               ov = CONTAINING_RECORD(overlap, Overlapped, m_overlap);
+               if(eh == 0) continue;
+               switch(ov->m_event)
+               {
+                       case SOCKET_IO_EVENT_WRITE_READY:
+                       {
+                               eh->m_writeEvent = 0;
+                               eh->HandleEvent(EVENT_WRITE, 0);
+                       }
+                       break;
+
+                       case SOCKET_IO_EVENT_READ_READY:
+                       {
+                               if(ov->m_params)
+                               {
+                                       // if we had params, it means we are a udp socket with a udp_overlap pointer in this long.
+                                       udp_overlap * uv = (udp_overlap*)ov->m_params;
+                                       uv->udp_len = len;
+                                       this->udp_ov = uv;
+                                       eh->m_readEvent = 0;
+                                       eh->HandleEvent(EVENT_READ, 0);
+                                       this->udp_ov = 0;
+                                       delete uv;
+                                       PostReadEvent(eh);
+                               }
+                               else
+                               {
+                                       ret = ioctlsocket(eh->GetFd(), FIONREAD, &bytes_recv);
+                                       eh->m_readEvent = 0;
+                                       if(ret != 0 || bytes_recv == 0)
+                                       {
+                                               /* end of file */
+                                               PostCompletionEvent(eh, SOCKET_IO_EVENT_ERROR, EIO); /* Old macdonald had an error, EIEIO. */
+                                       }
+                                       else
+                                       {
+                                               eh->HandleEvent(EVENT_READ, 0);
+                                               PostReadEvent(eh);
+                                       }
+                               }
+                       }
+                       break;
+               
+                       case SOCKET_IO_EVENT_ACCEPT:
+                       {
+                               /* this is kinda messy.. :/ */
+                               eh->HandleEvent(EVENT_READ, ov->m_params);
+                               delete ((accept_overlap*)ov->m_params);
+                               eh->m_acceptEvent = 0;
+                               PostAcceptEvent(eh);
+                       }
+                       break;
+
+                       case SOCKET_IO_EVENT_ERROR:
+                       {
+                               eh->HandleEvent(EVENT_ERROR, ov->m_params);
+                       }
+                       break;
+               }
+               
+               delete ov;
+       }
+
+       return 0;
+}
+
+void IOCPEngine::PostAcceptEvent(EventHandler * eh)
+{
+       int fd = WSASocket(AF_INET, SOCK_STREAM, 0, 0, 0, WSA_FLAG_OVERLAPPED);
+       int len = sizeof(sockaddr_in) + 16;
+       DWORD dwBytes;
+       accept_overlap* ao = new accept_overlap;
+       memset(ao->buf, 0, 1024);
+       ao->socket = fd;
+
+       Overlapped* ov = new Overlapped(SOCKET_IO_EVENT_ACCEPT, (int)ao);
+       eh->m_acceptEvent = (void*)ov;
+
+       if(AcceptEx(eh->GetFd(), fd, ao->buf, 0, len, len, &dwBytes, &ov->m_overlap) == FALSE)
+       {
+               int err = WSAGetLastError();
+               if(err != WSA_IO_PENDING)
+               {
+                       printf("PostAcceptEvent err: %d\n", err);
+               }
+       }
+}
+
+
+std::string IOCPEngine::GetName()
+{
+       return "iocp";
+}
+
+int __accept_socket(SOCKET s, sockaddr * addr, int * addrlen, void * acceptevent)
+{
+       Overlapped* ovl = (Overlapped*)acceptevent;
+       accept_overlap* ov = (accept_overlap*)ovl->m_params;
+
+       sockaddr_in* server_address = (sockaddr_in*)&ov->buf[10];
+       sockaddr_in* client_address = (sockaddr_in*)&ov->buf[38];
+
+       memcpy(addr, client_address, sizeof(sockaddr_in));
+       *addrlen = sizeof(sockaddr_in);
+
+       return ov->socket;
+}
+
+int __getsockname(SOCKET s, sockaddr * name, int * namelen, void * acceptevent)
+{
+       Overlapped* ovl = (Overlapped*)acceptevent;
+       accept_overlap* ov = (accept_overlap*)ovl->m_params;
+
+       sockaddr_in* server_address = (sockaddr_in*)&ov->buf[10];
+       sockaddr_in* client_address = (sockaddr_in*)&ov->buf[38];
+
+       memcpy(name, server_address, sizeof(sockaddr_in));
+       *namelen = sizeof(sockaddr_in);
+
+       return 0;
+}
+
+int __recvfrom(SOCKET s, char * buf, int len, int flags, struct sockaddr * from, int * fromlen, udp_overlap * ov)
+{
+       memcpy(buf, ov->udp_buffer, ov->udp_len);
+       memcpy(from, ov->udp_sockaddr, *fromlen);
+       return ov->udp_len;
+}
+
+EventHandler * IOCPEngine::GetRef(int fd)
+{
+       map<int, EventHandler*>::iterator itr = m_binding.find(fd);
+       return (itr == m_binding.end()) ? 0 : itr->second;
+}
+
+bool IOCPEngine::HasFd(int fd)
+{
+       return (GetRef(fd) != 0);
+}
+
+EventHandler * IOCPEngine::GetIntRef(int fd)
+{
+       if(fd < 0 || fd > MAX_DESCRIPTORS)
+               return 0;
+       return ref[fd];
+}
+
index de9a78f4efdf3114eb4309addfc6f569a8bdbec5..7fcdae2b6a58084056cb25268e9b2e1365fb253a 100644 (file)
@@ -1 +1,158 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "exitcodes.h"\r#include <sys/types.h>\r#include <sys/event.h>\r#include <sys/time.h>\r#include "socketengine_kqueue.h"\r\r\rKQueueEngine::KQueueEngine(InspIRCd* Instance) : SocketEngine(Instance)\r{\r     EngineHandle = kqueue();\r       if (EngineHandle == -1)\r        {\r              ServerInstance->Log(SPARSE,"ERROR: Could not initialize socket engine. Your kernel probably does not have the proper features.");\r              ServerInstance->Log(SPARSE,"ERROR: this is a fatal error, exiting now.");\r              printf("ERROR: Could not initialize socket engine. Your kernel probably does not have the proper features.");\r          printf("ERROR: this is a fatal error, exiting now.");\r          InspIRCd::Exit(EXIT_STATUS_SOCKETENGINE);\r      }\r      CurrentSetSize = 0;\r}\r\rKQueueEngine::~KQueueEngine()\r{\r close(EngineHandle);\r}\r\rbool KQueueEngine::AddFd(EventHandler* eh)\r{\r   int fd = eh->GetFd();\r\r if ((fd < 0) || (fd > MAX_DESCRIPTORS))\r                return false;\r\r if (GetRemainingFds() <= 1)\r            return false;\r\r if (ref[fd])\r           return false;\r\r ref[fd] = eh;\r\r struct kevent ke;\r      EV_SET(&ke, fd, eh->Readable() ? EVFILT_READ : EVFILT_WRITE, EV_ADD, 0, 0, NULL);\r\r     int i = kevent(EngineHandle, &ke, 1, 0, 0, NULL);\r      if (i == -1)\r           return false;\r\r CurrentSetSize++;\r\r     ServerInstance->Log(DEBUG,"New file descriptor: %d", fd);\r      return true;\r}\r\rbool KQueueEngine::DelFd(EventHandler* eh, bool force)\r{\r       int fd = eh->GetFd();\r\r if ((fd < 0) || (fd > MAX_DESCRIPTORS))\r                return false;\r\r struct kevent ke;\r      EV_SET(&ke, eh->GetFd(), EVFILT_READ, EV_DELETE, 0, 0, NULL);\r\r int i = kevent(EngineHandle, &ke, 1, 0, 0, NULL);\r\r     EV_SET(&ke, eh->GetFd(), EVFILT_WRITE, EV_DELETE, 0, 0, NULL);\r\r        int j = kevent(EngineHandle, &ke, 1, 0, 0, NULL);\r\r     if ((j < 0) && (i < 0) && !force)\r              return false;\r\r CurrentSetSize--;\r      ref[fd] = NULL;\r\r       ServerInstance->Log(DEBUG,"Remove file descriptor: %d", fd);\r   return true;\r}\r\rvoid KQueueEngine::WantWrite(EventHandler* eh)\r{\r       /** When changing an item in a kqueue, there is no 'modify' call\r        * as in epoll. Instead, we add the item again, and this overwrites\r     * the original setting rather than adding it twice. See man kqueue.\r    */\r    struct kevent ke;\r      EV_SET(&ke, eh->GetFd(), EVFILT_WRITE, EV_ADD | EV_ONESHOT, 0, 0, NULL);\r       kevent(EngineHandle, &ke, 1, 0, 0, NULL);\r}\r\rint KQueueEngine::GetMaxFds()\r{\r   return MAX_DESCRIPTORS;\r}\r\rint KQueueEngine::GetRemainingFds()\r{\r       return MAX_DESCRIPTORS - CurrentSetSize;\r}\r\rint KQueueEngine::DispatchEvents()\r{\r       ts.tv_nsec = 0;\r        ts.tv_sec = 1;\r int i = kevent(EngineHandle, NULL, 0, &ke_list[0], MAX_DESCRIPTORS, &ts);\r      for (int j = 0; j < i; j++)\r    {\r              if (ke_list[j].flags & EV_EOF)\r         {\r                      /* We love you kqueue, oh yes we do *sings*!\r                    * kqueue gives us the error number directly in the EOF state!\r                  * Unlike smelly epoll and select, where we have to getsockopt\r                  * to get the error, this saves us time and cpu cycles. Go BSD!\r                         */\r                    if (ref[ke_list[j].ident])\r                             ref[ke_list[j].ident]->HandleEvent(EVENT_ERROR, ke_list[j].fflags);\r                    continue;\r              }\r              if (ke_list[j].flags & EVFILT_WRITE)\r           {\r                      /* This looks wrong but its right. As above, theres no modify\r                   * call in kqueue. See the manpage.\r                     */\r                    struct kevent ke;\r                      EV_SET(&ke, ke_list[j].ident, EVFILT_READ, EV_ADD, 0, 0, NULL);\r                        kevent(EngineHandle, &ke, 1, 0, 0, NULL);\r                      if (ref[ke_list[j].ident])\r                             ref[ke_list[j].ident]->HandleEvent(EVENT_WRITE);\r               }\r              else\r           {\r                      if (ref[ke_list[j].ident])\r                             ref[ke_list[j].ident]->HandleEvent(EVENT_READ);\r                }\r      }\r\r     return i;\r}\r\rstd::string KQueueEngine::GetName()\r{\r     return "kqueue";\r}\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "exitcodes.h"
+#include <sys/types.h>
+#include <sys/event.h>
+#include <sys/time.h>
+#include "socketengine_kqueue.h"
+
+
+KQueueEngine::KQueueEngine(InspIRCd* Instance) : SocketEngine(Instance)
+{
+       EngineHandle = kqueue();
+       if (EngineHandle == -1)
+       {
+               ServerInstance->Log(SPARSE,"ERROR: Could not initialize socket engine. Your kernel probably does not have the proper features.");
+               ServerInstance->Log(SPARSE,"ERROR: this is a fatal error, exiting now.");
+               printf("ERROR: Could not initialize socket engine. Your kernel probably does not have the proper features.");
+               printf("ERROR: this is a fatal error, exiting now.");
+               InspIRCd::Exit(EXIT_STATUS_SOCKETENGINE);
+       }
+       CurrentSetSize = 0;
+}
+
+KQueueEngine::~KQueueEngine()
+{
+       close(EngineHandle);
+}
+
+bool KQueueEngine::AddFd(EventHandler* eh)
+{
+       int fd = eh->GetFd();
+
+       if ((fd < 0) || (fd > MAX_DESCRIPTORS))
+               return false;
+
+       if (GetRemainingFds() <= 1)
+               return false;
+
+       if (ref[fd])
+               return false;
+
+       ref[fd] = eh;
+
+       struct kevent ke;
+       EV_SET(&ke, fd, eh->Readable() ? EVFILT_READ : EVFILT_WRITE, EV_ADD, 0, 0, NULL);
+
+       int i = kevent(EngineHandle, &ke, 1, 0, 0, NULL);
+       if (i == -1)
+               return false;
+
+       CurrentSetSize++;
+
+       ServerInstance->Log(DEBUG,"New file descriptor: %d", fd);
+       return true;
+}
+
+bool KQueueEngine::DelFd(EventHandler* eh, bool force)
+{
+       int fd = eh->GetFd();
+
+       if ((fd < 0) || (fd > MAX_DESCRIPTORS))
+               return false;
+
+       struct kevent ke;
+       EV_SET(&ke, eh->GetFd(), EVFILT_READ, EV_DELETE, 0, 0, NULL);
+
+       int i = kevent(EngineHandle, &ke, 1, 0, 0, NULL);
+
+       EV_SET(&ke, eh->GetFd(), EVFILT_WRITE, EV_DELETE, 0, 0, NULL);
+
+       int j = kevent(EngineHandle, &ke, 1, 0, 0, NULL);
+
+       if ((j < 0) && (i < 0) && !force)
+               return false;
+
+       CurrentSetSize--;
+       ref[fd] = NULL;
+
+       ServerInstance->Log(DEBUG,"Remove file descriptor: %d", fd);
+       return true;
+}
+
+void KQueueEngine::WantWrite(EventHandler* eh)
+{
+       /** When changing an item in a kqueue, there is no 'modify' call
+        * as in epoll. Instead, we add the item again, and this overwrites
+        * the original setting rather than adding it twice. See man kqueue.
+        */
+       struct kevent ke;
+       EV_SET(&ke, eh->GetFd(), EVFILT_WRITE, EV_ADD | EV_ONESHOT, 0, 0, NULL);
+       kevent(EngineHandle, &ke, 1, 0, 0, NULL);
+}
+
+int KQueueEngine::GetMaxFds()
+{
+       return MAX_DESCRIPTORS;
+}
+
+int KQueueEngine::GetRemainingFds()
+{
+       return MAX_DESCRIPTORS - CurrentSetSize;
+}
+
+int KQueueEngine::DispatchEvents()
+{
+       ts.tv_nsec = 0;
+       ts.tv_sec = 1;
+       int i = kevent(EngineHandle, NULL, 0, &ke_list[0], MAX_DESCRIPTORS, &ts);
+       for (int j = 0; j < i; j++)
+       {
+               if (ke_list[j].flags & EV_EOF)
+               {
+                       /* We love you kqueue, oh yes we do *sings*!
+                        * kqueue gives us the error number directly in the EOF state!
+                        * Unlike smelly epoll and select, where we have to getsockopt
+                        * to get the error, this saves us time and cpu cycles. Go BSD!
+                        */
+                       if (ref[ke_list[j].ident])
+                               ref[ke_list[j].ident]->HandleEvent(EVENT_ERROR, ke_list[j].fflags);
+                       continue;
+               }
+               if (ke_list[j].flags & EVFILT_WRITE)
+               {
+                       /* This looks wrong but its right. As above, theres no modify
+                        * call in kqueue. See the manpage.
+                        */
+                       struct kevent ke;
+                       EV_SET(&ke, ke_list[j].ident, EVFILT_READ, EV_ADD, 0, 0, NULL);
+                       kevent(EngineHandle, &ke, 1, 0, 0, NULL);
+                       if (ref[ke_list[j].ident])
+                               ref[ke_list[j].ident]->HandleEvent(EVENT_WRITE);
+               }
+               else
+               {
+                       if (ref[ke_list[j].ident])
+                               ref[ke_list[j].ident]->HandleEvent(EVENT_READ);
+               }
+       }
+
+       return i;
+}
+
+std::string KQueueEngine::GetName()
+{
+       return "kqueue";
+}
index d3704f0a461babee6535f307d1218cefb4251cdd..869e0a6fb3876b8f406c170f4e4d21f1df2ce517 100644 (file)
@@ -1 +1,129 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "exitcodes.h"\r#include <port.h>\r#include "socketengine_ports.h"\r\rPortsEngine::PortsEngine(InspIRCd* Instance) : SocketEngine(Instance)\r{\r   EngineHandle = port_create();\r\r if (EngineHandle == -1)\r        {\r              ServerInstance->Log(SPARSE,"ERROR: Could not initialize socket engine: %s", strerror(errno));\r          ServerInstance->Log(SPARSE,"ERROR: This is a fatal error, exiting now.");\r              printf("ERROR: Could not initialize socket engine: %s\n", strerror(errno));\r            printf("ERROR: This is a fatal error, exiting now.\n");\r                InspIRCd::Exit(EXIT_STATUS_SOCKETENGINE);\r      }\r      CurrentSetSize = 0;\r}\r\rPortsEngine::~PortsEngine()\r{\r   close(EngineHandle);\r}\r\rbool PortsEngine::AddFd(EventHandler* eh)\r{\r    int fd = eh->GetFd();\r  if ((fd < 0) || (fd > MAX_DESCRIPTORS))\r                return false;\r\r if (GetRemainingFds() <= 1)\r            return false;\r\r if (ref[fd])\r           return false;\r\r ref[fd] = eh;\r  port_associate(EngineHandle, PORT_SOURCE_FD, fd, eh->Readable() ? POLLRDNORM : POLLWRNORM, eh);\r\r       ServerInstance->Log(DEBUG,"New file descriptor: %d", fd);\r      CurrentSetSize++;\r      return true;\r}\r\rvoid PortsEngine::WantWrite(EventHandler* eh)\r{\r        port_associate(EngineHandle, PORT_SOURCE_FD, eh->GetFd(), POLLWRNORM, eh);\r}\r\rbool PortsEngine::DelFd(EventHandler* eh, bool force)\r{\r  int fd = eh->GetFd();\r  if ((fd < 0) || (fd > MAX_DESCRIPTORS))\r                return false;\r\r port_dissociate(EngineHandle, PORT_SOURCE_FD, fd);\r\r    CurrentSetSize--;\r      ref[fd] = NULL;\r\r       ServerInstance->Log(DEBUG,"Remove file descriptor: %d", fd);\r   return true;\r}\r\rint PortsEngine::GetMaxFds()\r{\r return MAX_DESCRIPTORS;\r}\r\rint PortsEngine::GetRemainingFds()\r{\r        return MAX_DESCRIPTORS - CurrentSetSize;\r}\r\rint PortsEngine::DispatchEvents()\r{\r        struct timespec poll_time;\r\r    poll_time.tv_sec = 1;\r  poll_time.tv_nsec = 0;\r\r        unsigned int nget = 1; // used to denote a retrieve request.\r   int i = port_getn(EngineHandle, this->events, MAX_DESCRIPTORS, &nget, &poll_time);\r\r    // first handle an error condition\r     if (i == -1)\r           return i;\r\r     for (i = 0; i < nget; i++)\r     {\r              switch (this->events[i].portev_source)\r         {\r                      case PORT_SOURCE_FD:\r                   {\r                              int fd = this->events[i].portev_object;\r                                if (ref[fd])\r                           {\r                                      // reinsert port for next time around\r                                  port_associate(EngineHandle, PORT_SOURCE_FD, fd, POLLRDNORM, ref[fd]);\r                                 ref[fd]->HandleEvent((this->events[i].portev_events & POLLRDNORM) ? EVENT_READ : EVENT_WRITE);\r                         }\r                      }\r                      default:\r                       break;\r         }\r      }\r\r     return i;\r}\r\rstd::string PortsEngine::GetName()\r{\r      return "ports";\r}\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "exitcodes.h"
+#include <port.h>
+#include "socketengine_ports.h"
+
+PortsEngine::PortsEngine(InspIRCd* Instance) : SocketEngine(Instance)
+{
+       EngineHandle = port_create();
+
+       if (EngineHandle == -1)
+       {
+               ServerInstance->Log(SPARSE,"ERROR: Could not initialize socket engine: %s", strerror(errno));
+               ServerInstance->Log(SPARSE,"ERROR: This is a fatal error, exiting now.");
+               printf("ERROR: Could not initialize socket engine: %s\n", strerror(errno));
+               printf("ERROR: This is a fatal error, exiting now.\n");
+               InspIRCd::Exit(EXIT_STATUS_SOCKETENGINE);
+       }
+       CurrentSetSize = 0;
+}
+
+PortsEngine::~PortsEngine()
+{
+       close(EngineHandle);
+}
+
+bool PortsEngine::AddFd(EventHandler* eh)
+{
+       int fd = eh->GetFd();
+       if ((fd < 0) || (fd > MAX_DESCRIPTORS))
+               return false;
+
+       if (GetRemainingFds() <= 1)
+               return false;
+
+       if (ref[fd])
+               return false;
+
+       ref[fd] = eh;
+       port_associate(EngineHandle, PORT_SOURCE_FD, fd, eh->Readable() ? POLLRDNORM : POLLWRNORM, eh);
+
+       ServerInstance->Log(DEBUG,"New file descriptor: %d", fd);
+       CurrentSetSize++;
+       return true;
+}
+
+void PortsEngine::WantWrite(EventHandler* eh)
+{
+       port_associate(EngineHandle, PORT_SOURCE_FD, eh->GetFd(), POLLWRNORM, eh);
+}
+
+bool PortsEngine::DelFd(EventHandler* eh, bool force)
+{
+       int fd = eh->GetFd();
+       if ((fd < 0) || (fd > MAX_DESCRIPTORS))
+               return false;
+
+       port_dissociate(EngineHandle, PORT_SOURCE_FD, fd);
+
+       CurrentSetSize--;
+       ref[fd] = NULL;
+
+       ServerInstance->Log(DEBUG,"Remove file descriptor: %d", fd);
+       return true;
+}
+
+int PortsEngine::GetMaxFds()
+{
+       return MAX_DESCRIPTORS;
+}
+
+int PortsEngine::GetRemainingFds()
+{
+       return MAX_DESCRIPTORS - CurrentSetSize;
+}
+
+int PortsEngine::DispatchEvents()
+{
+       struct timespec poll_time;
+
+       poll_time.tv_sec = 1;
+       poll_time.tv_nsec = 0;
+
+       unsigned int nget = 1; // used to denote a retrieve request.
+       int i = port_getn(EngineHandle, this->events, MAX_DESCRIPTORS, &nget, &poll_time);
+
+       // first handle an error condition
+       if (i == -1)
+               return i;
+
+       for (i = 0; i < nget; i++)
+       {
+               switch (this->events[i].portev_source)
+               {
+                       case PORT_SOURCE_FD:
+                       {
+                               int fd = this->events[i].portev_object;
+                               if (ref[fd])
+                               {
+                                       // reinsert port for next time around
+                                       port_associate(EngineHandle, PORT_SOURCE_FD, fd, POLLRDNORM, ref[fd]);
+                                       ref[fd]->HandleEvent((this->events[i].portev_events & POLLRDNORM) ? EVENT_READ : EVENT_WRITE);
+                               }
+                       }
+                       default:
+                       break;
+               }
+       }
+
+       return i;
+}
+
+std::string PortsEngine::GetName()
+{
+       return "ports";
+}
+
index 73e909193b597deb9c0d882576d485bf932621c1..ef5f2071f82aa2853f9cab99e4435daf36a23db0 100644 (file)
@@ -1 +1,167 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include <sys/select.h>\r#include "socketengine_select.h"\r\r\rSelectEngine::SelectEngine(InspIRCd* Instance) : SocketEngine(Instance)\r{\r        EngineHandle = 0;\r      CurrentSetSize = 0;\r    memset(writeable, 0, sizeof(writeable));\r}\r\rSelectEngine::~SelectEngine()\r{\r}\r\rbool SelectEngine::AddFd(EventHandler* eh)\r{\r    int fd = eh->GetFd();\r  if ((fd < 0) || (fd > MAX_DESCRIPTORS))\r                return false;\r\r if (GetRemainingFds() <= 1)\r            return false;\r\r fds[fd] = fd;\r\r if (ref[fd])\r           return false;\r\r ref[fd] = eh;\r\r CurrentSetSize++;\r\r     ServerInstance->Log(DEBUG,"New file descriptor: %d", fd);\r      return true;\r}\r\rvoid SelectEngine::WantWrite(EventHandler* eh)\r{\r       writeable[eh->GetFd()] = true;\r}\r\rbool SelectEngine::DelFd(EventHandler* eh, bool force)\r{\r     int fd = eh->GetFd();\r\r if ((fd < 0) || (fd > MAX_DESCRIPTORS))\r                return false;\r\r std::map<int,int>::iterator t = fds.find(fd);\r  if (t != fds.end())\r            fds.erase(t);\r\r CurrentSetSize--;\r      ref[fd] = NULL;\r\r       ServerInstance->Log(DEBUG,"Remove file descriptor: %d", fd);\r   return true;\r}\r\rint SelectEngine::GetMaxFds()\r{\r        return FD_SETSIZE;\r}\r\rint SelectEngine::GetRemainingFds()\r{\r    return FD_SETSIZE - CurrentSetSize;\r}\r\rint SelectEngine::DispatchEvents()\r{\r    int result = 0;\r        timeval tval;\r  int sresult = 0;\r       EventHandler* ev[MAX_DESCRIPTORS];\r     socklen_t codesize;\r    int errcode;\r\r  FD_ZERO(&wfdset);\r      FD_ZERO(&rfdset);\r      FD_ZERO(&errfdset);\r\r   for (std::map<int,int>::iterator a = fds.begin(); a != fds.end(); a++)\r {\r              if (ref[a->second]->Readable())\r                        FD_SET (a->second, &rfdset);\r           else\r                   FD_SET (a->second, &wfdset);\r           if (writeable[a->second])\r                      FD_SET (a->second, &wfdset);\r\r          FD_SET (a->second, &errfdset);\r }\r      tval.tv_sec = 1;\r       tval.tv_usec = 0;\r      sresult = select(FD_SETSIZE, &rfdset, &wfdset, &errfdset, &tval);\r      if (sresult > 0)\r       {\r              for (std::map<int,int>::iterator a = fds.begin(); a != fds.end(); a++)\r         {\r                      if ((FD_ISSET (a->second, &rfdset)) || (FD_ISSET (a->second, &wfdset)) || FD_ISSET (a->second, &errfdset))\r                     {\r                              ev[result++] = ref[a->second];\r                 }\r              }\r      }\r\r     /** An event handler may remove its own descriptor from the list, therefore it is not\r   * safe to directly iterate over the list and dispatch events there with STL iterators.\r         * Thats a shame because it makes this code slower and more resource intensive, but maybe\r       * the user should stop using select(), as select() smells anyway.\r      */\r    for (int i = 0; i < result; i++)\r       {\r              if (ev[i])\r             {\r                      if (FD_ISSET (ev[i]->GetFd(), &errfdset))\r                      {\r                              if (ev[i])\r                             {\r                                      if (getsockopt(ev[i]->GetFd(), SOL_SOCKET, SO_ERROR, &errcode, &codesize) < 0)\r                                         errcode = errno;\r\r                                      ev[i]->HandleEvent(EVENT_ERROR, errcode);\r                              }\r                              continue;\r                      }\r                      if (ev[i])\r                     {\r                              if (writeable[ev[i]->GetFd()])\r                         {\r                                      if (ev[i])\r                                             ev[i]->HandleEvent(EVENT_WRITE);\r                                       writeable[ev[i]->GetFd()] = false;\r\r                            }\r                              else\r                           {\r                                      if (ev[i])\r                                             ev[i]->HandleEvent(ev[i]->Readable() ? EVENT_READ : EVENT_WRITE);\r                              }\r                      }\r              }\r      }\r\r     return result;\r}\r\rstd::string SelectEngine::GetName()\r{\r        return "select";\r}\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include <sys/select.h>
+#include "socketengine_select.h"
+
+
+SelectEngine::SelectEngine(InspIRCd* Instance) : SocketEngine(Instance)
+{
+       EngineHandle = 0;
+       CurrentSetSize = 0;
+       memset(writeable, 0, sizeof(writeable));
+}
+
+SelectEngine::~SelectEngine()
+{
+}
+
+bool SelectEngine::AddFd(EventHandler* eh)
+{
+       int fd = eh->GetFd();
+       if ((fd < 0) || (fd > MAX_DESCRIPTORS))
+               return false;
+
+       if (GetRemainingFds() <= 1)
+               return false;
+
+       fds[fd] = fd;
+
+       if (ref[fd])
+               return false;
+
+       ref[fd] = eh;
+
+       CurrentSetSize++;
+
+       ServerInstance->Log(DEBUG,"New file descriptor: %d", fd);
+       return true;
+}
+
+void SelectEngine::WantWrite(EventHandler* eh)
+{
+       writeable[eh->GetFd()] = true;
+}
+
+bool SelectEngine::DelFd(EventHandler* eh, bool force)
+{
+       int fd = eh->GetFd();
+
+       if ((fd < 0) || (fd > MAX_DESCRIPTORS))
+               return false;
+
+       std::map<int,int>::iterator t = fds.find(fd);
+       if (t != fds.end())
+               fds.erase(t);
+
+       CurrentSetSize--;
+       ref[fd] = NULL;
+
+       ServerInstance->Log(DEBUG,"Remove file descriptor: %d", fd);
+       return true;
+}
+
+int SelectEngine::GetMaxFds()
+{
+       return FD_SETSIZE;
+}
+
+int SelectEngine::GetRemainingFds()
+{
+       return FD_SETSIZE - CurrentSetSize;
+}
+
+int SelectEngine::DispatchEvents()
+{
+       int result = 0;
+       timeval tval;
+       int sresult = 0;
+       EventHandler* ev[MAX_DESCRIPTORS];
+       socklen_t codesize;
+       int errcode;
+
+       FD_ZERO(&wfdset);
+       FD_ZERO(&rfdset);
+       FD_ZERO(&errfdset);
+
+       for (std::map<int,int>::iterator a = fds.begin(); a != fds.end(); a++)
+       {
+               if (ref[a->second]->Readable())
+                       FD_SET (a->second, &rfdset);
+               else
+                       FD_SET (a->second, &wfdset);
+               if (writeable[a->second])
+                       FD_SET (a->second, &wfdset);
+
+               FD_SET (a->second, &errfdset);
+       }
+       tval.tv_sec = 1;
+       tval.tv_usec = 0;
+       sresult = select(FD_SETSIZE, &rfdset, &wfdset, &errfdset, &tval);
+       if (sresult > 0)
+       {
+               for (std::map<int,int>::iterator a = fds.begin(); a != fds.end(); a++)
+               {
+                       if ((FD_ISSET (a->second, &rfdset)) || (FD_ISSET (a->second, &wfdset)) || FD_ISSET (a->second, &errfdset))
+                       {
+                               ev[result++] = ref[a->second];
+                       }
+               }
+       }
+
+       /** An event handler may remove its own descriptor from the list, therefore it is not
+        * safe to directly iterate over the list and dispatch events there with STL iterators.
+        * Thats a shame because it makes this code slower and more resource intensive, but maybe
+        * the user should stop using select(), as select() smells anyway.
+        */
+       for (int i = 0; i < result; i++)
+       {
+               if (ev[i])
+               {
+                       if (FD_ISSET (ev[i]->GetFd(), &errfdset))
+                       {
+                               if (ev[i])
+                               {
+                                       if (getsockopt(ev[i]->GetFd(), SOL_SOCKET, SO_ERROR, &errcode, &codesize) < 0)
+                                               errcode = errno;
+
+                                       ev[i]->HandleEvent(EVENT_ERROR, errcode);
+                               }
+                               continue;
+                       }
+                       if (ev[i])
+                       {
+                               if (writeable[ev[i]->GetFd()])
+                               {
+                                       if (ev[i])
+                                               ev[i]->HandleEvent(EVENT_WRITE);
+                                       writeable[ev[i]->GetFd()] = false;
+
+                               }
+                               else
+                               {
+                                       if (ev[i])
+                                               ev[i]->HandleEvent(ev[i]->Readable() ? EVENT_READ : EVENT_WRITE);
+                               }
+                       }
+               }
+       }
+
+       return result;
+}
+
+std::string SelectEngine::GetName()
+{
+       return "select";
+}
index 90cf8bd958c14e92545286f028af0bcf410200b3..c041075025321e04fc5aa8cd8b2e20fb64a11fc3 100644 (file)
@@ -1 +1,135 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "timer.h"\r\rTimerManager::TimerManager(InspIRCd* Instance) : CantDeleteHere(false), ServerInstance(Instance)\r{\r}\r\rvoid TimerManager::TickTimers(time_t TIME)\r{\r      this->CantDeleteHere = true;\r   timerlist::iterator found = Timers.find(TIME);\r\r        if (found != Timers.end())\r     {\r              timergroup* x = found->second;\r         /* There are pending timers to trigger.\r                 * WARNING: Timers may delete themselves from within\r            * their own Tick methods! see the comment below in\r             * the DelTimer method.\r                 */\r            for (timergroup::iterator y = x->begin(); y != x->end(); y++)\r          {\r                      InspTimer* n = *y;\r                     n->Tick(TIME);\r                 if (n->GetRepeat())\r                    {\r                              AddTimer(n, n->GetSecs());\r                     }\r                      else\r                   {\r                              DELETE(n);\r                     }\r              }\r\r             Timers.erase(found);\r           DELETE(x);\r     }\r\r     this->CantDeleteHere = false;\r}\r\rvoid TimerManager::DelTimer(InspTimer* T)\r{\r   if (this->CantDeleteHere)\r      {\r              /* If a developer tries to delete a timer from within its own Tick method,\r              * then chances are this is just going to totally fuck over the timergroup\r              * and timerlist iterators and cause a crash. Thanks to peavey and Bricker\r              * for noticing this bug.\r               * If we're within the tick loop when the DelTimer is called (signified\r                 * by the var 'CantDeleteHere') then we simply return for non-repeating\r                 * timers, and cancel the repeat on repeating timers. We can do this because\r            * we know that the timer tick loop will safely delete the timer for us\r                 * anyway and therefore we avoid stack corruption.\r              */\r            if (T->GetRepeat())\r                    T->CancelRepeat();\r             else\r                   return;\r        }\r\r     timerlist::iterator found = Timers.find(T->GetTimer());\r\r       if (found != Timers.end())\r     {\r              timergroup* x = found->second;\r         for (timergroup::iterator y = x->begin(); y != x->end(); y++)\r          {\r                      InspTimer* n = *y;\r                     if (n == T)\r                    {\r                              DELETE(n);\r                             x->erase(y);\r                           if (!x->size())\r                                {\r                                      Timers.erase(found);\r                                   DELETE(x);\r                             }\r                              return;\r                        }\r              }\r      }\r}\r\r/** Because some muppets may do odd things, and their ircd may lock up due\r * to crappy 3rd party modules, or they may change their system time a bit,\r * this accounts for shifts of up to 120 secs by looking behind for missed\r * timers and executing them. This is only executed once every 5 secs.\r * If you move your clock BACK, and your timers move further ahead as a result,\r * then tough titty you'll just have to wait.\r */\rvoid TimerManager::TickMissedTimers(time_t TIME)\r{\r     for (time_t n = TIME-1; n > TIME-120; n--)\r             this->TickTimers(TIME);\r}\r\rvoid TimerManager::AddTimer(InspTimer* T, long secs_from_now)\r{\r     timergroup* x = NULL;\r\r int time_to_trigger = 0;\r       if (!secs_from_now)\r            time_to_trigger = T->GetTimer();\r       else\r           time_to_trigger = secs_from_now + ServerInstance->Time();\r\r     timerlist::iterator found = Timers.find(time_to_trigger);\r\r     if (found != Timers.end())\r     {\r              x = found->second;\r     }\r      else\r   {\r              x = new timergroup;\r            Timers[time_to_trigger] = x;\r   }\r\r     x->push_back(T);\r}\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "timer.h"
+
+TimerManager::TimerManager(InspIRCd* Instance) : CantDeleteHere(false), ServerInstance(Instance)
+{
+}
+
+void TimerManager::TickTimers(time_t TIME)
+{
+       this->CantDeleteHere = true;
+       timerlist::iterator found = Timers.find(TIME);
+
+       if (found != Timers.end())
+       {
+               timergroup* x = found->second;
+               /* There are pending timers to trigger.
+                * WARNING: Timers may delete themselves from within
+                * their own Tick methods! see the comment below in
+                * the DelTimer method.
+                */
+               for (timergroup::iterator y = x->begin(); y != x->end(); y++)
+               {
+                       InspTimer* n = *y;
+                       n->Tick(TIME);
+                       if (n->GetRepeat())
+                       {
+                               AddTimer(n, n->GetSecs());
+                       }
+                       else
+                       {
+                               DELETE(n);
+                       }
+               }
+
+               Timers.erase(found);
+               DELETE(x);
+       }
+
+       this->CantDeleteHere = false;
+}
+
+void TimerManager::DelTimer(InspTimer* T)
+{
+       if (this->CantDeleteHere)
+       {
+               /* If a developer tries to delete a timer from within its own Tick method,
+                * then chances are this is just going to totally fuck over the timergroup
+                * and timerlist iterators and cause a crash. Thanks to peavey and Bricker
+                * for noticing this bug.
+                * If we're within the tick loop when the DelTimer is called (signified
+                * by the var 'CantDeleteHere') then we simply return for non-repeating
+                * timers, and cancel the repeat on repeating timers. We can do this because
+                * we know that the timer tick loop will safely delete the timer for us
+                * anyway and therefore we avoid stack corruption.
+                */
+               if (T->GetRepeat())
+                       T->CancelRepeat();
+               else
+                       return;
+       }
+
+       timerlist::iterator found = Timers.find(T->GetTimer());
+
+       if (found != Timers.end())
+       {
+               timergroup* x = found->second;
+               for (timergroup::iterator y = x->begin(); y != x->end(); y++)
+               {
+                       InspTimer* n = *y;
+                       if (n == T)
+                       {
+                               DELETE(n);
+                               x->erase(y);
+                               if (!x->size())
+                               {
+                                       Timers.erase(found);
+                                       DELETE(x);
+                               }
+                               return;
+                       }
+               }
+       }
+}
+
+/** Because some muppets may do odd things, and their ircd may lock up due
+ * to crappy 3rd party modules, or they may change their system time a bit,
+ * this accounts for shifts of up to 120 secs by looking behind for missed
+ * timers and executing them. This is only executed once every 5 secs.
+ * If you move your clock BACK, and your timers move further ahead as a result,
+ * then tough titty you'll just have to wait.
+ */
+void TimerManager::TickMissedTimers(time_t TIME)
+{
+       for (time_t n = TIME-1; n > TIME-120; n--)
+               this->TickTimers(TIME);
+}
+
+void TimerManager::AddTimer(InspTimer* T, long secs_from_now)
+{
+       timergroup* x = NULL;
+
+       int time_to_trigger = 0;
+       if (!secs_from_now)
+               time_to_trigger = T->GetTimer();
+       else
+               time_to_trigger = secs_from_now + ServerInstance->Time();
+
+       timerlist::iterator found = Timers.find(time_to_trigger);
+
+       if (found != Timers.end())
+       {
+               x = found->second;
+       }
+       else
+       {
+               x = new timergroup;
+               Timers[time_to_trigger] = x;
+       }
+
+       x->push_back(T);
+}
+
index c2b2f0b83b521c1fd65173bbd7fa0e00791d9e19..b27844fb6c654917a53fac8e407dae769cf3bb58 100644 (file)
@@ -1 +1,305 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "configreader.h"\r#include "users.h"\r#include "modules.h"\r#include "wildcard.h"\r#include "xline.h"\r#include "socketengine.h"\r#include "command_parse.h"\r\rvoid InspIRCd::FloodQuitUser(userrec* current)\r{\r   this->Log(DEFAULT,"Excess flood from: %s@%s", current->ident, current->host);\r  this->SNO->WriteToSnoMask('f',"Excess flood from: %s%s%s@%s",\r                  current->registered == REG_ALL ? current->nick : "",\r                   current->registered == REG_ALL ? "!" : "", current->ident, current->host);\r     current->SetWriteError("Excess flood");\r        if (current->registered != REG_ALL)\r    {\r              XLines->add_zline(120,this->Config->ServerName,"Flood from unregistered connection",current->GetIPString());\r           XLines->apply_lines(APPLY_ZLINES);\r     }\r}\r\rvoid InspIRCd::ProcessUser(userrec* cu)\r{\r int result = EAGAIN;\r\r  if (cu->GetFd() == FD_MAGIC_NUMBER)\r            return;\r\r       if (this->Config->GetIOHook(cu->GetPort()))\r    {\r              int result2 = 0;\r               int MOD_RESULT = 0;\r\r           try\r            {\r                      MOD_RESULT = this->Config->GetIOHook(cu->GetPort())->OnRawSocketRead(cu->GetFd(),ReadBuffer,sizeof(ReadBuffer),result2);\r               }\r              catch (CoreException& modexcept)\r               {\r                      this->Log(DEBUG, "%s threw an exception: %s", modexcept.GetSource(), modexcept.GetReason());\r           }\r\r             if (MOD_RESULT < 0)\r            {\r                      result = -EAGAIN;\r              }\r              else\r           {\r                      result = result2;\r              }\r      }\r      else\r   {\r              result = cu->ReadData(ReadBuffer, sizeof(ReadBuffer));\r }\r\r     if ((result) && (result != -EAGAIN))\r   {\r              userrec *current;\r              int currfd;\r            int floodlines = 0;\r\r           this->stats->statsRecv += result;\r              /*\r              * perform a check on the raw buffer as an array (not a string!) to remove\r              * character 0 which is illegal in the RFC - replace them with spaces.\r          * XXX - no garauntee there's not \0's in the middle of the data,\r               *       and no reason for it to be terminated either. -- Om\r            */\r\r           for (int checker = 0; checker < result; checker++)\r             {\r                      if (ReadBuffer[checker] == 0)\r                          ReadBuffer[checker] = ' ';\r             }\r\r             if (result > 0)\r                        ReadBuffer[result] = '\0';\r\r            current = cu;\r          currfd = current->GetFd();\r\r            // add the data to the users buffer\r            if (result > 0)\r                {\r                      if (!current->AddBuffer(ReadBuffer))\r                   {\r                              // AddBuffer returned false, theres too much data in the user's buffer and theyre up to no good.\r                               if (current->registered == REG_ALL)\r                            {\r                                      // Make sure they arn't flooding long lines.\r                                   if (TIME > current->reset_due)\r                                 {\r                                              current->reset_due = TIME + current->threshold;\r                                                current->lines_in = 0;\r                                 }\r\r                                     current->lines_in++;\r\r                                  if (current->flood && current->lines_in > current->flood)\r                                              FloodQuitUser(current);\r                                        else\r                                   {\r                                              current->WriteServ("NOTICE %s :Your previous line was too long and was not delivered (Over %d chars) Please shorten it.", current->nick, MAXBUF-2);\r                                            current->recvq.clear();\r                                        }\r                              }\r                              else\r                                   FloodQuitUser(current);\r\r                               return;\r                        }\r\r                     // while there are complete lines to process...\r                        while (current->BufferIsReady())\r                       {\r                              if (TIME > current->reset_due)\r                         {\r                                      current->reset_due = TIME + current->threshold;\r                                        current->lines_in = 0;\r                         }\r\r                             if (++current->lines_in > current->flood && current->flood)\r                            {\r                                      FloodQuitUser(current);\r                                        return;\r                                }\r\r                             if ((++floodlines > current->flood) && (current->flood != 0))\r                          {\r                                      FloodQuitUser(current);\r                                        return;\r                                }\r\r                             // use GetBuffer to copy single lines into the sanitized string\r                                std::string single_line = current->GetBuffer();\r                                current->bytes_in += single_line.length();\r                             current->cmds_in++;\r                            if (single_line.length() > MAXBUF - 2)  /* MAXBUF is 514 to allow for neccessary line terminators */\r                                   single_line.resize(MAXBUF - 2); /* So to trim to 512 here, we use MAXBUF - 2 */\r\r                               EventHandler* old_comp = this->SE->GetRef(currfd);\r\r                            this->Parser->ProcessBuffer(single_line,current);\r                              /*\r                              * look for the user's record in case it's changed... if theyve quit,\r                           * we cant do anything more with their buffer, so bail.\r                                 * there used to be an ugly, slow loop here. Now we have a reference\r                            * table, life is much easier (and FASTER)\r                              */\r                            EventHandler* new_comp = this->SE->GetRef(currfd);\r\r                            if (new_comp != old_comp)\r                                      return;\r                        }\r\r                     return;\r                }\r\r             if ((result == -1) && (errno != EAGAIN) && (errno != EINTR))\r           {\r                      cu->SetWriteError(strerror(errno));\r                    return;\r                }\r      }\r\r     // result EAGAIN means nothing read\r    else if ((result == EAGAIN) || (result == -EAGAIN))\r    {\r              /* do nothing */\r       }\r      else if (result == 0)\r  {\r              cu->SetWriteError("Connection closed");\r                return;\r        }\r}\r\r/**\r * This function is called once a second from the mainloop.\r * It is intended to do background checking on all the user structs, e.g.\r * stuff like ping checks, registration timeouts, etc.\r */\rvoid InspIRCd::DoBackgroundUserStuff(time_t TIME)\r{\r  /* Is it time yet? */\r  if (TIME < next_call)\r          return;\r        else\r   {\r              /* Time we actually need to call this again */\r         const time_t DUMMY_VALUE = 32768;\r              next_call = TIME + DUMMY_VALUE;\r\r               /* XXX: IT IS NOT SAFE TO USE AN ITERATOR HERE. DON'T EVEN THINK ABOUT IT. */\r          for (unsigned long count2 = 0; count2 != this->local_users.size(); count2++)\r           {\r                      if (count2 >= this->local_users.size())\r                                break;\r\r                        userrec* curr = this->local_users[count2];\r\r                    if (curr)\r                      {\r                              /*\r                              * registration timeout -- didnt send USER/NICK/HOST\r                            * in the time specified in their connection class.\r                             */\r                            if ((TIME > curr->timeout) && (curr->registered != REG_ALL))\r                           {\r                                      curr->muted = true;\r                                    GlobalCulls.AddItem(curr,"Registration timeout");\r                                      continue;\r                              }\r                              else\r                           {\r                                      if ((curr->registered != REG_ALL) && (next_call > (time_t)curr->timeout))\r                                              next_call = curr->timeout;\r                             }\r\r                             /*\r                              * user has signed on with USER/NICK/PASS, and dns has completed, all the modules\r                               * say this user is ok to proceed, fully connect them.\r                          */\r                            bool ready = AllModulesReportReady(curr);\r                              if ((TIME > curr->signon) && (curr->registered == REG_NICKUSER) && (ready))\r                            {\r                                      if (!curr->dns_done)\r                                   {\r                                              curr->WriteServ("NOTICE Auth :*** Could not resolve your hostname: Request timed out; using your IP address (%s) instead.", curr->GetIPString());\r                                              curr->dns_done = true;\r                                 }\r                                      this->stats->statsDnsBad++;\r                                    curr->FullConnect();\r                                   continue;\r                              }\r                              else\r                           {\r                                      if ((curr->registered == REG_NICKUSER) && (ready) && (next_call > curr->signon))\r                                               next_call = curr->signon;\r                              }\r\r                             if ((curr->dns_done) && (curr->registered == REG_NICKUSER) && (ready))\r                         {\r                                      curr->FullConnect();\r                                   continue;\r                              }\r                              else\r                           {\r                                      if ((curr->registered == REG_NICKUSER) && (ready) && (next_call > curr->signon + this->Config->dns_timeout))\r                                           next_call = curr->signon + this->Config->dns_timeout;\r                          }\r\r                             // It's time to PING this user. Send them a ping.\r                              if ((TIME > curr->nping) && (curr->registered == REG_ALL))\r                             {\r                                      // This user didn't answer the last ping, remove them\r                                  if (!curr->lastping)\r                                   {\r                                              /* Everybody loves boobies. */\r                                         time_t time = this->Time(false) - (curr->nping - curr->pingmax);\r                                               char message[MAXBUF];\r                                          snprintf(message, MAXBUF, "Ping timeout: %ld second%s", time, time > 1 ? "s" : "");\r                                            curr->muted = true;\r                                            GlobalCulls.AddItem(curr, message);\r                                            curr->lastping = 1;\r                                            curr->nping = TIME+curr->pingmax;\r                                              continue;\r                                      }\r                                      curr->Write("PING :%s",this->Config->ServerName);\r                                      curr->lastping = 0;\r                                    curr->nping = TIME+curr->pingmax;\r                              }\r                              else\r                           {\r                                      if ((curr->registered == REG_ALL) && (next_call > curr->nping))\r                                                next_call = curr->nping;\r                               }\r                      }\r              }\r\r             /* If theres nothing to do, trigger in the next second, something might come up */\r             time_t delta = next_call - TIME;\r               if (delta == DUMMY_VALUE)\r              {\r                      next_call = TIME + 1;\r                  delta = 1;\r             }\r      }\r}\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "configreader.h"
+#include "users.h"
+#include "modules.h"
+#include "wildcard.h"
+#include "xline.h"
+#include "socketengine.h"
+#include "command_parse.h"
+
+void InspIRCd::FloodQuitUser(userrec* current)
+{
+       this->Log(DEFAULT,"Excess flood from: %s@%s", current->ident, current->host);
+       this->SNO->WriteToSnoMask('f',"Excess flood from: %s%s%s@%s",
+                       current->registered == REG_ALL ? current->nick : "",
+                       current->registered == REG_ALL ? "!" : "", current->ident, current->host);
+       current->SetWriteError("Excess flood");
+       if (current->registered != REG_ALL)
+       {
+               XLines->add_zline(120,this->Config->ServerName,"Flood from unregistered connection",current->GetIPString());
+               XLines->apply_lines(APPLY_ZLINES);
+       }
+}
+
+void InspIRCd::ProcessUser(userrec* cu)
+{
+       int result = EAGAIN;
+
+       if (cu->GetFd() == FD_MAGIC_NUMBER)
+               return;
+
+       if (this->Config->GetIOHook(cu->GetPort()))
+       {
+               int result2 = 0;
+               int MOD_RESULT = 0;
+
+               try
+               {
+                       MOD_RESULT = this->Config->GetIOHook(cu->GetPort())->OnRawSocketRead(cu->GetFd(),ReadBuffer,sizeof(ReadBuffer),result2);
+               }
+               catch (CoreException& modexcept)
+               {
+                       this->Log(DEBUG, "%s threw an exception: %s", modexcept.GetSource(), modexcept.GetReason());
+               }
+
+               if (MOD_RESULT < 0)
+               {
+                       result = -EAGAIN;
+               }
+               else
+               {
+                       result = result2;
+               }
+       }
+       else
+       {
+               result = cu->ReadData(ReadBuffer, sizeof(ReadBuffer));
+       }
+
+       if ((result) && (result != -EAGAIN))
+       {
+               userrec *current;
+               int currfd;
+               int floodlines = 0;
+
+               this->stats->statsRecv += result;
+               /*
+                * perform a check on the raw buffer as an array (not a string!) to remove
+                * character 0 which is illegal in the RFC - replace them with spaces.
+                * XXX - no garauntee there's not \0's in the middle of the data,
+                *       and no reason for it to be terminated either. -- Om
+                */
+
+               for (int checker = 0; checker < result; checker++)
+               {
+                       if (ReadBuffer[checker] == 0)
+                               ReadBuffer[checker] = ' ';
+               }
+
+               if (result > 0)
+                       ReadBuffer[result] = '\0';
+
+               current = cu;
+               currfd = current->GetFd();
+
+               // add the data to the users buffer
+               if (result > 0)
+               {
+                       if (!current->AddBuffer(ReadBuffer))
+                       {
+                               // AddBuffer returned false, theres too much data in the user's buffer and theyre up to no good.
+                               if (current->registered == REG_ALL)
+                               {
+                                       // Make sure they arn't flooding long lines.
+                                       if (TIME > current->reset_due)
+                                       {
+                                               current->reset_due = TIME + current->threshold;
+                                               current->lines_in = 0;
+                                       }
+
+                                       current->lines_in++;
+
+                                       if (current->flood && current->lines_in > current->flood)
+                                               FloodQuitUser(current);
+                                       else
+                                       {
+                                               current->WriteServ("NOTICE %s :Your previous line was too long and was not delivered (Over %d chars) Please shorten it.", current->nick, MAXBUF-2);
+                                               current->recvq.clear();
+                                       }
+                               }
+                               else
+                                       FloodQuitUser(current);
+
+                               return;
+                       }
+
+                       // while there are complete lines to process...
+                       while (current->BufferIsReady())
+                       {
+                               if (TIME > current->reset_due)
+                               {
+                                       current->reset_due = TIME + current->threshold;
+                                       current->lines_in = 0;
+                               }
+
+                               if (++current->lines_in > current->flood && current->flood)
+                               {
+                                       FloodQuitUser(current);
+                                       return;
+                               }
+
+                               if ((++floodlines > current->flood) && (current->flood != 0))
+                               {
+                                       FloodQuitUser(current);
+                                       return;
+                               }
+
+                               // use GetBuffer to copy single lines into the sanitized string
+                               std::string single_line = current->GetBuffer();
+                               current->bytes_in += single_line.length();
+                               current->cmds_in++;
+                               if (single_line.length() > MAXBUF - 2)  /* MAXBUF is 514 to allow for neccessary line terminators */
+                                       single_line.resize(MAXBUF - 2); /* So to trim to 512 here, we use MAXBUF - 2 */
+
+                               EventHandler* old_comp = this->SE->GetRef(currfd);
+
+                               this->Parser->ProcessBuffer(single_line,current);
+                               /*
+                                * look for the user's record in case it's changed... if theyve quit,
+                                * we cant do anything more with their buffer, so bail.
+                                * there used to be an ugly, slow loop here. Now we have a reference
+                                * table, life is much easier (and FASTER)
+                                */
+                               EventHandler* new_comp = this->SE->GetRef(currfd);
+
+                               if (new_comp != old_comp)
+                                       return;
+                       }
+
+                       return;
+               }
+
+               if ((result == -1) && (errno != EAGAIN) && (errno != EINTR))
+               {
+                       cu->SetWriteError(strerror(errno));
+                       return;
+               }
+       }
+
+       // result EAGAIN means nothing read
+       else if ((result == EAGAIN) || (result == -EAGAIN))
+       {
+               /* do nothing */
+       }
+       else if (result == 0)
+       {
+               cu->SetWriteError("Connection closed");
+               return;
+       }
+}
+
+/**
+ * This function is called once a second from the mainloop.
+ * It is intended to do background checking on all the user structs, e.g.
+ * stuff like ping checks, registration timeouts, etc.
+ */
+void InspIRCd::DoBackgroundUserStuff(time_t TIME)
+{
+       /* Is it time yet? */
+       if (TIME < next_call)
+               return;
+       else
+       {
+               /* Time we actually need to call this again */
+               const time_t DUMMY_VALUE = 32768;
+               next_call = TIME + DUMMY_VALUE;
+
+               /* XXX: IT IS NOT SAFE TO USE AN ITERATOR HERE. DON'T EVEN THINK ABOUT IT. */
+               for (unsigned long count2 = 0; count2 != this->local_users.size(); count2++)
+               {
+                       if (count2 >= this->local_users.size())
+                               break;
+
+                       userrec* curr = this->local_users[count2];
+
+                       if (curr)
+                       {
+                               /*
+                                * registration timeout -- didnt send USER/NICK/HOST
+                                * in the time specified in their connection class.
+                                */
+                               if ((TIME > curr->timeout) && (curr->registered != REG_ALL))
+                               {
+                                       curr->muted = true;
+                                       GlobalCulls.AddItem(curr,"Registration timeout");
+                                       continue;
+                               }
+                               else
+                               {
+                                       if ((curr->registered != REG_ALL) && (next_call > (time_t)curr->timeout))
+                                               next_call = curr->timeout;
+                               }
+
+                               /*
+                                * user has signed on with USER/NICK/PASS, and dns has completed, all the modules
+                                * say this user is ok to proceed, fully connect them.
+                                */
+                               bool ready = AllModulesReportReady(curr);
+                               if ((TIME > curr->signon) && (curr->registered == REG_NICKUSER) && (ready))
+                               {
+                                       if (!curr->dns_done)
+                                       {
+                                               curr->WriteServ("NOTICE Auth :*** Could not resolve your hostname: Request timed out; using your IP address (%s) instead.", curr->GetIPString());
+                                               curr->dns_done = true;
+                                       }
+                                       this->stats->statsDnsBad++;
+                                       curr->FullConnect();
+                                       continue;
+                               }
+                               else
+                               {
+                                       if ((curr->registered == REG_NICKUSER) && (ready) && (next_call > curr->signon))
+                                               next_call = curr->signon;
+                               }
+
+                               if ((curr->dns_done) && (curr->registered == REG_NICKUSER) && (ready))
+                               {
+                                       curr->FullConnect();
+                                       continue;
+                               }
+                               else
+                               {
+                                       if ((curr->registered == REG_NICKUSER) && (ready) && (next_call > curr->signon + this->Config->dns_timeout))
+                                               next_call = curr->signon + this->Config->dns_timeout;
+                               }
+
+                               // It's time to PING this user. Send them a ping.
+                               if ((TIME > curr->nping) && (curr->registered == REG_ALL))
+                               {
+                                       // This user didn't answer the last ping, remove them
+                                       if (!curr->lastping)
+                                       {
+                                               /* Everybody loves boobies. */
+                                               time_t time = this->Time(false) - (curr->nping - curr->pingmax);
+                                               char message[MAXBUF];
+                                               snprintf(message, MAXBUF, "Ping timeout: %ld second%s", time, time > 1 ? "s" : "");
+                                               curr->muted = true;
+                                               GlobalCulls.AddItem(curr, message);
+                                               curr->lastping = 1;
+                                               curr->nping = TIME+curr->pingmax;
+                                               continue;
+                                       }
+                                       curr->Write("PING :%s",this->Config->ServerName);
+                                       curr->lastping = 0;
+                                       curr->nping = TIME+curr->pingmax;
+                               }
+                               else
+                               {
+                                       if ((curr->registered == REG_ALL) && (next_call > curr->nping))
+                                               next_call = curr->nping;
+                               }
+                       }
+               }
+
+               /* If theres nothing to do, trigger in the next second, something might come up */
+               time_t delta = next_call - TIME;
+               if (delta == DUMMY_VALUE)
+               {
+                       next_call = TIME + 1;
+                       delta = 1;
+               }
+       }
+}
index 250586f1dda76504700f0d4b322bd1b4a413c9bc..7da7d6b0960291d0b14f2867e8c0eea03808b741 100644 (file)
@@ -1 +1,2007 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "configreader.h"\r#include "channels.h"\r#include "users.h"\r#include <stdarg.h>\r#include "socketengine.h"\r#include "wildcard.h"\r#include "xline.h"\r#include "commands/cmd_whowas.h"\r\rstatic unsigned long already_sent[MAX_DESCRIPTORS] = {0};\r\r/* XXX: Used for speeding up WriteCommon operations */\runsigned long uniq_id = 0;\r\rbool InitTypes(ServerConfig* conf, const char* tag)\r{\r     if (conf->opertypes.size())\r    {\r              for (opertype_t::iterator n = conf->opertypes.begin(); n != conf->opertypes.end(); n++)\r                {\r                      if (n->second)\r                         delete[] n->second;\r            }\r      }\r\r     conf->opertypes.clear();\r       return true;\r}\r\rbool InitClasses(ServerConfig* conf, const char* tag)\r{\r        if (conf->operclass.size())\r    {\r              for (operclass_t::iterator n = conf->operclass.begin(); n != conf->operclass.end(); n++)\r               {\r                      if (n->second)\r                         delete[] n->second;\r            }\r      }\r\r     conf->operclass.clear();\r       return true;\r}\r\rbool DoType(ServerConfig* conf, const char* tag, char** entries, ValueList &values, int* types)\r{\r      const char* TypeName = values[0].GetString();\r  const char* Classes = values[1].GetString();\r\r  conf->opertypes[TypeName] = strnewdup(Classes);\r        return true;\r}\r\rbool DoClass(ServerConfig* conf, const char* tag, char** entries, ValueList &values, int* types)\r{\r     const char* ClassName = values[0].GetString();\r const char* CommandList = values[1].GetString();\r\r      conf->operclass[ClassName] = strnewdup(CommandList);\r   return true;\r}\r\rbool DoneClassesAndTypes(ServerConfig* conf, const char* tag)\r{\r        return true;\r}\r\rstd::string userrec::ProcessNoticeMasks(const char *sm)\r{\r      bool adding = true, oldadding = false;\r const char *c = sm;\r    std::string output;\r\r   while (c && *c)\r        {\r              switch (*c)\r            {\r                      case '+':\r                              adding = true;\r                 break;\r                 case '-':\r                              adding = false;\r                        break;\r                 case '*':\r                              for (unsigned char d = 'A'; d <= 'z'; d++)\r                             {\r                                      if (ServerInstance->SNO->IsEnabled(d))\r                                 {\r                                              if ((!IsNoticeMaskSet(d) && adding) || (IsNoticeMaskSet(d) && !adding))\r                                                {\r                                                      if ((oldadding != adding) || (!output.length()))\r                                                               output += (adding ? '+' : '-');\r\r                                                       this->SetNoticeMask(d, adding);\r\r                                                       output += d;\r                                           }\r                                      }\r                                      oldadding = adding;\r                            }\r                      break;\r                 default:\r                               if ((*c >= 'A') && (*c <= 'z') && (ServerInstance->SNO->IsEnabled(*c)))\r                                {\r                                      if ((!IsNoticeMaskSet(*c) && adding) || (IsNoticeMaskSet(*c) && !adding))\r                                      {\r                                              if ((oldadding != adding) || (!output.length()))\r                                                       output += (adding ? '+' : '-');\r\r                                               this->SetNoticeMask(*c, adding);\r\r                                              output += *c;\r                                  }\r                              }\r                              oldadding = adding;\r                    break;\r         }\r\r             *c++;\r  }\r\r     return output;\r}\r\rvoid userrec::StartDNSLookup()\r{\r     try\r    {\r              bool cached;\r           const char* ip = this->GetIPString();\r\r         /* Special case for 4in6 (Have i mentioned i HATE 4in6?) */\r            if (!strncmp(ip, "0::ffff:", 8))\r                       res_reverse = new UserResolver(this->ServerInstance, this, ip + 8, DNS_QUERY_PTR4, cached);\r            else\r                   res_reverse = new UserResolver(this->ServerInstance, this, ip, this->GetProtocolFamily() == AF_INET ? DNS_QUERY_PTR4 : DNS_QUERY_PTR6, cached);\r\r               this->ServerInstance->AddResolver(res_reverse, cached);\r        }\r      catch (CoreException& e)\r       {\r              ServerInstance->Log(DEBUG,"Error in resolver: %s",e.GetReason());\r      }\r}\r\rUserResolver::UserResolver(InspIRCd* Instance, userrec* user, std::string to_resolve, QueryType qt, bool &cache) :\r        Resolver(Instance, to_resolve, qt, cache), bound_user(user)\r{\r  this->fwd = (qt == DNS_QUERY_A || qt == DNS_QUERY_AAAA);\r       this->bound_fd = user->GetFd();\r}\r\rvoid UserResolver::OnLookupComplete(const std::string &result, unsigned int ttl, bool cached)\r{\r     if ((!this->fwd) && (ServerInstance->SE->GetRef(this->bound_fd) == this->bound_user))\r  {\r              this->bound_user->stored_host = result;\r                try\r            {\r                      /* Check we didnt time out */\r                  if (this->bound_user->registered != REG_ALL)\r                   {\r                              bool cached;\r#ifdef IPV6\r                               if (this->bound_user->GetProtocolFamily() == AF_INET6)\r                         {\r                                      /* IPV6 forward lookup (with possibility of 4in6) */\r                                   const char* ip = this->bound_user->GetIPString();\r                                      bound_user->res_forward = new UserResolver(this->ServerInstance, this->bound_user, result, (!strncmp(ip, "0::ffff:", 8) ? DNS_QUERY_A : DNS_QUERY_AAAA), cached);\r                              }\r                              else\r                                   /* IPV4 lookup (mixed protocol mode) */\r#endif\r                         /* IPV4 lookup (ipv4 only mode) */\r                             bound_user->res_forward = new UserResolver(this->ServerInstance, this->bound_user, result, DNS_QUERY_A, cached);\r                               this->ServerInstance->AddResolver(bound_user->res_forward, cached);\r                    }\r              }\r              catch (CoreException& e)\r               {\r                      ServerInstance->Log(DEBUG,"Error in resolver: %s",e.GetReason());\r              }\r      }\r      else if ((this->fwd) && (ServerInstance->SE->GetRef(this->bound_fd) == this->bound_user))\r      {\r              /* Both lookups completed */\r           std::string result2("0::ffff:");\r               result2.append(result);\r                if (this->bound_user->GetIPString() == result || this->bound_user->GetIPString() == result2)\r           {\r                      std::string hostname = this->bound_user->stored_host;\r                  if (hostname.length() < 65)\r                    {\r                              /* Check we didnt time out */\r                          if ((this->bound_user->registered != REG_ALL) && (!this->bound_user->dns_done))\r                                {\r                                      /* Hostnames starting with : are not a good thing (tm) */\r                                      if (*(hostname.c_str()) == ':')\r                                                hostname.insert(0, "0");\r\r                                      this->bound_user->WriteServ("NOTICE Auth :*** Found your hostname (%s)%s", hostname.c_str(), (cached ? " -- cached" : ""));\r                                    this->bound_user->dns_done = true;\r                                     strlcpy(this->bound_user->dhost, hostname.c_str(),64);\r                                 strlcpy(this->bound_user->host, hostname.c_str(),64);\r                                  /* Invalidate cache */\r                                 this->bound_user->InvalidateCache();\r                           }\r                      }\r                      else\r                   {\r                              if (!this->bound_user->dns_done)\r                               {\r                                      this->bound_user->WriteServ("NOTICE Auth :*** Your hostname is longer than the maximum of 64 characters, using your IP address (%s) instead.", this->bound_user->GetIPString());\r                                       this->bound_user->dns_done = true;\r                             }\r                      }\r              }\r              else\r           {\r                      if (!this->bound_user->dns_done)\r                       {\r                              this->bound_user->WriteServ("NOTICE Auth :*** Your hostname does not match up with your IP address. Sorry, using your IP address (%s) instead.", this->bound_user->GetIPString());\r                             this->bound_user->dns_done = true;\r                     }\r              }\r      }\r}\r\rvoid UserResolver::OnError(ResolverError e, const std::string &errormessage)\r{\r    if (ServerInstance->SE->GetRef(this->bound_fd) == this->bound_user)\r    {\r              /* Since dns timeout is implemented outside of the resolver, this was a race condition that could result in this message being sent *after*\r             * the user was fully connected. This check fixes that issue  - Special */\r             if (!this->bound_user->dns_done)\r               {\r                      /* Error message here */\r                       this->bound_user->WriteServ("NOTICE Auth :*** Could not resolve your hostname: %s; using your IP address (%s) instead.", errormessage.c_str(), this->bound_user->GetIPString());\r                       this->bound_user->dns_done = true;\r             }\r      }\r}\r\r\rbool userrec::IsNoticeMaskSet(unsigned char sm)\r{\r        return (snomasks[sm-65]);\r}\r\rvoid userrec::SetNoticeMask(unsigned char sm, bool value)\r{\r       snomasks[sm-65] = value;\r}\r\rconst char* userrec::FormatNoticeMasks()\r{\r static char data[MAXBUF];\r      int offset = 0;\r\r       for (int n = 0; n < 64; n++)\r   {\r              if (snomasks[n])\r                       data[offset++] = n+65;\r }\r\r     data[offset] = 0;\r      return data;\r}\r\r\r\rbool userrec::IsModeSet(unsigned char m)\r{\r   return (modes[m-65]);\r}\r\rvoid userrec::SetMode(unsigned char m, bool value)\r{\r  modes[m-65] = value;\r}\r\rconst char* userrec::FormatModes()\r{\r   static char data[MAXBUF];\r      int offset = 0;\r        for (int n = 0; n < 64; n++)\r   {\r              if (modes[n])\r                  data[offset++] = n+65;\r }\r      data[offset] = 0;\r      return data;\r}\r\rvoid userrec::DecrementModes()\r{\r       for (int n = 0; n < 64; n++)\r   {\r              if (modes[n])\r          {\r                      ModeHandler* mh = ServerInstance->Modes->FindMode(n+65, MODETYPE_USER);\r                        if (mh)\r                                mh->ChangeCount(-1);\r           }\r      }\r}\r\ruserrec::userrec(InspIRCd* Instance) : ServerInstance(Instance)\r{\r // the PROPER way to do it, AVOID bzero at *ALL* costs\r *password = *nick = *ident = *host = *dhost = *fullname = *awaymsg = *oper = 0;\r        server = (char*)Instance->FindServerNamePtr(Instance->Config->ServerName);\r     reset_due = ServerInstance->Time();\r    age = ServerInstance->Time(true);\r      lines_in = lastping = signon = idle_lastmsg = nping = registered = 0;\r  ChannelCount = timeout = flood = bytes_in = bytes_out = cmds_in = cmds_out = 0;\r        muted = exempt = haspassed = dns_done = false;\r fd = -1;\r       recvq.clear();\r sendq.clear();\r WriteError.clear();\r    res_forward = res_reverse = NULL;\r      Visibility = NULL;\r     ip = NULL;\r     chans.clear();\r invites.clear();\r       memset(modes,0,sizeof(modes));\r memset(snomasks,0,sizeof(snomasks));\r   /* Invalidate cache */\r operquit = cached_fullhost = cached_hostip = cached_makehost = cached_fullrealhost = NULL;\r}\r\rvoid userrec::RemoveCloneCounts()\r{\r      clonemap::iterator x = ServerInstance->local_clones.find(this->GetIPString());\r if (x != ServerInstance->local_clones.end())\r   {\r              x->second--;\r           if (!x->second)\r                {\r                      ServerInstance->local_clones.erase(x);\r         }\r      }\r      \r       clonemap::iterator y = ServerInstance->global_clones.find(this->GetIPString());\r        if (y != ServerInstance->global_clones.end())\r  {\r              y->second--;\r           if (!y->second)\r                {\r                      ServerInstance->global_clones.erase(y);\r                }\r      }\r}\r\ruserrec::~userrec()\r{\r     this->InvalidateCache();\r       this->DecrementModes();\r        if (operquit)\r          free(operquit);\r        if (ip)\r        {\r              this->RemoveCloneCounts();\r\r            if (this->GetProtocolFamily() == AF_INET)\r              {\r                      delete (sockaddr_in*)ip;\r               }\r#ifdef SUPPORT_IP6LINKS\r              else\r           {\r                      delete (sockaddr_in6*)ip;\r              }\r#endif\r       }\r}\r\rchar* userrec::MakeHost()\r{\r       if (this->cached_makehost)\r             return this->cached_makehost;\r\r char nhost[MAXBUF];\r    /* This is much faster than snprintf */\r        char* t = nhost;\r       for(char* n = ident; *n; n++)\r          *t++ = *n;\r     *t++ = '@';\r    for(char* n = host; *n; n++)\r           *t++ = *n;\r     *t = 0;\r\r       this->cached_makehost = strdup(nhost);\r\r        return this->cached_makehost;\r}\r\rchar* userrec::MakeHostIP()\r{\r if (this->cached_hostip)\r               return this->cached_hostip;\r\r   char ihost[MAXBUF];\r    /* This is much faster than snprintf */\r        char* t = ihost;\r       for(char* n = ident; *n; n++)\r          *t++ = *n;\r     *t++ = '@';\r    for(const char* n = this->GetIPString(); *n; n++)\r              *t++ = *n;\r     *t = 0;\r\r       this->cached_hostip = strdup(ihost);\r\r  return this->cached_hostip;\r}\r\rvoid userrec::CloseSocket()\r{\r   shutdown(this->fd,2);\r  close(this->fd);\r}\r\rchar* userrec::GetFullHost()\r{\r     if (this->cached_fullhost)\r             return this->cached_fullhost;\r\r char result[MAXBUF];\r   char* t = result;\r      for(char* n = nick; *n; n++)\r           *t++ = *n;\r     *t++ = '!';\r    for(char* n = ident; *n; n++)\r          *t++ = *n;\r     *t++ = '@';\r    for(char* n = dhost; *n; n++)\r          *t++ = *n;\r     *t = 0;\r\r       this->cached_fullhost = strdup(result);\r\r       return this->cached_fullhost;\r}\r\rchar* userrec::MakeWildHost()\r{\r       static char nresult[MAXBUF];\r   char* t = nresult;\r     *t++ = '*';     *t++ = '!';\r    *t++ = '*';     *t++ = '@';\r    for(char* n = dhost; *n; n++)\r          *t++ = *n;\r     *t = 0;\r        return nresult;\r}\r\rint userrec::ReadData(void* buffer, size_t size)\r{\r  if (IS_LOCAL(this))\r    {\r#ifndef WIN32\r                return read(this->fd, buffer, size);\r#else\r             return recv(this->fd, (char*)buffer, size, 0);\r#endif\r  }\r      else\r           return 0;\r}\r\r\rchar* userrec::GetFullRealHost()\r{\r       if (this->cached_fullrealhost)\r         return this->cached_fullrealhost;\r\r     char fresult[MAXBUF];\r  char* t = fresult;\r     for(char* n = nick; *n; n++)\r           *t++ = *n;\r     *t++ = '!';\r    for(char* n = ident; *n; n++)\r          *t++ = *n;\r     *t++ = '@';\r    for(char* n = host; *n; n++)\r           *t++ = *n;\r     *t = 0;\r\r       this->cached_fullrealhost = strdup(fresult);\r\r  return this->cached_fullrealhost;\r}\r\rbool userrec::IsInvited(const irc::string &channel)\r{\r     for (InvitedList::iterator i = invites.begin(); i != invites.end(); i++)\r       {\r              if (channel == *i)\r             {\r                      return true;\r           }\r      }\r      return false;\r}\r\rInvitedList* userrec::GetInviteList()\r{\r       return &invites;\r}\r\rvoid userrec::InviteTo(const irc::string &channel)\r{\r       invites.push_back(channel);\r}\r\rvoid userrec::RemoveInvite(const irc::string &channel)\r{\r        for (InvitedList::iterator i = invites.begin(); i != invites.end(); i++)\r       {\r              if (channel == *i)\r             {\r                      invites.erase(i);\r                      return;\r                }\r      }\r}\r\rbool userrec::HasPermission(const std::string &command)\r{\r char* mycmd;\r   char* savept;\r  char* savept2;\r\r        /*\r      * users on remote servers can completely bypass all permissions based checks.\r  * This prevents desyncs when one server has different type/class tags to another.\r      * That having been said, this does open things up to the possibility of source changes\r         * allowing remote kills, etc - but if they have access to the src, they most likely have\r       * access to the conf - so it's an end to a means either way.\r   */\r    if (!IS_LOCAL(this))\r           return true;\r\r  // are they even an oper at all?\r       if (IS_OPER(this))\r     {\r              opertype_t::iterator iter_opertype = ServerInstance->Config->opertypes.find(this->oper);\r               if (iter_opertype != ServerInstance->Config->opertypes.end())\r          {\r                      char* Classes = strdup(iter_opertype->second);\r                 char* myclass = strtok_r(Classes," ",&savept);\r                 while (myclass)\r                        {\r                              operclass_t::iterator iter_operclass = ServerInstance->Config->operclass.find(myclass);\r                                if (iter_operclass != ServerInstance->Config->operclass.end())\r                         {\r                                      char* CommandList = strdup(iter_operclass->second);\r                                    mycmd = strtok_r(CommandList," ",&savept2);\r                                    while (mycmd)\r                                  {\r                                              if ((!strcasecmp(mycmd,command.c_str())) || (*mycmd == '*'))\r                                           {\r                                                      free(Classes);\r                                                 free(CommandList);\r                                                     return true;\r                                           }\r                                              mycmd = strtok_r(NULL," ",&savept2);\r                                   }\r                                      free(CommandList);\r                             }\r                              myclass = strtok_r(NULL," ",&savept);\r                  }\r                      free(Classes);\r         }\r      }\r      return false;\r}\r\r/** NOTE: We cannot pass a const reference to this method.\r * The string is changed by the workings of the method,\r * so that if we pass const ref, we end up copying it to\r * something we can change anyway. Makes sense to just let\r * the compiler do that copy for us.\r */\rbool userrec::AddBuffer(std::string a)\r{\r      try\r    {\r              std::string::size_type i = a.rfind('\r');\r\r             while (i != std::string::npos)\r         {\r                      a.erase(i, 1);\r                 i = a.rfind('\r');\r             }\r\r             if (a.length())\r                        recvq.append(a);\r\r              if (recvq.length() > (unsigned)this->recvqmax)\r         {\r                      this->SetWriteError("RecvQ exceeded");\r                 ServerInstance->WriteOpers("*** User %s RecvQ of %d exceeds connect class maximum of %d",this->nick,recvq.length(),this->recvqmax);\r                    return false;\r          }\r\r             return true;\r   }\r\r     catch (...)\r    {\r              ServerInstance->Log(DEBUG,"Exception in userrec::AddBuffer()");\r                return false;\r  }\r}\r\rbool userrec::BufferIsReady()\r{\r   return (recvq.find('\n') != std::string::npos);\r}\r\rvoid userrec::ClearBuffer()\r{\r       recvq.clear();\r}\r\rstd::string userrec::GetBuffer()\r{\r   try\r    {\r              if (!recvq.length())\r                   return "";\r\r            /* Strip any leading \r or \n off the string.\r           * Usually there are only one or two of these,\r          * so its is computationally cheap to do.\r               */\r            std::string::iterator t = recvq.begin();\r               while (t != recvq.end() && (*t == '\r' || *t == '\n'))\r         {\r                      recvq.erase(t);\r                        t = recvq.begin();\r             }\r\r             for (std::string::iterator x = recvq.begin(); x != recvq.end(); x++)\r           {\r                      /* Find the first complete line, return it as the\r                       * result, and leave the recvq as whats left\r                    */\r                    if (*x == '\n')\r                        {\r                              std::string ret = std::string(recvq.begin(), x);\r                               recvq.erase(recvq.begin(), x + 1);\r                             return ret;\r                    }\r              }\r              return "";\r     }\r\r     catch (...)\r    {\r              ServerInstance->Log(DEBUG,"Exception in userrec::GetBuffer()");\r                return "";\r     }\r}\r\rvoid userrec::AddWriteBuf(const std::string &data)\r{\r      if (*this->GetWriteError())\r            return;\r\r       if (sendq.length() + data.length() > (unsigned)this->sendqmax)\r {\r              /*\r              * Fix by brain - Set the error text BEFORE calling writeopers, because\r                 * if we dont it'll recursively  call here over and over again trying\r           * to repeatedly add the text to the sendq!\r             */\r            this->SetWriteError("SendQ exceeded");\r         ServerInstance->WriteOpers("*** User %s SendQ of %d exceeds connect class maximum of %d",this->nick,sendq.length() + data.length(),this->sendqmax);\r            return;\r        }\r\r     try\r    {\r              if (data.length() > MAXBUF - 2) /* MAXBUF has a value of 514, to account for line terminators */\r                       sendq.append(data.substr(0,MAXBUF - 4)).append("\r\n"); /* MAXBUF-4 = 510 */\r           else\r                   sendq.append(data);\r    }\r      catch (...)\r    {\r              this->SetWriteError("SendQ exceeded");\r         ServerInstance->WriteOpers("*** User %s SendQ got an exception",this->nick);\r   }\r}\r\r// send AS MUCH OF THE USERS SENDQ as we are able to (might not be all of it)\rvoid userrec::FlushWriteBuf()\r{\r     try\r    {\r              if ((this->fd == FD_MAGIC_NUMBER) || (*this->GetWriteError()))\r         {\r                      sendq.clear();\r         }\r              if ((sendq.length()) && (this->fd != FD_MAGIC_NUMBER))\r         {\r                      int old_sendq_length = sendq.length();\r#ifndef WIN32\r           int n_sent = write(this->fd, this->sendq.data(), this->sendq.length());\r#else\r          int n_sent = send(this->fd, (const char*)this->sendq.data(), this->sendq.length(), 0);\r#endif\r                  if (n_sent == -1)\r                      {\r                              if (errno == EAGAIN)\r                           {\r                                      /* The socket buffer is full. This isnt fatal,\r                                  * try again later.\r                                     */\r                                    this->ServerInstance->SE->WantWrite(this);\r                             }\r                              else\r                           {\r                                      /* Fatal error, set write error and bail\r                                        */\r                                    this->SetWriteError(strerror(errno));\r                                  return;\r                                }\r                      }\r                      else\r                   {\r                              /* advance the queue */\r                                if (n_sent)\r                                    this->sendq = this->sendq.substr(n_sent);\r                              /* update the user's stats counters */\r                         this->bytes_out += n_sent;\r                             this->cmds_out++;\r                              if (n_sent != old_sendq_length)\r                                        this->ServerInstance->SE->WantWrite(this);\r                     }\r              }\r      }\r\r     catch (...)\r    {\r              ServerInstance->Log(DEBUG,"Exception in userrec::FlushWriteBuf()");\r    }\r\r     if (this->sendq.empty())\r       {\r              FOREACH_MOD(I_OnBufferFlushed,OnBufferFlushed(this));\r  }\r}\r\rvoid userrec::SetWriteError(const std::string &error)\r{\r   try\r    {\r              // don't try to set the error twice, its already set take the first string.\r            if (this->WriteError.empty())\r                  this->WriteError = error;\r      }\r\r     catch (...)\r    {\r              ServerInstance->Log(DEBUG,"Exception in userrec::SetWriteError()");\r    }\r}\r\rconst char* userrec::GetWriteError()\r{\r    return this->WriteError.c_str();\r}\r\rvoid userrec::Oper(const std::string &opertype)\r{\r  try\r    {\r              this->modes[UM_OPERATOR] = 1;\r          this->WriteServ("MODE %s :+o", this->nick);\r            FOREACH_MOD(I_OnOper, OnOper(this, opertype));\r         ServerInstance->Log(DEFAULT,"OPER: %s!%s@%s opered as type: %s", this->nick, this->ident, this->host, opertype.c_str());\r               strlcpy(this->oper, opertype.c_str(), NICKMAX - 1);\r            ServerInstance->all_opers.push_back(this);\r             FOREACH_MOD(I_OnPostOper,OnPostOper(this, opertype));\r  }\r\r     catch (...)\r    {\r              ServerInstance->Log(DEBUG,"Exception in userrec::Oper()");\r     }\r}\r\rvoid userrec::UnOper()\r{\r  try\r    {\r              if (IS_OPER(this))\r             {\r                      // unset their oper type (what IS_OPER checks), and remove +o\r                  *this->oper = 0;\r                       this->modes[UM_OPERATOR] = 0;\r\r                 // remove them from the opers list.\r                    for (std::vector<userrec*>::iterator a = ServerInstance->all_opers.begin(); a < ServerInstance->all_opers.end(); a++)\r                  {\r                              if (*a == this)\r                                {\r                                      ServerInstance->all_opers.erase(a);\r                                    return;\r                                }\r                      }\r              }\r      }\r\r     catch (...)\r    {\r              ServerInstance->Log(DEBUG,"Exception in userrec::UnOper()");\r   }\r}\r\rvoid userrec::QuitUser(InspIRCd* Instance, userrec *user, const std::string &quitreason, const char* operreason)\r{\r        user->muted = true;\r    Instance->GlobalCulls.AddItem(user, quitreason.c_str(), operreason);\r}\r\r/* adds or updates an entry in the whowas list */\rvoid userrec::AddToWhoWas()\r{\r        command_t* whowas_command = ServerInstance->Parser->GetHandler("WHOWAS");\r      if (whowas_command)\r    {\r              std::deque<classbase*> params;\r         params.push_back(this);\r                whowas_command->HandleInternal(WHOWAS_ADD, params);\r    }\r}\r\r/* add a client connection to the sockets list */\rvoid userrec::AddClient(InspIRCd* Instance, int socket, int port, bool iscached, int socketfamily, sockaddr* ip)\r{\r      std::string tempnick = ConvToStr(socket) + "-unknown";\r user_hash::iterator iter = Instance->clientlist->find(tempnick);\r       char ipaddr[MAXBUF];\r#ifdef IPV6\r       if (socketfamily == AF_INET6)\r          inet_ntop(AF_INET6, &((const sockaddr_in6*)ip)->sin6_addr, ipaddr, sizeof(ipaddr));\r    else\r#endif\r    inet_ntop(AF_INET, &((const sockaddr_in*)ip)->sin_addr, ipaddr, sizeof(ipaddr));\r       userrec* New;\r  int j = 0;\r\r    Instance->unregistered_count++;\r\r       /*\r      * fix by brain.\r        * as these nicknames are 'RFC impossible', we can be sure nobody is going to be\r        * using one as a registered connection. As they are per fd, we can also safely assume\r  * that we wont have collisions. Therefore, if the nick exists in the list, its only\r    * used by a dead socket, erase the iterator so that the new client may reclaim it.\r     * this was probably the cause of 'server ignores me when i hammer it with reconnects'\r  * issue in earlier alphas/betas\r        */\r    if (iter != Instance->clientlist->end())\r       {\r              userrec* goner = iter->second;\r         DELETE(goner);\r         Instance->clientlist->erase(iter);\r     }\r\r     New = new userrec(Instance);\r   (*(Instance->clientlist))[tempnick] = New;\r     New->fd = socket;\r      strlcpy(New->nick,tempnick.c_str(),NICKMAX-1);\r\r        New->server = Instance->FindServerNamePtr(Instance->Config->ServerName);\r       /* We don't need range checking here, we KNOW 'unknown\0' will fit into the ident field. */\r    strcpy(New->ident, "unknown");\r\r        New->registered = REG_NONE;\r    New->signon = Instance->Time() + Instance->Config->dns_timeout;\r        New->lastping = 1;\r\r    New->SetSockAddr(socketfamily, ipaddr, port);\r\r /* Smarter than your average bear^H^H^H^Hset of strlcpys. */\r   for (const char* temp = New->GetIPString(); *temp && j < 64; temp++, j++)\r              New->dhost[j] = New->host[j] = *temp;\r  New->dhost[j] = New->host[j] = 0;\r\r     Instance->AddLocalClone(New);\r  Instance->AddGlobalClone(New);\r\r        /*\r      * First class check. We do this again in FullConnect after DNS is done, and NICK/USER is recieved.\r     * See my note down there for why this is required. DO NOT REMOVE. :) -- w00t\r   */\r    ConnectClass* i = New->GetClass();\r\r    if (!i)\r        {\r              userrec::QuitUser(Instance, New, "Access denied by configuration");\r            return;\r        }\r\r     New->CheckClass();\r\r    New->pingmax = i->GetPingTime();\r       New->nping = Instance->Time() + i->GetPingTime() + Instance->Config->dns_timeout;\r      New->timeout = Instance->Time() + i->GetRegTimeout();\r  New->flood = i->GetFlood();\r    New->threshold = i->GetThreshold();\r    New->sendqmax = i->GetSendqMax();\r      New->recvqmax = i->GetRecvqMax();\r\r     Instance->local_users.push_back(New);\r\r if ((Instance->local_users.size() > Instance->Config->SoftLimit) || (Instance->local_users.size() >= MAXCLIENTS))\r      {\r              Instance->WriteOpers("*** Warning: softlimit value has been reached: %d clients", Instance->Config->SoftLimit);\r                userrec::QuitUser(Instance, New,"No more connections allowed");\r                return;\r        }\r\r     /*\r      * XXX -\r        * this is done as a safety check to keep the file descriptors within range of fd_ref_table.\r    * its a pretty big but for the moment valid assumption:\r        * file descriptors are handed out starting at 0, and are recycled as theyre freed.\r     * therefore if there is ever an fd over 65535, 65536 clients must be connected to the\r  * irc server at once (or the irc server otherwise initiating this many connections, files etc)\r         * which for the time being is a physical impossibility (even the largest networks dont have more\r       * than about 10,000 users on ONE server!)\r      */\r#ifndef WINDOWS\r    if ((unsigned int)socket >= MAX_DESCRIPTORS)\r   {\r              userrec::QuitUser(Instance, New, "Server is full");\r            return;\r        }\r#endif\r\r      New->exempt = (Instance->XLines->matches_exception(New) != NULL);\r      if (!New->exempt)\r      {\r              ZLine* r = Instance->XLines->matches_zline(ipaddr);\r            if (r)\r         {\r                      char reason[MAXBUF];\r                   if (*Instance->Config->MoronBanner)\r                            New->WriteServ("NOTICE %s :*** %s", New->nick, Instance->Config->MoronBanner);\r                 snprintf(reason,MAXBUF,"Z-Lined: %s",r->reason);\r                       userrec::QuitUser(Instance, New, reason);\r                      return;\r                }\r      }\r\r     if (socket > -1)\r       {\r              if (!Instance->SE->AddFd(New))\r         {\r                      userrec::QuitUser(Instance, New, "Internal error handling connection");\r                        return;\r                }\r      }\r\r     /* NOTE: even if dns lookups are *off*, we still need to display this.\r  * BOPM and other stuff requires it.\r    */\r    New->WriteServ("NOTICE Auth :*** Looking up your hostname...");\r}\r\runsigned long userrec::GlobalCloneCount()\r{\r clonemap::iterator x = ServerInstance->global_clones.find(this->GetIPString());\r        if (x != ServerInstance->global_clones.end())\r          return x->second;\r      else\r           return 0;\r}\r\runsigned long userrec::LocalCloneCount()\r{\r        clonemap::iterator x = ServerInstance->local_clones.find(this->GetIPString());\r if (x != ServerInstance->local_clones.end())\r           return x->second;\r      else\r           return 0;\r}\r\r/*\r * Check class restrictions\r */\rvoid userrec::CheckClass()\r{\r   ConnectClass* a = this->GetClass();\r\r   if ((!a) || (a->GetType() == CC_DENY))\r {\r              userrec::QuitUser(ServerInstance, this, "Unauthorised connection");\r            return;\r        }\r      else if ((a->GetMaxLocal()) && (this->LocalCloneCount() > a->GetMaxLocal()))\r   {\r              userrec::QuitUser(ServerInstance, this, "No more connections allowed from your host via this connect class (local)");\r          ServerInstance->WriteOpers("*** WARNING: maximum LOCAL connections (%ld) exceeded for IP %s", a->GetMaxLocal(), this->GetIPString());\r          return;\r        }\r      else if ((a->GetMaxGlobal()) && (this->GlobalCloneCount() > a->GetMaxGlobal()))\r        {\r              userrec::QuitUser(ServerInstance, this, "No more connections allowed from your host via this connect class (global)");\r         ServerInstance->WriteOpers("*** WARNING: maximum GLOBAL connections (%ld) exceeded for IP %s", a->GetMaxGlobal(), this->GetIPString());\r                return;\r        }\r}\r\rvoid userrec::FullConnect()\r{\r     ServerInstance->stats->statsConnects++;\r        this->idle_lastmsg = ServerInstance->Time();\r\r  /*\r      * You may be thinking "wtf, we checked this in userrec::AddClient!" - and yes, we did, BUT.\r    * At the time AddClient is called, we don't have a resolved host, by here we probably do - which\r       * may put the user into a totally seperate class with different restrictions! so we *must* check again.\r        * Don't remove this! -- w00t\r   */\r    this->CheckClass();\r    \r       /* Check the password, if one is required by the user's connect class.\r  * This CANNOT be in CheckClass(), because that is called prior to PASS as well!\r        */\r    if ((!this->GetClass()->GetPass().empty()) && (!this->haspassed))\r      {\r              userrec::QuitUser(ServerInstance, this, "Invalid password");\r           return;\r        }\r      \r       if (!this->exempt)\r     {\r              GLine* r = ServerInstance->XLines->matches_gline(this);\r\r               if (r)\r         {\r                      this->muted = true;\r                    char reason[MAXBUF];\r                   if (*ServerInstance->Config->MoronBanner)\r                              this->WriteServ("NOTICE %s :*** %s", this->nick, ServerInstance->Config->MoronBanner);\r                 snprintf(reason,MAXBUF,"G-Lined: %s",r->reason);\r                       ServerInstance->GlobalCulls.AddItem(this, reason);\r                     return;\r                }\r\r             KLine* n = ServerInstance->XLines->matches_kline(this);\r\r               if (n)\r         {\r                      this->muted = true;\r                    char reason[MAXBUF];\r                   if (*ServerInstance->Config->MoronBanner)\r                              this->WriteServ("NOTICE %s :*** %s", this, ServerInstance->Config->MoronBanner);\r                       snprintf(reason,MAXBUF,"K-Lined: %s",n->reason);\r                       ServerInstance->GlobalCulls.AddItem(this, reason);\r                     return;\r                }\r      }\r\r     this->WriteServ("NOTICE Auth :Welcome to \002%s\002!",ServerInstance->Config->Network);\r        this->WriteServ("001 %s :Welcome to the %s IRC Network %s!%s@%s",this->nick, ServerInstance->Config->Network, this->nick, this->ident, this->host);\r    this->WriteServ("002 %s :Your host is %s, running version %s",this->nick,ServerInstance->Config->ServerName,VERSION);\r  this->WriteServ("003 %s :This server was created %s %s", this->nick, __TIME__, __DATE__);\r      this->WriteServ("004 %s %s %s %s %s %s", this->nick, ServerInstance->Config->ServerName, VERSION, ServerInstance->Modes->UserModeList().c_str(), ServerInstance->Modes->ChannelModeList().c_str(), ServerInstance->Modes->ParaModeList().c_str());\r\r    ServerInstance->Config->Send005(this);\r\r        this->ShowMOTD();\r\r     /* Now registered */\r   if (ServerInstance->unregistered_count)\r                ServerInstance->unregistered_count--;\r\r /* Trigger LUSERS output, give modules a chance too */\r int MOD_RESULT = 0;\r    FOREACH_RESULT(I_OnPreCommand, OnPreCommand("LUSERS", NULL, 0, this, true, "LUSERS"));\r if (!MOD_RESULT)\r               ServerInstance->CallCommandHandler("LUSERS", NULL, 0, this);\r\r  /*\r      * fix 3 by brain, move registered = 7 below these so that spurious modes and host\r      * changes dont go out onto the network and produce 'fake direction'.\r   */\r    FOREACH_MOD(I_OnUserConnect,OnUserConnect(this));\r\r     this->registered = REG_ALL;\r\r   FOREACH_MOD(I_OnPostConnect,OnPostConnect(this));\r\r     ServerInstance->SNO->WriteToSnoMask('c',"Client connecting on port %d: %s!%s@%s [%s] [%s]", this->GetPort(), this->nick, this->ident, this->host, this->GetIPString(), this->fullname);\r}\r\r/** userrec::UpdateNick()\r * re-allocates a nick in the user_hash after they change nicknames,\r * returns a pointer to the new user as it may have moved\r */\ruserrec* userrec::UpdateNickHash(const char* New)\r{\r    try\r    {\r              //user_hash::iterator newnick;\r         user_hash::iterator oldnick = ServerInstance->clientlist->find(this->nick);\r\r           if (!strcasecmp(this->nick,New))\r                       return oldnick->second;\r\r               if (oldnick == ServerInstance->clientlist->end())\r                      return NULL; /* doesnt exist */\r\r               userrec* olduser = oldnick->second;\r            (*(ServerInstance->clientlist))[New] = olduser;\r                ServerInstance->clientlist->erase(oldnick);\r            return olduser;\r        }\r\r     catch (...)\r    {\r              ServerInstance->Log(DEBUG,"Exception in userrec::UpdateNickHash()");\r           return NULL;\r   }\r}\r\rvoid userrec::InvalidateCache()\r{\r /* Invalidate cache */\r if (cached_fullhost)\r           free(cached_fullhost);\r if (cached_hostip)\r             free(cached_hostip);\r   if (cached_makehost)\r           free(cached_makehost);\r if (cached_fullrealhost)\r               free(cached_fullrealhost);\r     cached_fullhost = cached_hostip = cached_makehost = cached_fullrealhost = NULL;\r}\r\rbool userrec::ForceNickChange(const char* newnick)\r{\r        try\r    {\r              int MOD_RESULT = 0;\r\r           this->InvalidateCache();\r\r              FOREACH_RESULT(I_OnUserPreNick,OnUserPreNick(this, newnick));\r\r         if (MOD_RESULT)\r                {\r                      ServerInstance->stats->statsCollisions++;\r                      return false;\r          }\r\r             if (ServerInstance->XLines->matches_qline(newnick))\r            {\r                      ServerInstance->stats->statsCollisions++;\r                      return false;\r          }\r\r             if (this->registered == REG_ALL)\r               {\r                      return (ServerInstance->Parser->CallHandler("NICK", &newnick, 1, this) == CMD_SUCCESS);\r                }\r              return false;\r  }\r\r     catch (...)\r    {\r              ServerInstance->Log(DEBUG,"Exception in userrec::ForceNickChange()");\r          return false;\r  }\r}\r\rvoid userrec::SetSockAddr(int protocol_family, const char* ip, int port)\r{\r        switch (protocol_family)\r       {\r#ifdef SUPPORT_IP6LINKS\r              case AF_INET6:\r         {\r                      sockaddr_in6* sin = new sockaddr_in6;\r                  sin->sin6_family = AF_INET6;\r                   sin->sin6_port = port;\r                 inet_pton(AF_INET6, ip, &sin->sin6_addr);\r                      this->ip = (sockaddr*)sin;\r             }\r              break;\r#endif\r          case AF_INET:\r          {\r                      sockaddr_in* sin = new sockaddr_in;\r                    sin->sin_family = AF_INET;\r                     sin->sin_port = port;\r                  inet_pton(AF_INET, ip, &sin->sin_addr);\r                        this->ip = (sockaddr*)sin;\r             }\r              break;\r         default:\r                       ServerInstance->Log(DEBUG,"Ut oh, I dont know protocol %d to be set on '%s'!", protocol_family, this->nick);\r           break;\r }\r}\r\rint userrec::GetPort()\r{\r  if (this->ip == NULL)\r          return 0;\r\r     switch (this->GetProtocolFamily())\r     {\r#ifdef SUPPORT_IP6LINKS\r              case AF_INET6:\r         {\r                      sockaddr_in6* sin = (sockaddr_in6*)this->ip;\r                   return sin->sin6_port;\r         }\r              break;\r#endif\r          case AF_INET:\r          {\r                      sockaddr_in* sin = (sockaddr_in*)this->ip;\r                     return sin->sin_port;\r          }\r              break;\r         default:\r               break;\r }\r      return 0;\r}\r\rint userrec::GetProtocolFamily()\r{\r        if (this->ip == NULL)\r          return 0;\r\r     sockaddr_in* sin = (sockaddr_in*)this->ip;\r     return sin->sin_family;\r}\r\rconst char* userrec::GetIPString()\r{\r        static char buf[1024];\r\r        if (this->ip == NULL)\r          return "";\r\r    switch (this->GetProtocolFamily())\r     {\r#ifdef SUPPORT_IP6LINKS\r              case AF_INET6:\r         {\r                      static char temp[1024];\r\r                       sockaddr_in6* sin = (sockaddr_in6*)this->ip;\r                   inet_ntop(sin->sin6_family, &sin->sin6_addr, buf, sizeof(buf));\r                        /* IP addresses starting with a : on irc are a Bad Thing (tm) */\r                       if (*buf == ':')\r                       {\r                              strlcpy(&temp[1], buf, sizeof(temp) - 1);\r                              *temp = '0';\r                           return temp;\r                   }\r                      return buf;\r            }\r              break;\r#endif\r          case AF_INET:\r          {\r                      sockaddr_in* sin = (sockaddr_in*)this->ip;\r                     inet_ntop(sin->sin_family, &sin->sin_addr, buf, sizeof(buf));\r                  return buf;\r            }\r              break;\r         default:\r               break;\r }\r      return "";\r}\r\rconst char* userrec::GetIPString(char* buf)\r{\r    if (this->ip == NULL)\r  {\r              *buf = 0;\r              return buf;\r    }\r\r     switch (this->GetProtocolFamily())\r     {\r#ifdef SUPPORT_IP6LINKS\r              case AF_INET6:\r         {\r                      static char temp[1024];\r\r                       sockaddr_in6* sin = (sockaddr_in6*)this->ip;\r                   inet_ntop(sin->sin6_family, &sin->sin6_addr, buf, sizeof(buf));\r                        /* IP addresses starting with a : on irc are a Bad Thing (tm) */\r                       if (*buf == ':')\r                       {\r                              strlcpy(&temp[1], buf, sizeof(temp) - 1);\r                              *temp = '0';\r                           strlcpy(buf, temp, sizeof(temp));\r                      }\r                      return buf;\r            }\r              break;\r#endif\r          case AF_INET:\r          {\r                      sockaddr_in* sin = (sockaddr_in*)this->ip;\r                     inet_ntop(sin->sin_family, &sin->sin_addr, buf, sizeof(buf));\r                  return buf;\r            }\r              break;\r\r                default:\r               break;\r }\r      return "";\r}\r\r/** NOTE: We cannot pass a const reference to this method.\r * The string is changed by the workings of the method,\r * so that if we pass const ref, we end up copying it to\r * something we can change anyway. Makes sense to just let\r * the compiler do that copy for us.\r */\rvoid userrec::Write(std::string text)\r{\r#ifdef WINDOWS\r   if ((this->fd < 0) || (this->m_internalFd > MAX_DESCRIPTORS))\r#else\r    if ((this->fd < 0) || (this->fd > MAX_DESCRIPTORS))\r#endif\r             return;\r\r       try\r    {\r              /* ServerInstance->Log(DEBUG,"C[%d] <- %s", this->GetFd(), text.c_str());\r               * WARNING: The above debug line is VERY loud, do NOT\r           * enable it till we have a good way of filtering it\r            * out of the logs (e.g. 1.2 would be good).\r            */\r            text.append("\r\n");\r   }\r      catch (...)\r    {\r              ServerInstance->Log(DEBUG,"Exception in userrec::Write() std::string::append");\r                return;\r        }\r\r     if (ServerInstance->Config->GetIOHook(this->GetPort()))\r        {\r              try\r            {\r                      /* XXX: The lack of buffering here is NOT a bug, modules implementing this interface have to\r                    * implement their own buffering mechanisms\r                     */\r                    ServerInstance->Config->GetIOHook(this->GetPort())->OnRawSocketWrite(this->fd, text.data(), text.length());\r            }\r              catch (CoreException& modexcept)\r               {\r                      ServerInstance->Log(DEBUG, "%s threw an exception: %s", modexcept.GetSource(), modexcept.GetReason());\r         }\r      }\r      else\r   {\r              this->AddWriteBuf(text);\r       }\r      ServerInstance->stats->statsSent += text.length();\r     this->ServerInstance->SE->WantWrite(this);\r}\r\r/** Write()\r */\rvoid userrec::Write(const char *text, ...)\r{\r     va_list argsPtr;\r       char textbuffer[MAXBUF];\r\r      va_start(argsPtr, text);\r       vsnprintf(textbuffer, MAXBUF, text, argsPtr);\r  va_end(argsPtr);\r\r      this->Write(std::string(textbuffer));\r}\r\rvoid userrec::WriteServ(const std::string& text)\r{\r    char textbuffer[MAXBUF];\r\r      snprintf(textbuffer,MAXBUF,":%s %s",ServerInstance->Config->ServerName,text.c_str());\r  this->Write(std::string(textbuffer));\r}\r\r/** WriteServ()\r *  Same as Write(), except `text' is prefixed with `:server.name '.\r */\rvoid userrec::WriteServ(const char* text, ...)\r{\r     va_list argsPtr;\r       char textbuffer[MAXBUF];\r\r      va_start(argsPtr, text);\r       vsnprintf(textbuffer, MAXBUF, text, argsPtr);\r  va_end(argsPtr);\r\r      this->WriteServ(std::string(textbuffer));\r}\r\r\rvoid userrec::WriteFrom(userrec *user, const std::string &text)\r{\r        char tb[MAXBUF];\r\r      snprintf(tb,MAXBUF,":%s %s",user->GetFullHost(),text.c_str());\r\r        this->Write(std::string(tb));\r}\r\r\r/* write text from an originating user to originating user */\r\rvoid userrec::WriteFrom(userrec *user, const char* text, ...)\r{\r       va_list argsPtr;\r       char textbuffer[MAXBUF];\r\r      va_start(argsPtr, text);\r       vsnprintf(textbuffer, MAXBUF, text, argsPtr);\r  va_end(argsPtr);\r\r      this->WriteFrom(user, std::string(textbuffer));\r}\r\r\r/* write text to an destination user from a source user (e.g. user privmsg) */\r\rvoid userrec::WriteTo(userrec *dest, const char *data, ...)\r{\r      char textbuffer[MAXBUF];\r       va_list argsPtr;\r\r      va_start(argsPtr, data);\r       vsnprintf(textbuffer, MAXBUF, data, argsPtr);\r  va_end(argsPtr);\r\r      this->WriteTo(dest, std::string(textbuffer));\r}\r\rvoid userrec::WriteTo(userrec *dest, const std::string &data)\r{\r       dest->WriteFrom(this, data);\r}\r\r\rvoid userrec::WriteCommon(const char* text, ...)\r{\r    char textbuffer[MAXBUF];\r       va_list argsPtr;\r\r      if (this->registered != REG_ALL)\r               return;\r\r       va_start(argsPtr, text);\r       vsnprintf(textbuffer, MAXBUF, text, argsPtr);\r  va_end(argsPtr);\r\r      this->WriteCommon(std::string(textbuffer));\r}\r\rvoid userrec::WriteCommon(const std::string &text)\r{\r    try\r    {\r              bool sent_to_at_least_one = false;\r             char tb[MAXBUF];\r\r              if (this->registered != REG_ALL)\r                       return;\r\r               uniq_id++;\r\r            /* We dont want to be doing this n times, just once */\r         snprintf(tb,MAXBUF,":%s %s",this->GetFullHost(),text.c_str());\r         std::string out = tb;\r\r         for (UCListIter v = this->chans.begin(); v != this->chans.end(); v++)\r          {\r                      CUList* ulist = v->first->GetUsers();\r                  for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)\r                      {\r                              if ((IS_LOCAL(i->first)) && (already_sent[i->first->fd] != uniq_id))\r                           {\r                                      already_sent[i->first->fd] = uniq_id;\r                                  i->first->Write(out);\r                                  sent_to_at_least_one = true;\r                           }\r                      }\r              }\r\r             /*\r              * if the user was not in any channels, no users will receive the text. Make sure the user\r              * receives their OWN message for WriteCommon\r           */\r            if (!sent_to_at_least_one)\r             {\r                      this->Write(std::string(tb));\r          }\r      }\r\r     catch (...)\r    {\r              ServerInstance->Log(DEBUG,"Exception in userrec::WriteCommon()");\r      }\r}\r\r\r/* write a formatted string to all users who share at least one common\r * channel, NOT including the source user e.g. for use in QUIT\r */\r\rvoid userrec::WriteCommonExcept(const char* text, ...)\r{\r      char textbuffer[MAXBUF];\r       va_list argsPtr;\r\r      va_start(argsPtr, text);\r       vsnprintf(textbuffer, MAXBUF, text, argsPtr);\r  va_end(argsPtr);\r\r      this->WriteCommonExcept(std::string(textbuffer));\r}\r\rvoid userrec::WriteCommonQuit(const std::string &normal_text, const std::string &oper_text)\r{\r     char tb1[MAXBUF];\r      char tb2[MAXBUF];\r\r     if (this->registered != REG_ALL)\r               return;\r\r       uniq_id++;\r     snprintf(tb1,MAXBUF,":%s QUIT :%s",this->GetFullHost(),normal_text.c_str());\r   snprintf(tb2,MAXBUF,":%s QUIT :%s",this->GetFullHost(),oper_text.c_str());\r     std::string out1 = tb1;\r        std::string out2 = tb2;\r\r       for (UCListIter v = this->chans.begin(); v != this->chans.end(); v++)\r  {\r              CUList *ulist = v->first->GetUsers();\r          for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)\r              {\r                      if (this != i->first)\r                  {\r                              if ((IS_LOCAL(i->first)) && (already_sent[i->first->fd] != uniq_id))\r                           {\r                                      already_sent[i->first->fd] = uniq_id;\r                                  i->first->Write(IS_OPER(i->first) ? out2 : out1);\r                              }\r                      }\r              }\r      }\r}\r\rvoid userrec::WriteCommonExcept(const std::string &text)\r{\r        char tb1[MAXBUF];\r      std::string out1;\r\r     if (this->registered != REG_ALL)\r               return;\r\r       uniq_id++;\r     snprintf(tb1,MAXBUF,":%s %s",this->GetFullHost(),text.c_str());\r        out1 = tb1;\r\r   for (UCListIter v = this->chans.begin(); v != this->chans.end(); v++)\r  {\r              CUList *ulist = v->first->GetUsers();\r          for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)\r              {\r                      if (this != i->first)\r                  {\r                              if ((IS_LOCAL(i->first)) && (already_sent[i->first->fd] != uniq_id))\r                           {\r                                      already_sent[i->first->fd] = uniq_id;\r                                  i->first->Write(out1);\r                         }\r                      }\r              }\r      }\r\r}\r\rvoid userrec::WriteWallOps(const std::string &text)\r{\r    if (!IS_OPER(this) && IS_LOCAL(this))\r          return;\r\r       std::string wallop("WALLOPS :");\r       wallop.append(text);\r\r  for (std::vector<userrec*>::const_iterator i = ServerInstance->local_users.begin(); i != ServerInstance->local_users.end(); i++)\r       {\r              userrec* t = *i;\r               if (t->modes[UM_WALLOPS])\r                      this->WriteTo(t,wallop);\r       }\r}\r\rvoid userrec::WriteWallOps(const char* text, ...)\r{\r       char textbuffer[MAXBUF];\r       va_list argsPtr;\r\r      va_start(argsPtr, text);\r       vsnprintf(textbuffer, MAXBUF, text, argsPtr);\r  va_end(argsPtr);\r\r      this->WriteWallOps(std::string(textbuffer));\r}\r\r/* return 0 or 1 depending if users u and u2 share one or more common channels\r * (used by QUIT, NICK etc which arent channel specific notices)\r *\r * The old algorithm in 1.0 for this was relatively inefficient, iterating over\r * the first users channels then the second users channels within the outer loop,\r * therefore it was a maximum of x*y iterations (upon returning 0 and checking\r * all possible iterations). However this new function instead checks against the\r * channel's userlist in the inner loop which is a std::map<userrec*,userrec*>\r * and saves us time as we already know what pointer value we are after.\r * Don't quote me on the maths as i am not a mathematician or computer scientist,\r * but i believe this algorithm is now x+(log y) maximum iterations instead.\r */\rbool userrec::SharesChannelWith(userrec *other)\r{\r     if ((!other) || (this->registered != REG_ALL) || (other->registered != REG_ALL))\r               return false;\r\r /* Outer loop */\r       for (UCListIter i = this->chans.begin(); i != this->chans.end(); i++)\r  {\r              /* Eliminate the inner loop (which used to be ~equal in size to the outer loop)\r                 * by replacing it with a map::find which *should* be more efficient\r            */\r            if (i->first->HasUser(other))\r                  return true;\r   }\r      return false;\r}\r\rbool userrec::ChangeName(const char* gecos)\r{\r if (!strcmp(gecos, this->fullname))\r            return true;\r\r  if (IS_LOCAL(this))\r    {\r              int MOD_RESULT = 0;\r            FOREACH_RESULT(I_OnChangeLocalUserGECOS,OnChangeLocalUserGECOS(this,gecos));\r           if (MOD_RESULT)\r                        return false;\r          FOREACH_MOD(I_OnChangeName,OnChangeName(this,gecos));\r  }\r      strlcpy(this->fullname,gecos,MAXGECOS+1);\r\r     return true;\r}\r\rbool userrec::ChangeDisplayedHost(const char* host)\r{\r  if (!strcmp(host, this->dhost))\r                return true;\r\r  if (IS_LOCAL(this))\r    {\r              int MOD_RESULT = 0;\r            FOREACH_RESULT(I_OnChangeLocalUserHost,OnChangeLocalUserHost(this,host));\r              if (MOD_RESULT)\r                        return false;\r          FOREACH_MOD(I_OnChangeHost,OnChangeHost(this,host));\r   }\r      if (this->ServerInstance->Config->CycleHosts)\r          this->WriteCommonExcept("QUIT :Changing hosts");\r\r      /* Fix by Om: userrec::dhost is 65 long, this was truncating some long hosts */\r        strlcpy(this->dhost,host,64);\r\r this->InvalidateCache();\r\r      if (this->ServerInstance->Config->CycleHosts)\r  {\r              for (UCListIter i = this->chans.begin(); i != this->chans.end(); i++)\r          {\r                      i->first->WriteAllExceptSender(this, false, 0, "JOIN %s", i->first->name);\r                     std::string n = this->ServerInstance->Modes->ModeString(this, i->first);\r                       if (n.length() > 0)\r                            i->first->WriteAllExceptSender(this, true, 0, "MODE %s +%s", i->first->name, n.c_str());\r               }\r      }\r\r     if (IS_LOCAL(this))\r            this->WriteServ("396 %s %s :is now your displayed host",this->nick,this->dhost);\r\r      return true;\r}\r\rbool userrec::ChangeIdent(const char* newident)\r{\r      if (!strcmp(newident, this->ident))\r            return true;\r\r  if (this->ServerInstance->Config->CycleHosts)\r          this->WriteCommonExcept("%s","QUIT :Changing ident");\r\r strlcpy(this->ident, newident, IDENTMAX+2);\r\r   this->InvalidateCache();\r\r      if (this->ServerInstance->Config->CycleHosts)\r  {\r              for (UCListIter i = this->chans.begin(); i != this->chans.end(); i++)\r          {\r                      i->first->WriteAllExceptSender(this, false, 0, "JOIN %s", i->first->name);\r                     std::string n = this->ServerInstance->Modes->ModeString(this, i->first);\r                       if (n.length() > 0)\r                            i->first->WriteAllExceptSender(this, true, 0, "MODE %s +%s", i->first->name, n.c_str());\r               }\r      }\r\r     return true;\r}\r\rvoid userrec::SendAll(const char* command, char* text, ...)\r{\r  char textbuffer[MAXBUF];\r       char formatbuffer[MAXBUF];\r     va_list argsPtr;\r\r      va_start(argsPtr, text);\r       vsnprintf(textbuffer, MAXBUF, text, argsPtr);\r  va_end(argsPtr);\r\r      snprintf(formatbuffer,MAXBUF,":%s %s $* :%s", this->GetFullHost(), command, textbuffer);\r       std::string fmt = formatbuffer;\r\r       for (std::vector<userrec*>::const_iterator i = ServerInstance->local_users.begin(); i != ServerInstance->local_users.end(); i++)\r       {\r              (*i)->Write(fmt);\r      }\r}\r\r\rstd::string userrec::ChannelList(userrec* source)\r{\r      try\r    {\r              std::string list;\r              for (UCListIter i = this->chans.begin(); i != this->chans.end(); i++)\r          {\r                      /* If the target is the same as the sender, let them see all their channels.\r                    * If the channel is NOT private/secret OR the user shares a common channel\r                     * If the user is an oper, and the <options:operspywhois> option is set.\r                        */\r                    if ((source == this) || (IS_OPER(source) && ServerInstance->Config->OperSpyWhois) || (((!i->first->modes[CM_PRIVATE]) && (!i->first->modes[CM_SECRET])) || (i->first->HasUser(source))))\r                       {\r                              list.append(i->first->GetPrefixChar(this)).append(i->first->name).append(" ");\r                 }\r              }\r              return list;\r   }\r      catch (...)\r    {\r              ServerInstance->Log(DEBUG,"Exception in userrec::ChannelList()");\r              return "";\r     }\r}\r\rvoid userrec::SplitChanList(userrec* dest, const std::string &cl)\r{\r       std::string line;\r      std::ostringstream prefix;\r     std::string::size_type start, pos, length;\r\r    try\r    {\r              prefix << this->nick << " " << dest->nick << " :";\r             line = prefix.str();\r           int namelen = strlen(ServerInstance->Config->ServerName) + 6;\r\r         for (start = 0; (pos = cl.find(' ', start)) != std::string::npos; start = pos+1)\r               {\r                      length = (pos == std::string::npos) ? cl.length() : pos;\r\r                      if (line.length() + namelen + length - start > 510)\r                    {\r                              ServerInstance->SendWhoisLine(this, dest, 319, "%s", line.c_str());\r                            line = prefix.str();\r                   }\r\r                     if(pos == std::string::npos)\r                   {\r                              line.append(cl.substr(start, length - start));\r                         break;\r                 }\r                      else\r                   {\r                              line.append(cl.substr(start, length - start + 1));\r                     }\r              }\r\r             if (line.length())\r             {\r                      ServerInstance->SendWhoisLine(this, dest, 319, "%s", line.c_str());\r            }\r      }\r\r     catch (...)\r    {\r              ServerInstance->Log(DEBUG,"Exception in userrec::SplitChanList()");\r    }\r}\r\r\r/* looks up a users password for their connection class (<ALLOW>/<DENY> tags)\r * NOTE: If the <ALLOW> or <DENY> tag specifies an ip, and this user resolves,\r * then their ip will be taken as 'priority' anyway, so for example,\r * <connect allow="127.0.0.1"> will match joe!bloggs@localhost\r */\rConnectClass* userrec::GetClass()\r{\r for (ClassVector::iterator i = ServerInstance->Config->Classes.begin(); i != ServerInstance->Config->Classes.end(); i++)\r       {\r              if (((match(this->GetIPString(),i->GetHost().c_str(),true)) || (match(this->host,i->GetHost().c_str()))))\r              {\r                      if (i->GetPort())\r                      {\r                              if (this->GetPort() == i->GetPort())\r                                   return &(*i);\r                          else\r                                   continue;\r                      }\r                      else\r                           return &(*i);\r          }\r      }\r      return NULL;\r}\r\rvoid userrec::PurgeEmptyChannels()\r{\r   std::vector<chanrec*> to_delete;\r\r      // firstly decrement the count on each channel\r for (UCListIter f = this->chans.begin(); f != this->chans.end(); f++)\r  {\r              f->first->RemoveAllPrefixes(this);\r             if (f->first->DelUser(this) == 0)\r              {\r                      /* No users left in here, mark it for deletion */\r                      try\r                    {\r                              to_delete.push_back(f->first);\r                 }\r                      catch (...)\r                    {\r                              ServerInstance->Log(DEBUG,"Exception in userrec::PurgeEmptyChannels to_delete.push_back()");\r                   }\r              }\r      }\r\r     for (std::vector<chanrec*>::iterator n = to_delete.begin(); n != to_delete.end(); n++)\r {\r              chanrec* thischan = *n;\r                chan_hash::iterator i2 = ServerInstance->chanlist->find(thischan->name);\r               if (i2 != ServerInstance->chanlist->end())\r             {\r                      FOREACH_MOD(I_OnChannelDelete,OnChannelDelete(i2->second));\r                    DELETE(i2->second);\r                    ServerInstance->chanlist->erase(i2);\r                   this->chans.erase(*n);\r         }\r      }\r\r     this->UnOper();\r}\r\rvoid userrec::ShowMOTD()\r{\r  if (!ServerInstance->Config->MOTD.size())\r      {\r              this->WriteServ("422 %s :Message of the day file is missing.",this->nick);\r             return;\r        }\r      this->WriteServ("375 %s :%s message of the day", this->nick, ServerInstance->Config->ServerName);\r\r     for (file_cache::iterator i = ServerInstance->Config->MOTD.begin(); i != ServerInstance->Config->MOTD.end(); i++)\r              this->WriteServ("372 %s :- %s",this->nick,i->c_str());\r\r        this->WriteServ("376 %s :End of message of the day.", this->nick);\r}\r\rvoid userrec::ShowRULES()\r{\r      if (!ServerInstance->Config->RULES.size())\r     {\r              this->WriteServ("NOTICE %s :Rules file is missing.",this->nick);\r               return;\r        }\r      this->WriteServ("NOTICE %s :%s rules",this->nick,ServerInstance->Config->ServerName);\r\r for (file_cache::iterator i = ServerInstance->Config->RULES.begin(); i != ServerInstance->Config->RULES.end(); i++)\r            this->WriteServ("NOTICE %s :%s",this->nick,i->c_str());\r\r       this->WriteServ("NOTICE %s :End of %s rules.",this->nick,ServerInstance->Config->ServerName);\r}\r\rvoid userrec::HandleEvent(EventType et, int errornum)\r{\r       /* WARNING: May delete this user! */\r   int thisfd = this->GetFd();\r\r   try\r    {\r              switch (et)\r            {\r                      case EVENT_READ:\r                               ServerInstance->ProcessUser(this);\r                     break;\r                 case EVENT_WRITE:\r                              this->FlushWriteBuf();\r                 break;\r                 case EVENT_ERROR:\r                              /** This should be safe, but dont DARE do anything after it -- Brain */\r                                this->SetWriteError(errornum ? strerror(errornum) : "EOF from client");\r                        break;\r         }\r      }\r      catch (...)\r    {\r              ServerInstance->Log(DEBUG,"Exception in userrec::HandleEvent intercepted");\r    }\r\r     /* If the user has raised an error whilst being processed, quit them now we're safe to */\r      if ((ServerInstance->SE->GetRef(thisfd) == this))\r      {\r              if (!WriteError.empty())\r               {\r                      userrec::QuitUser(ServerInstance, this, GetWriteError());\r              }\r      }\r}\r\rvoid userrec::SetOperQuit(const std::string &oquit)\r{\r     if (operquit)\r          return;\r\r       operquit = strdup(oquit.c_str());\r}\r\rconst char* userrec::GetOperQuit()\r{\r      return operquit ? operquit : "";\r}\r\rVisData::VisData()\r{\r}\r\rVisData::~VisData()\r{\r}\r\rbool VisData::VisibleTo(userrec* user)\r{\r  return true;\r}\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "configreader.h"
+#include "channels.h"
+#include "users.h"
+#include <stdarg.h>
+#include "socketengine.h"
+#include "wildcard.h"
+#include "xline.h"
+#include "commands/cmd_whowas.h"
+
+static unsigned long already_sent[MAX_DESCRIPTORS] = {0};
+
+/* XXX: Used for speeding up WriteCommon operations */
+unsigned long uniq_id = 0;
+
+bool InitTypes(ServerConfig* conf, const char* tag)
+{
+       if (conf->opertypes.size())
+       {
+               for (opertype_t::iterator n = conf->opertypes.begin(); n != conf->opertypes.end(); n++)
+               {
+                       if (n->second)
+                               delete[] n->second;
+               }
+       }
+
+       conf->opertypes.clear();
+       return true;
+}
+
+bool InitClasses(ServerConfig* conf, const char* tag)
+{
+       if (conf->operclass.size())
+       {
+               for (operclass_t::iterator n = conf->operclass.begin(); n != conf->operclass.end(); n++)
+               {
+                       if (n->second)
+                               delete[] n->second;
+               }
+       }
+
+       conf->operclass.clear();
+       return true;
+}
+
+bool DoType(ServerConfig* conf, const char* tag, char** entries, ValueList &values, int* types)
+{
+       const char* TypeName = values[0].GetString();
+       const char* Classes = values[1].GetString();
+
+       conf->opertypes[TypeName] = strnewdup(Classes);
+       return true;
+}
+
+bool DoClass(ServerConfig* conf, const char* tag, char** entries, ValueList &values, int* types)
+{
+       const char* ClassName = values[0].GetString();
+       const char* CommandList = values[1].GetString();
+
+       conf->operclass[ClassName] = strnewdup(CommandList);
+       return true;
+}
+
+bool DoneClassesAndTypes(ServerConfig* conf, const char* tag)
+{
+       return true;
+}
+
+std::string userrec::ProcessNoticeMasks(const char *sm)
+{
+       bool adding = true, oldadding = false;
+       const char *c = sm;
+       std::string output;
+
+       while (c && *c)
+       {
+               switch (*c)
+               {
+                       case '+':
+                               adding = true;
+                       break;
+                       case '-':
+                               adding = false;
+                       break;
+                       case '*':
+                               for (unsigned char d = 'A'; d <= 'z'; d++)
+                               {
+                                       if (ServerInstance->SNO->IsEnabled(d))
+                                       {
+                                               if ((!IsNoticeMaskSet(d) && adding) || (IsNoticeMaskSet(d) && !adding))
+                                               {
+                                                       if ((oldadding != adding) || (!output.length()))
+                                                               output += (adding ? '+' : '-');
+
+                                                       this->SetNoticeMask(d, adding);
+
+                                                       output += d;
+                                               }
+                                       }
+                                       oldadding = adding;
+                               }
+                       break;
+                       default:
+                               if ((*c >= 'A') && (*c <= 'z') && (ServerInstance->SNO->IsEnabled(*c)))
+                               {
+                                       if ((!IsNoticeMaskSet(*c) && adding) || (IsNoticeMaskSet(*c) && !adding))
+                                       {
+                                               if ((oldadding != adding) || (!output.length()))
+                                                       output += (adding ? '+' : '-');
+
+                                               this->SetNoticeMask(*c, adding);
+
+                                               output += *c;
+                                       }
+                               }
+                               oldadding = adding;
+                       break;
+               }
+
+               *c++;
+       }
+
+       return output;
+}
+
+void userrec::StartDNSLookup()
+{
+       try
+       {
+               bool cached;
+               const char* ip = this->GetIPString();
+
+               /* Special case for 4in6 (Have i mentioned i HATE 4in6?) */
+               if (!strncmp(ip, "0::ffff:", 8))
+                       res_reverse = new UserResolver(this->ServerInstance, this, ip + 8, DNS_QUERY_PTR4, cached);
+               else
+                       res_reverse = new UserResolver(this->ServerInstance, this, ip, this->GetProtocolFamily() == AF_INET ? DNS_QUERY_PTR4 : DNS_QUERY_PTR6, cached);
+
+               this->ServerInstance->AddResolver(res_reverse, cached);
+       }
+       catch (CoreException& e)
+       {
+               ServerInstance->Log(DEBUG,"Error in resolver: %s",e.GetReason());
+       }
+}
+
+UserResolver::UserResolver(InspIRCd* Instance, userrec* user, std::string to_resolve, QueryType qt, bool &cache) :
+       Resolver(Instance, to_resolve, qt, cache), bound_user(user)
+{
+       this->fwd = (qt == DNS_QUERY_A || qt == DNS_QUERY_AAAA);
+       this->bound_fd = user->GetFd();
+}
+
+void UserResolver::OnLookupComplete(const std::string &result, unsigned int ttl, bool cached)
+{
+       if ((!this->fwd) && (ServerInstance->SE->GetRef(this->bound_fd) == this->bound_user))
+       {
+               this->bound_user->stored_host = result;
+               try
+               {
+                       /* Check we didnt time out */
+                       if (this->bound_user->registered != REG_ALL)
+                       {
+                               bool cached;
+#ifdef IPV6
+                               if (this->bound_user->GetProtocolFamily() == AF_INET6)
+                               {
+                                       /* IPV6 forward lookup (with possibility of 4in6) */
+                                       const char* ip = this->bound_user->GetIPString();
+                                       bound_user->res_forward = new UserResolver(this->ServerInstance, this->bound_user, result, (!strncmp(ip, "0::ffff:", 8) ? DNS_QUERY_A : DNS_QUERY_AAAA), cached);
+                               }
+                               else
+                                       /* IPV4 lookup (mixed protocol mode) */
+#endif
+                               /* IPV4 lookup (ipv4 only mode) */
+                               bound_user->res_forward = new UserResolver(this->ServerInstance, this->bound_user, result, DNS_QUERY_A, cached);
+                               this->ServerInstance->AddResolver(bound_user->res_forward, cached);
+                       }
+               }
+               catch (CoreException& e)
+               {
+                       ServerInstance->Log(DEBUG,"Error in resolver: %s",e.GetReason());
+               }
+       }
+       else if ((this->fwd) && (ServerInstance->SE->GetRef(this->bound_fd) == this->bound_user))
+       {
+               /* Both lookups completed */
+               std::string result2("0::ffff:");
+               result2.append(result);
+               if (this->bound_user->GetIPString() == result || this->bound_user->GetIPString() == result2)
+               {
+                       std::string hostname = this->bound_user->stored_host;
+                       if (hostname.length() < 65)
+                       {
+                               /* Check we didnt time out */
+                               if ((this->bound_user->registered != REG_ALL) && (!this->bound_user->dns_done))
+                               {
+                                       /* Hostnames starting with : are not a good thing (tm) */
+                                       if (*(hostname.c_str()) == ':')
+                                               hostname.insert(0, "0");
+
+                                       this->bound_user->WriteServ("NOTICE Auth :*** Found your hostname (%s)%s", hostname.c_str(), (cached ? " -- cached" : ""));
+                                       this->bound_user->dns_done = true;
+                                       strlcpy(this->bound_user->dhost, hostname.c_str(),64);
+                                       strlcpy(this->bound_user->host, hostname.c_str(),64);
+                                       /* Invalidate cache */
+                                       this->bound_user->InvalidateCache();
+                               }
+                       }
+                       else
+                       {
+                               if (!this->bound_user->dns_done)
+                               {
+                                       this->bound_user->WriteServ("NOTICE Auth :*** Your hostname is longer than the maximum of 64 characters, using your IP address (%s) instead.", this->bound_user->GetIPString());
+                                       this->bound_user->dns_done = true;
+                               }
+                       }
+               }
+               else
+               {
+                       if (!this->bound_user->dns_done)
+                       {
+                               this->bound_user->WriteServ("NOTICE Auth :*** Your hostname does not match up with your IP address. Sorry, using your IP address (%s) instead.", this->bound_user->GetIPString());
+                               this->bound_user->dns_done = true;
+                       }
+               }
+       }
+}
+
+void UserResolver::OnError(ResolverError e, const std::string &errormessage)
+{
+       if (ServerInstance->SE->GetRef(this->bound_fd) == this->bound_user)
+       {
+               /* Since dns timeout is implemented outside of the resolver, this was a race condition that could result in this message being sent *after*
+                * the user was fully connected. This check fixes that issue  - Special */
+               if (!this->bound_user->dns_done)
+               {
+                       /* Error message here */
+                       this->bound_user->WriteServ("NOTICE Auth :*** Could not resolve your hostname: %s; using your IP address (%s) instead.", errormessage.c_str(), this->bound_user->GetIPString());
+                       this->bound_user->dns_done = true;
+               }
+       }
+}
+
+
+bool userrec::IsNoticeMaskSet(unsigned char sm)
+{
+       return (snomasks[sm-65]);
+}
+
+void userrec::SetNoticeMask(unsigned char sm, bool value)
+{
+       snomasks[sm-65] = value;
+}
+
+const char* userrec::FormatNoticeMasks()
+{
+       static char data[MAXBUF];
+       int offset = 0;
+
+       for (int n = 0; n < 64; n++)
+       {
+               if (snomasks[n])
+                       data[offset++] = n+65;
+       }
+
+       data[offset] = 0;
+       return data;
+}
+
+
+
+bool userrec::IsModeSet(unsigned char m)
+{
+       return (modes[m-65]);
+}
+
+void userrec::SetMode(unsigned char m, bool value)
+{
+       modes[m-65] = value;
+}
+
+const char* userrec::FormatModes()
+{
+       static char data[MAXBUF];
+       int offset = 0;
+       for (int n = 0; n < 64; n++)
+       {
+               if (modes[n])
+                       data[offset++] = n+65;
+       }
+       data[offset] = 0;
+       return data;
+}
+
+void userrec::DecrementModes()
+{
+       for (int n = 0; n < 64; n++)
+       {
+               if (modes[n])
+               {
+                       ModeHandler* mh = ServerInstance->Modes->FindMode(n+65, MODETYPE_USER);
+                       if (mh)
+                               mh->ChangeCount(-1);
+               }
+       }
+}
+
+userrec::userrec(InspIRCd* Instance) : ServerInstance(Instance)
+{
+       // the PROPER way to do it, AVOID bzero at *ALL* costs
+       *password = *nick = *ident = *host = *dhost = *fullname = *awaymsg = *oper = 0;
+       server = (char*)Instance->FindServerNamePtr(Instance->Config->ServerName);
+       reset_due = ServerInstance->Time();
+       age = ServerInstance->Time(true);
+       lines_in = lastping = signon = idle_lastmsg = nping = registered = 0;
+       ChannelCount = timeout = flood = bytes_in = bytes_out = cmds_in = cmds_out = 0;
+       muted = exempt = haspassed = dns_done = false;
+       fd = -1;
+       recvq.clear();
+       sendq.clear();
+       WriteError.clear();
+       res_forward = res_reverse = NULL;
+       Visibility = NULL;
+       ip = NULL;
+       chans.clear();
+       invites.clear();
+       memset(modes,0,sizeof(modes));
+       memset(snomasks,0,sizeof(snomasks));
+       /* Invalidate cache */
+       operquit = cached_fullhost = cached_hostip = cached_makehost = cached_fullrealhost = NULL;
+}
+
+void userrec::RemoveCloneCounts()
+{
+       clonemap::iterator x = ServerInstance->local_clones.find(this->GetIPString());
+       if (x != ServerInstance->local_clones.end())
+       {
+               x->second--;
+               if (!x->second)
+               {
+                       ServerInstance->local_clones.erase(x);
+               }
+       }
+       
+       clonemap::iterator y = ServerInstance->global_clones.find(this->GetIPString());
+       if (y != ServerInstance->global_clones.end())
+       {
+               y->second--;
+               if (!y->second)
+               {
+                       ServerInstance->global_clones.erase(y);
+               }
+       }
+}
+
+userrec::~userrec()
+{
+       this->InvalidateCache();
+       this->DecrementModes();
+       if (operquit)
+               free(operquit);
+       if (ip)
+       {
+               this->RemoveCloneCounts();
+
+               if (this->GetProtocolFamily() == AF_INET)
+               {
+                       delete (sockaddr_in*)ip;
+               }
+#ifdef SUPPORT_IP6LINKS
+               else
+               {
+                       delete (sockaddr_in6*)ip;
+               }
+#endif
+       }
+}
+
+char* userrec::MakeHost()
+{
+       if (this->cached_makehost)
+               return this->cached_makehost;
+
+       char nhost[MAXBUF];
+       /* This is much faster than snprintf */
+       char* t = nhost;
+       for(char* n = ident; *n; n++)
+               *t++ = *n;
+       *t++ = '@';
+       for(char* n = host; *n; n++)
+               *t++ = *n;
+       *t = 0;
+
+       this->cached_makehost = strdup(nhost);
+
+       return this->cached_makehost;
+}
+
+char* userrec::MakeHostIP()
+{
+       if (this->cached_hostip)
+               return this->cached_hostip;
+
+       char ihost[MAXBUF];
+       /* This is much faster than snprintf */
+       char* t = ihost;
+       for(char* n = ident; *n; n++)
+               *t++ = *n;
+       *t++ = '@';
+       for(const char* n = this->GetIPString(); *n; n++)
+               *t++ = *n;
+       *t = 0;
+
+       this->cached_hostip = strdup(ihost);
+
+       return this->cached_hostip;
+}
+
+void userrec::CloseSocket()
+{
+       shutdown(this->fd,2);
+       close(this->fd);
+}
+
+char* userrec::GetFullHost()
+{
+       if (this->cached_fullhost)
+               return this->cached_fullhost;
+
+       char result[MAXBUF];
+       char* t = result;
+       for(char* n = nick; *n; n++)
+               *t++ = *n;
+       *t++ = '!';
+       for(char* n = ident; *n; n++)
+               *t++ = *n;
+       *t++ = '@';
+       for(char* n = dhost; *n; n++)
+               *t++ = *n;
+       *t = 0;
+
+       this->cached_fullhost = strdup(result);
+
+       return this->cached_fullhost;
+}
+
+char* userrec::MakeWildHost()
+{
+       static char nresult[MAXBUF];
+       char* t = nresult;
+       *t++ = '*';     *t++ = '!';
+       *t++ = '*';     *t++ = '@';
+       for(char* n = dhost; *n; n++)
+               *t++ = *n;
+       *t = 0;
+       return nresult;
+}
+
+int userrec::ReadData(void* buffer, size_t size)
+{
+       if (IS_LOCAL(this))
+       {
+#ifndef WIN32
+               return read(this->fd, buffer, size);
+#else
+               return recv(this->fd, (char*)buffer, size, 0);
+#endif
+       }
+       else
+               return 0;
+}
+
+
+char* userrec::GetFullRealHost()
+{
+       if (this->cached_fullrealhost)
+               return this->cached_fullrealhost;
+
+       char fresult[MAXBUF];
+       char* t = fresult;
+       for(char* n = nick; *n; n++)
+               *t++ = *n;
+       *t++ = '!';
+       for(char* n = ident; *n; n++)
+               *t++ = *n;
+       *t++ = '@';
+       for(char* n = host; *n; n++)
+               *t++ = *n;
+       *t = 0;
+
+       this->cached_fullrealhost = strdup(fresult);
+
+       return this->cached_fullrealhost;
+}
+
+bool userrec::IsInvited(const irc::string &channel)
+{
+       for (InvitedList::iterator i = invites.begin(); i != invites.end(); i++)
+       {
+               if (channel == *i)
+               {
+                       return true;
+               }
+       }
+       return false;
+}
+
+InvitedList* userrec::GetInviteList()
+{
+       return &invites;
+}
+
+void userrec::InviteTo(const irc::string &channel)
+{
+       invites.push_back(channel);
+}
+
+void userrec::RemoveInvite(const irc::string &channel)
+{
+       for (InvitedList::iterator i = invites.begin(); i != invites.end(); i++)
+       {
+               if (channel == *i)
+               {
+                       invites.erase(i);
+                       return;
+               }
+       }
+}
+
+bool userrec::HasPermission(const std::string &command)
+{
+       char* mycmd;
+       char* savept;
+       char* savept2;
+
+       /*
+        * users on remote servers can completely bypass all permissions based checks.
+        * This prevents desyncs when one server has different type/class tags to another.
+        * That having been said, this does open things up to the possibility of source changes
+        * allowing remote kills, etc - but if they have access to the src, they most likely have
+        * access to the conf - so it's an end to a means either way.
+        */
+       if (!IS_LOCAL(this))
+               return true;
+
+       // are they even an oper at all?
+       if (IS_OPER(this))
+       {
+               opertype_t::iterator iter_opertype = ServerInstance->Config->opertypes.find(this->oper);
+               if (iter_opertype != ServerInstance->Config->opertypes.end())
+               {
+                       char* Classes = strdup(iter_opertype->second);
+                       char* myclass = strtok_r(Classes," ",&savept);
+                       while (myclass)
+                       {
+                               operclass_t::iterator iter_operclass = ServerInstance->Config->operclass.find(myclass);
+                               if (iter_operclass != ServerInstance->Config->operclass.end())
+                               {
+                                       char* CommandList = strdup(iter_operclass->second);
+                                       mycmd = strtok_r(CommandList," ",&savept2);
+                                       while (mycmd)
+                                       {
+                                               if ((!strcasecmp(mycmd,command.c_str())) || (*mycmd == '*'))
+                                               {
+                                                       free(Classes);
+                                                       free(CommandList);
+                                                       return true;
+                                               }
+                                               mycmd = strtok_r(NULL," ",&savept2);
+                                       }
+                                       free(CommandList);
+                               }
+                               myclass = strtok_r(NULL," ",&savept);
+                       }
+                       free(Classes);
+               }
+       }
+       return false;
+}
+
+/** NOTE: We cannot pass a const reference to this method.
+ * The string is changed by the workings of the method,
+ * so that if we pass const ref, we end up copying it to
+ * something we can change anyway. Makes sense to just let
+ * the compiler do that copy for us.
+ */
+bool userrec::AddBuffer(std::string a)
+{
+       try
+       {
+               std::string::size_type i = a.rfind('\r');
+
+               while (i != std::string::npos)
+               {
+                       a.erase(i, 1);
+                       i = a.rfind('\r');
+               }
+
+               if (a.length())
+                       recvq.append(a);
+
+               if (recvq.length() > (unsigned)this->recvqmax)
+               {
+                       this->SetWriteError("RecvQ exceeded");
+                       ServerInstance->WriteOpers("*** User %s RecvQ of %d exceeds connect class maximum of %d",this->nick,recvq.length(),this->recvqmax);
+                       return false;
+               }
+
+               return true;
+       }
+
+       catch (...)
+       {
+               ServerInstance->Log(DEBUG,"Exception in userrec::AddBuffer()");
+               return false;
+       }
+}
+
+bool userrec::BufferIsReady()
+{
+       return (recvq.find('\n') != std::string::npos);
+}
+
+void userrec::ClearBuffer()
+{
+       recvq.clear();
+}
+
+std::string userrec::GetBuffer()
+{
+       try
+       {
+               if (!recvq.length())
+                       return "";
+
+               /* Strip any leading \r or \n off the string.
+                * Usually there are only one or two of these,
+                * so its is computationally cheap to do.
+                */
+               std::string::iterator t = recvq.begin();
+               while (t != recvq.end() && (*t == '\r' || *t == '\n'))
+               {
+                       recvq.erase(t);
+                       t = recvq.begin();
+               }
+
+               for (std::string::iterator x = recvq.begin(); x != recvq.end(); x++)
+               {
+                       /* Find the first complete line, return it as the
+                        * result, and leave the recvq as whats left
+                        */
+                       if (*x == '\n')
+                       {
+                               std::string ret = std::string(recvq.begin(), x);
+                               recvq.erase(recvq.begin(), x + 1);
+                               return ret;
+                       }
+               }
+               return "";
+       }
+
+       catch (...)
+       {
+               ServerInstance->Log(DEBUG,"Exception in userrec::GetBuffer()");
+               return "";
+       }
+}
+
+void userrec::AddWriteBuf(const std::string &data)
+{
+       if (*this->GetWriteError())
+               return;
+
+       if (sendq.length() + data.length() > (unsigned)this->sendqmax)
+       {
+               /*
+                * Fix by brain - Set the error text BEFORE calling writeopers, because
+                * if we dont it'll recursively  call here over and over again trying
+                * to repeatedly add the text to the sendq!
+                */
+               this->SetWriteError("SendQ exceeded");
+               ServerInstance->WriteOpers("*** User %s SendQ of %d exceeds connect class maximum of %d",this->nick,sendq.length() + data.length(),this->sendqmax);
+               return;
+       }
+
+       try
+       {
+               if (data.length() > MAXBUF - 2) /* MAXBUF has a value of 514, to account for line terminators */
+                       sendq.append(data.substr(0,MAXBUF - 4)).append("\r\n"); /* MAXBUF-4 = 510 */
+               else
+                       sendq.append(data);
+       }
+       catch (...)
+       {
+               this->SetWriteError("SendQ exceeded");
+               ServerInstance->WriteOpers("*** User %s SendQ got an exception",this->nick);
+       }
+}
+
+// send AS MUCH OF THE USERS SENDQ as we are able to (might not be all of it)
+void userrec::FlushWriteBuf()
+{
+       try
+       {
+               if ((this->fd == FD_MAGIC_NUMBER) || (*this->GetWriteError()))
+               {
+                       sendq.clear();
+               }
+               if ((sendq.length()) && (this->fd != FD_MAGIC_NUMBER))
+               {
+                       int old_sendq_length = sendq.length();
+#ifndef WIN32
+               int n_sent = write(this->fd, this->sendq.data(), this->sendq.length());
+#else
+               int n_sent = send(this->fd, (const char*)this->sendq.data(), this->sendq.length(), 0);
+#endif
+                       if (n_sent == -1)
+                       {
+                               if (errno == EAGAIN)
+                               {
+                                       /* The socket buffer is full. This isnt fatal,
+                                        * try again later.
+                                        */
+                                       this->ServerInstance->SE->WantWrite(this);
+                               }
+                               else
+                               {
+                                       /* Fatal error, set write error and bail
+                                        */
+                                       this->SetWriteError(strerror(errno));
+                                       return;
+                               }
+                       }
+                       else
+                       {
+                               /* advance the queue */
+                               if (n_sent)
+                                       this->sendq = this->sendq.substr(n_sent);
+                               /* update the user's stats counters */
+                               this->bytes_out += n_sent;
+                               this->cmds_out++;
+                               if (n_sent != old_sendq_length)
+                                       this->ServerInstance->SE->WantWrite(this);
+                       }
+               }
+       }
+
+       catch (...)
+       {
+               ServerInstance->Log(DEBUG,"Exception in userrec::FlushWriteBuf()");
+       }
+
+       if (this->sendq.empty())
+       {
+               FOREACH_MOD(I_OnBufferFlushed,OnBufferFlushed(this));
+       }
+}
+
+void userrec::SetWriteError(const std::string &error)
+{
+       try
+       {
+               // don't try to set the error twice, its already set take the first string.
+               if (this->WriteError.empty())
+                       this->WriteError = error;
+       }
+
+       catch (...)
+       {
+               ServerInstance->Log(DEBUG,"Exception in userrec::SetWriteError()");
+       }
+}
+
+const char* userrec::GetWriteError()
+{
+       return this->WriteError.c_str();
+}
+
+void userrec::Oper(const std::string &opertype)
+{
+       try
+       {
+               this->modes[UM_OPERATOR] = 1;
+               this->WriteServ("MODE %s :+o", this->nick);
+               FOREACH_MOD(I_OnOper, OnOper(this, opertype));
+               ServerInstance->Log(DEFAULT,"OPER: %s!%s@%s opered as type: %s", this->nick, this->ident, this->host, opertype.c_str());
+               strlcpy(this->oper, opertype.c_str(), NICKMAX - 1);
+               ServerInstance->all_opers.push_back(this);
+               FOREACH_MOD(I_OnPostOper,OnPostOper(this, opertype));
+       }
+
+       catch (...)
+       {
+               ServerInstance->Log(DEBUG,"Exception in userrec::Oper()");
+       }
+}
+
+void userrec::UnOper()
+{
+       try
+       {
+               if (IS_OPER(this))
+               {
+                       // unset their oper type (what IS_OPER checks), and remove +o
+                       *this->oper = 0;
+                       this->modes[UM_OPERATOR] = 0;
+
+                       // remove them from the opers list.
+                       for (std::vector<userrec*>::iterator a = ServerInstance->all_opers.begin(); a < ServerInstance->all_opers.end(); a++)
+                       {
+                               if (*a == this)
+                               {
+                                       ServerInstance->all_opers.erase(a);
+                                       return;
+                               }
+                       }
+               }
+       }
+
+       catch (...)
+       {
+               ServerInstance->Log(DEBUG,"Exception in userrec::UnOper()");
+       }
+}
+
+void userrec::QuitUser(InspIRCd* Instance, userrec *user, const std::string &quitreason, const char* operreason)
+{
+       user->muted = true;
+       Instance->GlobalCulls.AddItem(user, quitreason.c_str(), operreason);
+}
+
+/* adds or updates an entry in the whowas list */
+void userrec::AddToWhoWas()
+{
+       command_t* whowas_command = ServerInstance->Parser->GetHandler("WHOWAS");
+       if (whowas_command)
+       {
+               std::deque<classbase*> params;
+               params.push_back(this);
+               whowas_command->HandleInternal(WHOWAS_ADD, params);
+       }
+}
+
+/* add a client connection to the sockets list */
+void userrec::AddClient(InspIRCd* Instance, int socket, int port, bool iscached, int socketfamily, sockaddr* ip)
+{
+       std::string tempnick = ConvToStr(socket) + "-unknown";
+       user_hash::iterator iter = Instance->clientlist->find(tempnick);
+       char ipaddr[MAXBUF];
+#ifdef IPV6
+       if (socketfamily == AF_INET6)
+               inet_ntop(AF_INET6, &((const sockaddr_in6*)ip)->sin6_addr, ipaddr, sizeof(ipaddr));
+       else
+#endif
+       inet_ntop(AF_INET, &((const sockaddr_in*)ip)->sin_addr, ipaddr, sizeof(ipaddr));
+       userrec* New;
+       int j = 0;
+
+       Instance->unregistered_count++;
+
+       /*
+        * fix by brain.
+        * as these nicknames are 'RFC impossible', we can be sure nobody is going to be
+        * using one as a registered connection. As they are per fd, we can also safely assume
+        * that we wont have collisions. Therefore, if the nick exists in the list, its only
+        * used by a dead socket, erase the iterator so that the new client may reclaim it.
+        * this was probably the cause of 'server ignores me when i hammer it with reconnects'
+        * issue in earlier alphas/betas
+        */
+       if (iter != Instance->clientlist->end())
+       {
+               userrec* goner = iter->second;
+               DELETE(goner);
+               Instance->clientlist->erase(iter);
+       }
+
+       New = new userrec(Instance);
+       (*(Instance->clientlist))[tempnick] = New;
+       New->fd = socket;
+       strlcpy(New->nick,tempnick.c_str(),NICKMAX-1);
+
+       New->server = Instance->FindServerNamePtr(Instance->Config->ServerName);
+       /* We don't need range checking here, we KNOW 'unknown\0' will fit into the ident field. */
+       strcpy(New->ident, "unknown");
+
+       New->registered = REG_NONE;
+       New->signon = Instance->Time() + Instance->Config->dns_timeout;
+       New->lastping = 1;
+
+       New->SetSockAddr(socketfamily, ipaddr, port);
+
+       /* Smarter than your average bear^H^H^H^Hset of strlcpys. */
+       for (const char* temp = New->GetIPString(); *temp && j < 64; temp++, j++)
+               New->dhost[j] = New->host[j] = *temp;
+       New->dhost[j] = New->host[j] = 0;
+
+       Instance->AddLocalClone(New);
+       Instance->AddGlobalClone(New);
+
+       /*
+        * First class check. We do this again in FullConnect after DNS is done, and NICK/USER is recieved.
+        * See my note down there for why this is required. DO NOT REMOVE. :) -- w00t
+        */
+       ConnectClass* i = New->GetClass();
+
+       if (!i)
+       {
+               userrec::QuitUser(Instance, New, "Access denied by configuration");
+               return;
+       }
+
+       New->CheckClass();
+
+       New->pingmax = i->GetPingTime();
+       New->nping = Instance->Time() + i->GetPingTime() + Instance->Config->dns_timeout;
+       New->timeout = Instance->Time() + i->GetRegTimeout();
+       New->flood = i->GetFlood();
+       New->threshold = i->GetThreshold();
+       New->sendqmax = i->GetSendqMax();
+       New->recvqmax = i->GetRecvqMax();
+
+       Instance->local_users.push_back(New);
+
+       if ((Instance->local_users.size() > Instance->Config->SoftLimit) || (Instance->local_users.size() >= MAXCLIENTS))
+       {
+               Instance->WriteOpers("*** Warning: softlimit value has been reached: %d clients", Instance->Config->SoftLimit);
+               userrec::QuitUser(Instance, New,"No more connections allowed");
+               return;
+       }
+
+       /*
+        * XXX -
+        * this is done as a safety check to keep the file descriptors within range of fd_ref_table.
+        * its a pretty big but for the moment valid assumption:
+        * file descriptors are handed out starting at 0, and are recycled as theyre freed.
+        * therefore if there is ever an fd over 65535, 65536 clients must be connected to the
+        * irc server at once (or the irc server otherwise initiating this many connections, files etc)
+        * which for the time being is a physical impossibility (even the largest networks dont have more
+        * than about 10,000 users on ONE server!)
+        */
+#ifndef WINDOWS
+       if ((unsigned int)socket >= MAX_DESCRIPTORS)
+       {
+               userrec::QuitUser(Instance, New, "Server is full");
+               return;
+       }
+#endif
+
+       New->exempt = (Instance->XLines->matches_exception(New) != NULL);
+       if (!New->exempt)
+       {
+               ZLine* r = Instance->XLines->matches_zline(ipaddr);
+               if (r)
+               {
+                       char reason[MAXBUF];
+                       if (*Instance->Config->MoronBanner)
+                               New->WriteServ("NOTICE %s :*** %s", New->nick, Instance->Config->MoronBanner);
+                       snprintf(reason,MAXBUF,"Z-Lined: %s",r->reason);
+                       userrec::QuitUser(Instance, New, reason);
+                       return;
+               }
+       }
+
+       if (socket > -1)
+       {
+               if (!Instance->SE->AddFd(New))
+               {
+                       userrec::QuitUser(Instance, New, "Internal error handling connection");
+                       return;
+               }
+       }
+
+       /* NOTE: even if dns lookups are *off*, we still need to display this.
+        * BOPM and other stuff requires it.
+        */
+       New->WriteServ("NOTICE Auth :*** Looking up your hostname...");
+}
+
+unsigned long userrec::GlobalCloneCount()
+{
+       clonemap::iterator x = ServerInstance->global_clones.find(this->GetIPString());
+       if (x != ServerInstance->global_clones.end())
+               return x->second;
+       else
+               return 0;
+}
+
+unsigned long userrec::LocalCloneCount()
+{
+       clonemap::iterator x = ServerInstance->local_clones.find(this->GetIPString());
+       if (x != ServerInstance->local_clones.end())
+               return x->second;
+       else
+               return 0;
+}
+
+/*
+ * Check class restrictions
+ */
+void userrec::CheckClass()
+{
+       ConnectClass* a = this->GetClass();
+
+       if ((!a) || (a->GetType() == CC_DENY))
+       {
+               userrec::QuitUser(ServerInstance, this, "Unauthorised connection");
+               return;
+       }
+       else if ((a->GetMaxLocal()) && (this->LocalCloneCount() > a->GetMaxLocal()))
+       {
+               userrec::QuitUser(ServerInstance, this, "No more connections allowed from your host via this connect class (local)");
+               ServerInstance->WriteOpers("*** WARNING: maximum LOCAL connections (%ld) exceeded for IP %s", a->GetMaxLocal(), this->GetIPString());
+               return;
+       }
+       else if ((a->GetMaxGlobal()) && (this->GlobalCloneCount() > a->GetMaxGlobal()))
+       {
+               userrec::QuitUser(ServerInstance, this, "No more connections allowed from your host via this connect class (global)");
+               ServerInstance->WriteOpers("*** WARNING: maximum GLOBAL connections (%ld) exceeded for IP %s", a->GetMaxGlobal(), this->GetIPString());
+               return;
+       }
+}
+
+void userrec::FullConnect()
+{
+       ServerInstance->stats->statsConnects++;
+       this->idle_lastmsg = ServerInstance->Time();
+
+       /*
+        * You may be thinking "wtf, we checked this in userrec::AddClient!" - and yes, we did, BUT.
+        * At the time AddClient is called, we don't have a resolved host, by here we probably do - which
+        * may put the user into a totally seperate class with different restrictions! so we *must* check again.
+        * Don't remove this! -- w00t
+        */
+       this->CheckClass();
+       
+       /* Check the password, if one is required by the user's connect class.
+        * This CANNOT be in CheckClass(), because that is called prior to PASS as well!
+        */
+       if ((!this->GetClass()->GetPass().empty()) && (!this->haspassed))
+       {
+               userrec::QuitUser(ServerInstance, this, "Invalid password");
+               return;
+       }
+       
+       if (!this->exempt)
+       {
+               GLine* r = ServerInstance->XLines->matches_gline(this);
+
+               if (r)
+               {
+                       this->muted = true;
+                       char reason[MAXBUF];
+                       if (*ServerInstance->Config->MoronBanner)
+                               this->WriteServ("NOTICE %s :*** %s", this->nick, ServerInstance->Config->MoronBanner);
+                       snprintf(reason,MAXBUF,"G-Lined: %s",r->reason);
+                       ServerInstance->GlobalCulls.AddItem(this, reason);
+                       return;
+               }
+
+               KLine* n = ServerInstance->XLines->matches_kline(this);
+
+               if (n)
+               {
+                       this->muted = true;
+                       char reason[MAXBUF];
+                       if (*ServerInstance->Config->MoronBanner)
+                               this->WriteServ("NOTICE %s :*** %s", this, ServerInstance->Config->MoronBanner);
+                       snprintf(reason,MAXBUF,"K-Lined: %s",n->reason);
+                       ServerInstance->GlobalCulls.AddItem(this, reason);
+                       return;
+               }
+       }
+
+       this->WriteServ("NOTICE Auth :Welcome to \002%s\002!",ServerInstance->Config->Network);
+       this->WriteServ("001 %s :Welcome to the %s IRC Network %s!%s@%s",this->nick, ServerInstance->Config->Network, this->nick, this->ident, this->host);
+       this->WriteServ("002 %s :Your host is %s, running version %s",this->nick,ServerInstance->Config->ServerName,VERSION);
+       this->WriteServ("003 %s :This server was created %s %s", this->nick, __TIME__, __DATE__);
+       this->WriteServ("004 %s %s %s %s %s %s", this->nick, ServerInstance->Config->ServerName, VERSION, ServerInstance->Modes->UserModeList().c_str(), ServerInstance->Modes->ChannelModeList().c_str(), ServerInstance->Modes->ParaModeList().c_str());
+
+       ServerInstance->Config->Send005(this);
+
+       this->ShowMOTD();
+
+       /* Now registered */
+       if (ServerInstance->unregistered_count)
+               ServerInstance->unregistered_count--;
+
+       /* Trigger LUSERS output, give modules a chance too */
+       int MOD_RESULT = 0;
+       FOREACH_RESULT(I_OnPreCommand, OnPreCommand("LUSERS", NULL, 0, this, true, "LUSERS"));
+       if (!MOD_RESULT)
+               ServerInstance->CallCommandHandler("LUSERS", NULL, 0, this);
+
+       /*
+        * fix 3 by brain, move registered = 7 below these so that spurious modes and host
+        * changes dont go out onto the network and produce 'fake direction'.
+        */
+       FOREACH_MOD(I_OnUserConnect,OnUserConnect(this));
+
+       this->registered = REG_ALL;
+
+       FOREACH_MOD(I_OnPostConnect,OnPostConnect(this));
+
+       ServerInstance->SNO->WriteToSnoMask('c',"Client connecting on port %d: %s!%s@%s [%s] [%s]", this->GetPort(), this->nick, this->ident, this->host, this->GetIPString(), this->fullname);
+}
+
+/** userrec::UpdateNick()
+ * re-allocates a nick in the user_hash after they change nicknames,
+ * returns a pointer to the new user as it may have moved
+ */
+userrec* userrec::UpdateNickHash(const char* New)
+{
+       try
+       {
+               //user_hash::iterator newnick;
+               user_hash::iterator oldnick = ServerInstance->clientlist->find(this->nick);
+
+               if (!strcasecmp(this->nick,New))
+                       return oldnick->second;
+
+               if (oldnick == ServerInstance->clientlist->end())
+                       return NULL; /* doesnt exist */
+
+               userrec* olduser = oldnick->second;
+               (*(ServerInstance->clientlist))[New] = olduser;
+               ServerInstance->clientlist->erase(oldnick);
+               return olduser;
+       }
+
+       catch (...)
+       {
+               ServerInstance->Log(DEBUG,"Exception in userrec::UpdateNickHash()");
+               return NULL;
+       }
+}
+
+void userrec::InvalidateCache()
+{
+       /* Invalidate cache */
+       if (cached_fullhost)
+               free(cached_fullhost);
+       if (cached_hostip)
+               free(cached_hostip);
+       if (cached_makehost)
+               free(cached_makehost);
+       if (cached_fullrealhost)
+               free(cached_fullrealhost);
+       cached_fullhost = cached_hostip = cached_makehost = cached_fullrealhost = NULL;
+}
+
+bool userrec::ForceNickChange(const char* newnick)
+{
+       try
+       {
+               int MOD_RESULT = 0;
+
+               this->InvalidateCache();
+
+               FOREACH_RESULT(I_OnUserPreNick,OnUserPreNick(this, newnick));
+
+               if (MOD_RESULT)
+               {
+                       ServerInstance->stats->statsCollisions++;
+                       return false;
+               }
+
+               if (ServerInstance->XLines->matches_qline(newnick))
+               {
+                       ServerInstance->stats->statsCollisions++;
+                       return false;
+               }
+
+               if (this->registered == REG_ALL)
+               {
+                       return (ServerInstance->Parser->CallHandler("NICK", &newnick, 1, this) == CMD_SUCCESS);
+               }
+               return false;
+       }
+
+       catch (...)
+       {
+               ServerInstance->Log(DEBUG,"Exception in userrec::ForceNickChange()");
+               return false;
+       }
+}
+
+void userrec::SetSockAddr(int protocol_family, const char* ip, int port)
+{
+       switch (protocol_family)
+       {
+#ifdef SUPPORT_IP6LINKS
+               case AF_INET6:
+               {
+                       sockaddr_in6* sin = new sockaddr_in6;
+                       sin->sin6_family = AF_INET6;
+                       sin->sin6_port = port;
+                       inet_pton(AF_INET6, ip, &sin->sin6_addr);
+                       this->ip = (sockaddr*)sin;
+               }
+               break;
+#endif
+               case AF_INET:
+               {
+                       sockaddr_in* sin = new sockaddr_in;
+                       sin->sin_family = AF_INET;
+                       sin->sin_port = port;
+                       inet_pton(AF_INET, ip, &sin->sin_addr);
+                       this->ip = (sockaddr*)sin;
+               }
+               break;
+               default:
+                       ServerInstance->Log(DEBUG,"Ut oh, I dont know protocol %d to be set on '%s'!", protocol_family, this->nick);
+               break;
+       }
+}
+
+int userrec::GetPort()
+{
+       if (this->ip == NULL)
+               return 0;
+
+       switch (this->GetProtocolFamily())
+       {
+#ifdef SUPPORT_IP6LINKS
+               case AF_INET6:
+               {
+                       sockaddr_in6* sin = (sockaddr_in6*)this->ip;
+                       return sin->sin6_port;
+               }
+               break;
+#endif
+               case AF_INET:
+               {
+                       sockaddr_in* sin = (sockaddr_in*)this->ip;
+                       return sin->sin_port;
+               }
+               break;
+               default:
+               break;
+       }
+       return 0;
+}
+
+int userrec::GetProtocolFamily()
+{
+       if (this->ip == NULL)
+               return 0;
+
+       sockaddr_in* sin = (sockaddr_in*)this->ip;
+       return sin->sin_family;
+}
+
+const char* userrec::GetIPString()
+{
+       static char buf[1024];
+
+       if (this->ip == NULL)
+               return "";
+
+       switch (this->GetProtocolFamily())
+       {
+#ifdef SUPPORT_IP6LINKS
+               case AF_INET6:
+               {
+                       static char temp[1024];
+
+                       sockaddr_in6* sin = (sockaddr_in6*)this->ip;
+                       inet_ntop(sin->sin6_family, &sin->sin6_addr, buf, sizeof(buf));
+                       /* IP addresses starting with a : on irc are a Bad Thing (tm) */
+                       if (*buf == ':')
+                       {
+                               strlcpy(&temp[1], buf, sizeof(temp) - 1);
+                               *temp = '0';
+                               return temp;
+                       }
+                       return buf;
+               }
+               break;
+#endif
+               case AF_INET:
+               {
+                       sockaddr_in* sin = (sockaddr_in*)this->ip;
+                       inet_ntop(sin->sin_family, &sin->sin_addr, buf, sizeof(buf));
+                       return buf;
+               }
+               break;
+               default:
+               break;
+       }
+       return "";
+}
+
+const char* userrec::GetIPString(char* buf)
+{
+       if (this->ip == NULL)
+       {
+               *buf = 0;
+               return buf;
+       }
+
+       switch (this->GetProtocolFamily())
+       {
+#ifdef SUPPORT_IP6LINKS
+               case AF_INET6:
+               {
+                       static char temp[1024];
+
+                       sockaddr_in6* sin = (sockaddr_in6*)this->ip;
+                       inet_ntop(sin->sin6_family, &sin->sin6_addr, buf, sizeof(buf));
+                       /* IP addresses starting with a : on irc are a Bad Thing (tm) */
+                       if (*buf == ':')
+                       {
+                               strlcpy(&temp[1], buf, sizeof(temp) - 1);
+                               *temp = '0';
+                               strlcpy(buf, temp, sizeof(temp));
+                       }
+                       return buf;
+               }
+               break;
+#endif
+               case AF_INET:
+               {
+                       sockaddr_in* sin = (sockaddr_in*)this->ip;
+                       inet_ntop(sin->sin_family, &sin->sin_addr, buf, sizeof(buf));
+                       return buf;
+               }
+               break;
+
+               default:
+               break;
+       }
+       return "";
+}
+
+/** NOTE: We cannot pass a const reference to this method.
+ * The string is changed by the workings of the method,
+ * so that if we pass const ref, we end up copying it to
+ * something we can change anyway. Makes sense to just let
+ * the compiler do that copy for us.
+ */
+void userrec::Write(std::string text)
+{
+#ifdef WINDOWS
+       if ((this->fd < 0) || (this->m_internalFd > MAX_DESCRIPTORS))
+#else
+       if ((this->fd < 0) || (this->fd > MAX_DESCRIPTORS))
+#endif
+               return;
+
+       try
+       {
+               /* ServerInstance->Log(DEBUG,"C[%d] <- %s", this->GetFd(), text.c_str());
+                * WARNING: The above debug line is VERY loud, do NOT
+                * enable it till we have a good way of filtering it
+                * out of the logs (e.g. 1.2 would be good).
+                */
+               text.append("\r\n");
+       }
+       catch (...)
+       {
+               ServerInstance->Log(DEBUG,"Exception in userrec::Write() std::string::append");
+               return;
+       }
+
+       if (ServerInstance->Config->GetIOHook(this->GetPort()))
+       {
+               try
+               {
+                       /* XXX: The lack of buffering here is NOT a bug, modules implementing this interface have to
+                        * implement their own buffering mechanisms
+                        */
+                       ServerInstance->Config->GetIOHook(this->GetPort())->OnRawSocketWrite(this->fd, text.data(), text.length());
+               }
+               catch (CoreException& modexcept)
+               {
+                       ServerInstance->Log(DEBUG, "%s threw an exception: %s", modexcept.GetSource(), modexcept.GetReason());
+               }
+       }
+       else
+       {
+               this->AddWriteBuf(text);
+       }
+       ServerInstance->stats->statsSent += text.length();
+       this->ServerInstance->SE->WantWrite(this);
+}
+
+/** Write()
+ */
+void userrec::Write(const char *text, ...)
+{
+       va_list argsPtr;
+       char textbuffer[MAXBUF];
+
+       va_start(argsPtr, text);
+       vsnprintf(textbuffer, MAXBUF, text, argsPtr);
+       va_end(argsPtr);
+
+       this->Write(std::string(textbuffer));
+}
+
+void userrec::WriteServ(const std::string& text)
+{
+       char textbuffer[MAXBUF];
+
+       snprintf(textbuffer,MAXBUF,":%s %s",ServerInstance->Config->ServerName,text.c_str());
+       this->Write(std::string(textbuffer));
+}
+
+/** WriteServ()
+ *  Same as Write(), except `text' is prefixed with `:server.name '.
+ */
+void userrec::WriteServ(const char* text, ...)
+{
+       va_list argsPtr;
+       char textbuffer[MAXBUF];
+
+       va_start(argsPtr, text);
+       vsnprintf(textbuffer, MAXBUF, text, argsPtr);
+       va_end(argsPtr);
+
+       this->WriteServ(std::string(textbuffer));
+}
+
+
+void userrec::WriteFrom(userrec *user, const std::string &text)
+{
+       char tb[MAXBUF];
+
+       snprintf(tb,MAXBUF,":%s %s",user->GetFullHost(),text.c_str());
+
+       this->Write(std::string(tb));
+}
+
+
+/* write text from an originating user to originating user */
+
+void userrec::WriteFrom(userrec *user, const char* text, ...)
+{
+       va_list argsPtr;
+       char textbuffer[MAXBUF];
+
+       va_start(argsPtr, text);
+       vsnprintf(textbuffer, MAXBUF, text, argsPtr);
+       va_end(argsPtr);
+
+       this->WriteFrom(user, std::string(textbuffer));
+}
+
+
+/* write text to an destination user from a source user (e.g. user privmsg) */
+
+void userrec::WriteTo(userrec *dest, const char *data, ...)
+{
+       char textbuffer[MAXBUF];
+       va_list argsPtr;
+
+       va_start(argsPtr, data);
+       vsnprintf(textbuffer, MAXBUF, data, argsPtr);
+       va_end(argsPtr);
+
+       this->WriteTo(dest, std::string(textbuffer));
+}
+
+void userrec::WriteTo(userrec *dest, const std::string &data)
+{
+       dest->WriteFrom(this, data);
+}
+
+
+void userrec::WriteCommon(const char* text, ...)
+{
+       char textbuffer[MAXBUF];
+       va_list argsPtr;
+
+       if (this->registered != REG_ALL)
+               return;
+
+       va_start(argsPtr, text);
+       vsnprintf(textbuffer, MAXBUF, text, argsPtr);
+       va_end(argsPtr);
+
+       this->WriteCommon(std::string(textbuffer));
+}
+
+void userrec::WriteCommon(const std::string &text)
+{
+       try
+       {
+               bool sent_to_at_least_one = false;
+               char tb[MAXBUF];
+
+               if (this->registered != REG_ALL)
+                       return;
+
+               uniq_id++;
+
+               /* We dont want to be doing this n times, just once */
+               snprintf(tb,MAXBUF,":%s %s",this->GetFullHost(),text.c_str());
+               std::string out = tb;
+
+               for (UCListIter v = this->chans.begin(); v != this->chans.end(); v++)
+               {
+                       CUList* ulist = v->first->GetUsers();
+                       for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
+                       {
+                               if ((IS_LOCAL(i->first)) && (already_sent[i->first->fd] != uniq_id))
+                               {
+                                       already_sent[i->first->fd] = uniq_id;
+                                       i->first->Write(out);
+                                       sent_to_at_least_one = true;
+                               }
+                       }
+               }
+
+               /*
+                * if the user was not in any channels, no users will receive the text. Make sure the user
+                * receives their OWN message for WriteCommon
+                */
+               if (!sent_to_at_least_one)
+               {
+                       this->Write(std::string(tb));
+               }
+       }
+
+       catch (...)
+       {
+               ServerInstance->Log(DEBUG,"Exception in userrec::WriteCommon()");
+       }
+}
+
+
+/* write a formatted string to all users who share at least one common
+ * channel, NOT including the source user e.g. for use in QUIT
+ */
+
+void userrec::WriteCommonExcept(const char* text, ...)
+{
+       char textbuffer[MAXBUF];
+       va_list argsPtr;
+
+       va_start(argsPtr, text);
+       vsnprintf(textbuffer, MAXBUF, text, argsPtr);
+       va_end(argsPtr);
+
+       this->WriteCommonExcept(std::string(textbuffer));
+}
+
+void userrec::WriteCommonQuit(const std::string &normal_text, const std::string &oper_text)
+{
+       char tb1[MAXBUF];
+       char tb2[MAXBUF];
+
+       if (this->registered != REG_ALL)
+               return;
+
+       uniq_id++;
+       snprintf(tb1,MAXBUF,":%s QUIT :%s",this->GetFullHost(),normal_text.c_str());
+       snprintf(tb2,MAXBUF,":%s QUIT :%s",this->GetFullHost(),oper_text.c_str());
+       std::string out1 = tb1;
+       std::string out2 = tb2;
+
+       for (UCListIter v = this->chans.begin(); v != this->chans.end(); v++)
+       {
+               CUList *ulist = v->first->GetUsers();
+               for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
+               {
+                       if (this != i->first)
+                       {
+                               if ((IS_LOCAL(i->first)) && (already_sent[i->first->fd] != uniq_id))
+                               {
+                                       already_sent[i->first->fd] = uniq_id;
+                                       i->first->Write(IS_OPER(i->first) ? out2 : out1);
+                               }
+                       }
+               }
+       }
+}
+
+void userrec::WriteCommonExcept(const std::string &text)
+{
+       char tb1[MAXBUF];
+       std::string out1;
+
+       if (this->registered != REG_ALL)
+               return;
+
+       uniq_id++;
+       snprintf(tb1,MAXBUF,":%s %s",this->GetFullHost(),text.c_str());
+       out1 = tb1;
+
+       for (UCListIter v = this->chans.begin(); v != this->chans.end(); v++)
+       {
+               CUList *ulist = v->first->GetUsers();
+               for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
+               {
+                       if (this != i->first)
+                       {
+                               if ((IS_LOCAL(i->first)) && (already_sent[i->first->fd] != uniq_id))
+                               {
+                                       already_sent[i->first->fd] = uniq_id;
+                                       i->first->Write(out1);
+                               }
+                       }
+               }
+       }
+
+}
+
+void userrec::WriteWallOps(const std::string &text)
+{
+       if (!IS_OPER(this) && IS_LOCAL(this))
+               return;
+
+       std::string wallop("WALLOPS :");
+       wallop.append(text);
+
+       for (std::vector<userrec*>::const_iterator i = ServerInstance->local_users.begin(); i != ServerInstance->local_users.end(); i++)
+       {
+               userrec* t = *i;
+               if (t->modes[UM_WALLOPS])
+                       this->WriteTo(t,wallop);
+       }
+}
+
+void userrec::WriteWallOps(const char* text, ...)
+{
+       char textbuffer[MAXBUF];
+       va_list argsPtr;
+
+       va_start(argsPtr, text);
+       vsnprintf(textbuffer, MAXBUF, text, argsPtr);
+       va_end(argsPtr);
+
+       this->WriteWallOps(std::string(textbuffer));
+}
+
+/* return 0 or 1 depending if users u and u2 share one or more common channels
+ * (used by QUIT, NICK etc which arent channel specific notices)
+ *
+ * The old algorithm in 1.0 for this was relatively inefficient, iterating over
+ * the first users channels then the second users channels within the outer loop,
+ * therefore it was a maximum of x*y iterations (upon returning 0 and checking
+ * all possible iterations). However this new function instead checks against the
+ * channel's userlist in the inner loop which is a std::map<userrec*,userrec*>
+ * and saves us time as we already know what pointer value we are after.
+ * Don't quote me on the maths as i am not a mathematician or computer scientist,
+ * but i believe this algorithm is now x+(log y) maximum iterations instead.
+ */
+bool userrec::SharesChannelWith(userrec *other)
+{
+       if ((!other) || (this->registered != REG_ALL) || (other->registered != REG_ALL))
+               return false;
+
+       /* Outer loop */
+       for (UCListIter i = this->chans.begin(); i != this->chans.end(); i++)
+       {
+               /* Eliminate the inner loop (which used to be ~equal in size to the outer loop)
+                * by replacing it with a map::find which *should* be more efficient
+                */
+               if (i->first->HasUser(other))
+                       return true;
+       }
+       return false;
+}
+
+bool userrec::ChangeName(const char* gecos)
+{
+       if (!strcmp(gecos, this->fullname))
+               return true;
+
+       if (IS_LOCAL(this))
+       {
+               int MOD_RESULT = 0;
+               FOREACH_RESULT(I_OnChangeLocalUserGECOS,OnChangeLocalUserGECOS(this,gecos));
+               if (MOD_RESULT)
+                       return false;
+               FOREACH_MOD(I_OnChangeName,OnChangeName(this,gecos));
+       }
+       strlcpy(this->fullname,gecos,MAXGECOS+1);
+
+       return true;
+}
+
+bool userrec::ChangeDisplayedHost(const char* host)
+{
+       if (!strcmp(host, this->dhost))
+               return true;
+
+       if (IS_LOCAL(this))
+       {
+               int MOD_RESULT = 0;
+               FOREACH_RESULT(I_OnChangeLocalUserHost,OnChangeLocalUserHost(this,host));
+               if (MOD_RESULT)
+                       return false;
+               FOREACH_MOD(I_OnChangeHost,OnChangeHost(this,host));
+       }
+       if (this->ServerInstance->Config->CycleHosts)
+               this->WriteCommonExcept("QUIT :Changing hosts");
+
+       /* Fix by Om: userrec::dhost is 65 long, this was truncating some long hosts */
+       strlcpy(this->dhost,host,64);
+
+       this->InvalidateCache();
+
+       if (this->ServerInstance->Config->CycleHosts)
+       {
+               for (UCListIter i = this->chans.begin(); i != this->chans.end(); i++)
+               {
+                       i->first->WriteAllExceptSender(this, false, 0, "JOIN %s", i->first->name);
+                       std::string n = this->ServerInstance->Modes->ModeString(this, i->first);
+                       if (n.length() > 0)
+                               i->first->WriteAllExceptSender(this, true, 0, "MODE %s +%s", i->first->name, n.c_str());
+               }
+       }
+
+       if (IS_LOCAL(this))
+               this->WriteServ("396 %s %s :is now your displayed host",this->nick,this->dhost);
+
+       return true;
+}
+
+bool userrec::ChangeIdent(const char* newident)
+{
+       if (!strcmp(newident, this->ident))
+               return true;
+
+       if (this->ServerInstance->Config->CycleHosts)
+               this->WriteCommonExcept("%s","QUIT :Changing ident");
+
+       strlcpy(this->ident, newident, IDENTMAX+2);
+
+       this->InvalidateCache();
+
+       if (this->ServerInstance->Config->CycleHosts)
+       {
+               for (UCListIter i = this->chans.begin(); i != this->chans.end(); i++)
+               {
+                       i->first->WriteAllExceptSender(this, false, 0, "JOIN %s", i->first->name);
+                       std::string n = this->ServerInstance->Modes->ModeString(this, i->first);
+                       if (n.length() > 0)
+                               i->first->WriteAllExceptSender(this, true, 0, "MODE %s +%s", i->first->name, n.c_str());
+               }
+       }
+
+       return true;
+}
+
+void userrec::SendAll(const char* command, char* text, ...)
+{
+       char textbuffer[MAXBUF];
+       char formatbuffer[MAXBUF];
+       va_list argsPtr;
+
+       va_start(argsPtr, text);
+       vsnprintf(textbuffer, MAXBUF, text, argsPtr);
+       va_end(argsPtr);
+
+       snprintf(formatbuffer,MAXBUF,":%s %s $* :%s", this->GetFullHost(), command, textbuffer);
+       std::string fmt = formatbuffer;
+
+       for (std::vector<userrec*>::const_iterator i = ServerInstance->local_users.begin(); i != ServerInstance->local_users.end(); i++)
+       {
+               (*i)->Write(fmt);
+       }
+}
+
+
+std::string userrec::ChannelList(userrec* source)
+{
+       try
+       {
+               std::string list;
+               for (UCListIter i = this->chans.begin(); i != this->chans.end(); i++)
+               {
+                       /* If the target is the same as the sender, let them see all their channels.
+                        * If the channel is NOT private/secret OR the user shares a common channel
+                        * If the user is an oper, and the <options:operspywhois> option is set.
+                        */
+                       if ((source == this) || (IS_OPER(source) && ServerInstance->Config->OperSpyWhois) || (((!i->first->modes[CM_PRIVATE]) && (!i->first->modes[CM_SECRET])) || (i->first->HasUser(source))))
+                       {
+                               list.append(i->first->GetPrefixChar(this)).append(i->first->name).append(" ");
+                       }
+               }
+               return list;
+       }
+       catch (...)
+       {
+               ServerInstance->Log(DEBUG,"Exception in userrec::ChannelList()");
+               return "";
+       }
+}
+
+void userrec::SplitChanList(userrec* dest, const std::string &cl)
+{
+       std::string line;
+       std::ostringstream prefix;
+       std::string::size_type start, pos, length;
+
+       try
+       {
+               prefix << this->nick << " " << dest->nick << " :";
+               line = prefix.str();
+               int namelen = strlen(ServerInstance->Config->ServerName) + 6;
+
+               for (start = 0; (pos = cl.find(' ', start)) != std::string::npos; start = pos+1)
+               {
+                       length = (pos == std::string::npos) ? cl.length() : pos;
+
+                       if (line.length() + namelen + length - start > 510)
+                       {
+                               ServerInstance->SendWhoisLine(this, dest, 319, "%s", line.c_str());
+                               line = prefix.str();
+                       }
+
+                       if(pos == std::string::npos)
+                       {
+                               line.append(cl.substr(start, length - start));
+                               break;
+                       }
+                       else
+                       {
+                               line.append(cl.substr(start, length - start + 1));
+                       }
+               }
+
+               if (line.length())
+               {
+                       ServerInstance->SendWhoisLine(this, dest, 319, "%s", line.c_str());
+               }
+       }
+
+       catch (...)
+       {
+               ServerInstance->Log(DEBUG,"Exception in userrec::SplitChanList()");
+       }
+}
+
+
+/* looks up a users password for their connection class (<ALLOW>/<DENY> tags)
+ * NOTE: If the <ALLOW> or <DENY> tag specifies an ip, and this user resolves,
+ * then their ip will be taken as 'priority' anyway, so for example,
+ * <connect allow="127.0.0.1"> will match joe!bloggs@localhost
+ */
+ConnectClass* userrec::GetClass()
+{
+       for (ClassVector::iterator i = ServerInstance->Config->Classes.begin(); i != ServerInstance->Config->Classes.end(); i++)
+       {
+               if (((match(this->GetIPString(),i->GetHost().c_str(),true)) || (match(this->host,i->GetHost().c_str()))))
+               {
+                       if (i->GetPort())
+                       {
+                               if (this->GetPort() == i->GetPort())
+                                       return &(*i);
+                               else
+                                       continue;
+                       }
+                       else
+                               return &(*i);
+               }
+       }
+       return NULL;
+}
+
+void userrec::PurgeEmptyChannels()
+{
+       std::vector<chanrec*> to_delete;
+
+       // firstly decrement the count on each channel
+       for (UCListIter f = this->chans.begin(); f != this->chans.end(); f++)
+       {
+               f->first->RemoveAllPrefixes(this);
+               if (f->first->DelUser(this) == 0)
+               {
+                       /* No users left in here, mark it for deletion */
+                       try
+                       {
+                               to_delete.push_back(f->first);
+                       }
+                       catch (...)
+                       {
+                               ServerInstance->Log(DEBUG,"Exception in userrec::PurgeEmptyChannels to_delete.push_back()");
+                       }
+               }
+       }
+
+       for (std::vector<chanrec*>::iterator n = to_delete.begin(); n != to_delete.end(); n++)
+       {
+               chanrec* thischan = *n;
+               chan_hash::iterator i2 = ServerInstance->chanlist->find(thischan->name);
+               if (i2 != ServerInstance->chanlist->end())
+               {
+                       FOREACH_MOD(I_OnChannelDelete,OnChannelDelete(i2->second));
+                       DELETE(i2->second);
+                       ServerInstance->chanlist->erase(i2);
+                       this->chans.erase(*n);
+               }
+       }
+
+       this->UnOper();
+}
+
+void userrec::ShowMOTD()
+{
+       if (!ServerInstance->Config->MOTD.size())
+       {
+               this->WriteServ("422 %s :Message of the day file is missing.",this->nick);
+               return;
+       }
+       this->WriteServ("375 %s :%s message of the day", this->nick, ServerInstance->Config->ServerName);
+
+       for (file_cache::iterator i = ServerInstance->Config->MOTD.begin(); i != ServerInstance->Config->MOTD.end(); i++)
+               this->WriteServ("372 %s :- %s",this->nick,i->c_str());
+
+       this->WriteServ("376 %s :End of message of the day.", this->nick);
+}
+
+void userrec::ShowRULES()
+{
+       if (!ServerInstance->Config->RULES.size())
+       {
+               this->WriteServ("NOTICE %s :Rules file is missing.",this->nick);
+               return;
+       }
+       this->WriteServ("NOTICE %s :%s rules",this->nick,ServerInstance->Config->ServerName);
+
+       for (file_cache::iterator i = ServerInstance->Config->RULES.begin(); i != ServerInstance->Config->RULES.end(); i++)
+               this->WriteServ("NOTICE %s :%s",this->nick,i->c_str());
+
+       this->WriteServ("NOTICE %s :End of %s rules.",this->nick,ServerInstance->Config->ServerName);
+}
+
+void userrec::HandleEvent(EventType et, int errornum)
+{
+       /* WARNING: May delete this user! */
+       int thisfd = this->GetFd();
+
+       try
+       {
+               switch (et)
+               {
+                       case EVENT_READ:
+                               ServerInstance->ProcessUser(this);
+                       break;
+                       case EVENT_WRITE:
+                               this->FlushWriteBuf();
+                       break;
+                       case EVENT_ERROR:
+                               /** This should be safe, but dont DARE do anything after it -- Brain */
+                               this->SetWriteError(errornum ? strerror(errornum) : "EOF from client");
+                       break;
+               }
+       }
+       catch (...)
+       {
+               ServerInstance->Log(DEBUG,"Exception in userrec::HandleEvent intercepted");
+       }
+
+       /* If the user has raised an error whilst being processed, quit them now we're safe to */
+       if ((ServerInstance->SE->GetRef(thisfd) == this))
+       {
+               if (!WriteError.empty())
+               {
+                       userrec::QuitUser(ServerInstance, this, GetWriteError());
+               }
+       }
+}
+
+void userrec::SetOperQuit(const std::string &oquit)
+{
+       if (operquit)
+               return;
+
+       operquit = strdup(oquit.c_str());
+}
+
+const char* userrec::GetOperQuit()
+{
+       return operquit ? operquit : "";
+}
+
+VisData::VisData()
+{
+}
+
+VisData::~VisData()
+{
+}
+
+bool VisData::VisibleTo(userrec* user)
+{
+       return true;
+}
+
index bb0c9124dd9426b29baee9402cec67c08eb0fd1c..e9733c2a4b21afa5a6b0932ccd00caa17820651a 100755 (executable)
@@ -1 +1,2 @@
-#!sh\recho "InspIRCd-1.1.9+IsleOfMull"\r
\ No newline at end of file
+#!sh
+echo "InspIRCd-1.1.9+IsleOfMull"
index eeb6190f2b7bf90dfffd70b15479a14e04276d28..8587f17144ddeb0f12a999be1eb7fcf47ad00f54 100644 (file)
@@ -1 +1,148 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include <string>\r#include "hashcomp.h"\r#include "inspstring.h"\r\rusing irc::sockets::MatchCIDR;\r\r// Wed 27 Apr 2005 - Brain\r// I've taken our our old wildcard routine -\r// although comprehensive, it was topheavy and very\r// slow, and ate masses of cpu when doing lots of\r// comparisons. This is the 'de-facto' routine used\r// by many, nobody really knows who wrote it first\r// or what license its under, i've seen examples of it\r// (unattributed to any author) all over the 'net.\r// For now, we'll just consider this public domain.\r\rCoreExport bool csmatch(const char *str, const char *mask)\r{\r   unsigned char *cp = NULL, *mp = NULL;\r  unsigned char* string = (unsigned char*)str;\r   unsigned char* wild = (unsigned char*)mask;\r\r   while ((*string) && (*wild != '*'))\r    {\r              if ((*wild != *string) && (*wild != '?'))\r              {\r                      return 0;\r              }\r              wild++;\r                string++;\r      }\r\r     while (*string)\r        {\r              if (*wild == '*')\r              {\r                      if (!*++wild)\r                  {\r                              return 1;\r                      }\r                      mp = wild;\r                     cp = string+1;\r         }\r              else\r           if ((*wild == *string) || (*wild == '?'))\r              {\r                      wild++;\r                        string++;\r              }\r              else\r           {\r                      wild = mp;\r                     string = cp++;\r         }\r\r     }\r\r     while (*wild == '*')\r   {\r              wild++;\r        }\r\r     return !*wild;\r}\r\rCoreExport bool match(const char *str, const char *mask)\r{\r   unsigned char *cp = NULL, *mp = NULL;\r  unsigned char* string = (unsigned char*)str;\r   unsigned char* wild = (unsigned char*)mask;\r\r   while ((*string) && (*wild != '*'))\r    {\r              if ((lowermap[*wild] != lowermap[*string]) && (*wild != '?'))\r          {\r                      return 0;\r              }\r              wild++;\r                string++;\r      }\r\r     while (*string)\r        {\r              if (*wild == '*')\r              {\r                      if (!*++wild)\r                  {\r                              return 1;\r                      }\r                      mp = wild;\r                     cp = string+1;\r         }\r              else\r           if ((lowermap[*wild] == lowermap[*string]) || (*wild == '?'))\r          {\r                      wild++;\r                        string++;\r              }\r              else\r           {\r                      wild = mp;\r                     string = cp++;\r         }\r\r     }\r\r     while (*wild == '*')\r   {\r              wild++;\r        }\r\r     return !*wild;\r}\r\r/* Overloaded function that has the option of using cidr */\rCoreExport bool match(const char *str, const char *mask, bool use_cidr_match)\r{\r  if (use_cidr_match && MatchCIDR(str, mask, true))\r              return true;\r   return match(str, mask);\r}\r\rCoreExport bool match(bool case_sensitive, const char *str, const char *mask, bool use_cidr_match)\r{\r       if (use_cidr_match && MatchCIDR(str, mask, true))\r              return true;\r   return csmatch(str, mask);\r}\r\rCoreExport bool match(bool case_sensitive, const char *str, const char *mask)\r{\r  return case_sensitive ? csmatch(str, mask) : match(str, mask);\r}\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include <string>
+#include "hashcomp.h"
+#include "inspstring.h"
+
+using irc::sockets::MatchCIDR;
+
+// Wed 27 Apr 2005 - Brain
+// I've taken our our old wildcard routine -
+// although comprehensive, it was topheavy and very
+// slow, and ate masses of cpu when doing lots of
+// comparisons. This is the 'de-facto' routine used
+// by many, nobody really knows who wrote it first
+// or what license its under, i've seen examples of it
+// (unattributed to any author) all over the 'net.
+// For now, we'll just consider this public domain.
+
+CoreExport bool csmatch(const char *str, const char *mask)
+{
+       unsigned char *cp = NULL, *mp = NULL;
+       unsigned char* string = (unsigned char*)str;
+       unsigned char* wild = (unsigned char*)mask;
+
+       while ((*string) && (*wild != '*'))
+       {
+               if ((*wild != *string) && (*wild != '?'))
+               {
+                       return 0;
+               }
+               wild++;
+               string++;
+       }
+
+       while (*string)
+       {
+               if (*wild == '*')
+               {
+                       if (!*++wild)
+                       {
+                               return 1;
+                       }
+                       mp = wild;
+                       cp = string+1;
+               }
+               else
+               if ((*wild == *string) || (*wild == '?'))
+               {
+                       wild++;
+                       string++;
+               }
+               else
+               {
+                       wild = mp;
+                       string = cp++;
+               }
+
+       }
+
+       while (*wild == '*')
+       {
+               wild++;
+       }
+
+       return !*wild;
+}
+
+CoreExport bool match(const char *str, const char *mask)
+{
+       unsigned char *cp = NULL, *mp = NULL;
+       unsigned char* string = (unsigned char*)str;
+       unsigned char* wild = (unsigned char*)mask;
+
+       while ((*string) && (*wild != '*'))
+       {
+               if ((lowermap[*wild] != lowermap[*string]) && (*wild != '?'))
+               {
+                       return 0;
+               }
+               wild++;
+               string++;
+       }
+
+       while (*string)
+       {
+               if (*wild == '*')
+               {
+                       if (!*++wild)
+                       {
+                               return 1;
+                       }
+                       mp = wild;
+                       cp = string+1;
+               }
+               else
+               if ((lowermap[*wild] == lowermap[*string]) || (*wild == '?'))
+               {
+                       wild++;
+                       string++;
+               }
+               else
+               {
+                       wild = mp;
+                       string = cp++;
+               }
+
+       }
+
+       while (*wild == '*')
+       {
+               wild++;
+       }
+
+       return !*wild;
+}
+
+/* Overloaded function that has the option of using cidr */
+CoreExport bool match(const char *str, const char *mask, bool use_cidr_match)
+{
+       if (use_cidr_match && MatchCIDR(str, mask, true))
+               return true;
+       return match(str, mask);
+}
+
+CoreExport bool match(bool case_sensitive, const char *str, const char *mask, bool use_cidr_match)
+{
+       if (use_cidr_match && MatchCIDR(str, mask, true))
+               return true;
+       return csmatch(str, mask);
+}
+
+CoreExport bool match(bool case_sensitive, const char *str, const char *mask)
+{
+       return case_sensitive ? csmatch(str, mask) : match(str, mask);
+}
+
index 87b1d3e5ea0107fb5e90e658d17825e2f5da3eac..def9db42b92a9693c20796a9e0eee661d2d9aefa 100644 (file)
@@ -1 +1,897 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd.h"\r#include "users.h"\r#include "modules.h"\r#include "wildcard.h"\r#include "xline.h"\r\r/* Version two, now with optimized expiry!\r *\r * Because the old way was horrendously slow, the new way of expiring xlines is very\r * very efficient. I have improved the efficiency of the algorithm in two ways:\r *\r * (1) There are now two lists of items for each linetype. One list holds temporary\r *     items, and the other list holds permanent items (ones which will expire).\r *     Items which are on the permanent list are NEVER checked at all by the\r *     expire_lines() function.\r * (2) The temporary xline lists are always kept in strict numerical order, keyed by\r *     current time + duration. This means that the line which is due to expire the\r *     soonest is always pointed at by vector::begin(), so a simple while loop can\r *     very efficiently, very quickly and above all SAFELY pick off the first few\r *     items in the vector which need zapping.\r *\r *     -- Brain\r */\r\rbool InitXLine(ServerConfig* conf, const char* tag)\r{\r        return true;\r}\r\rbool DoneZLine(ServerConfig* conf, const char* tag)\r{\r  conf->GetInstance()->XLines->apply_lines(APPLY_ZLINES|APPLY_PERM_ONLY);\r        return true;\r}\r\rbool DoneQLine(ServerConfig* conf, const char* tag)\r{\r  conf->GetInstance()->XLines->apply_lines(APPLY_QLINES|APPLY_PERM_ONLY);\r        return true;\r}\r\rbool DoneKLine(ServerConfig* conf, const char* tag)\r{\r  conf->GetInstance()->XLines->apply_lines(APPLY_KLINES|APPLY_PERM_ONLY);\r        return true;\r}\r\rbool DoneELine(ServerConfig* conf, const char* tag)\r{\r  /* Yes, this is supposed to do nothing, we dont 'apply' these */\r       return true;\r}\r\rbool DoZLine(ServerConfig* conf, const char* tag, char** entries, ValueList &values, int* types)\r{\r     const char* reason = values[0].GetString();\r    const char* ipmask = values[1].GetString();\r\r   conf->GetInstance()->XLines->add_zline(0,"<Config>",reason,ipmask);\r    return true;\r}\r\rbool DoQLine(ServerConfig* conf, const char* tag, char** entries, ValueList &values, int* types)\r{\r     const char* reason = values[0].GetString();\r    const char* nick = values[1].GetString();\r\r     conf->GetInstance()->XLines->add_qline(0,"<Config>",reason,nick);\r      return true;\r}\r\rbool DoKLine(ServerConfig* conf, const char* tag, char** entries, ValueList &values, int* types)\r{\r     const char* reason = values[0].GetString();\r    const char* host = values[1].GetString();\r\r     conf->GetInstance()->XLines->add_kline(0,"<Config>",reason,host);\r      return true;\r}\r\rbool DoELine(ServerConfig* conf, const char* tag, char** entries, ValueList &values, int* types)\r{\r     const char* reason = values[0].GetString();\r    const char* host = values[1].GetString();\r\r     conf->GetInstance()->XLines->add_eline(0,"<Config>",reason,host);\r      return true;\r}\r\rIdentHostPair XLineManager::IdentSplit(const std::string &ident_and_host)\r{\r    IdentHostPair n = std::make_pair<std::string,std::string>("*","*");\r    std::string::size_type x = ident_and_host.find('@');\r   if (x != std::string::npos)\r    {\r              n.second = ident_and_host.substr(x + 1,ident_and_host.length());\r               n.first = ident_and_host.substr(0, x);\r         if (!n.first.length())\r                 n.first.assign("*");\r           if (!n.second.length())\r                        n.second.assign("*");\r  }\r      else\r   {\r              n.second = ident_and_host;\r     }\r\r     return n;\r}\r\r// adds a g:line\r\rbool XLineManager::add_gline(long duration, const char* source,const char* reason,const char* hostmask)\r{\r       IdentHostPair ih = IdentSplit(hostmask);\r\r      if (del_gline(hostmask, true))\r         return false;\r\r GLine* item = new GLine(ServerInstance->Time(), duration, source, reason, ih.first.c_str(), ih.second.c_str());\r\r       if (duration)\r  {\r              glines.push_back(item);\r                sort(glines.begin(), glines.end(),XLineManager::GSortComparison);\r      }\r      else\r   {\r              pglines.push_back(item);\r       }\r\r     return true;\r}\r\r// adds an e:line (exception to bans)\r\rbool XLineManager::add_eline(long duration, const char* source, const char* reason, const char* hostmask)\r{\r     IdentHostPair ih = IdentSplit(hostmask);\r\r      if (del_eline(hostmask, true))\r         return false;\r\r ELine* item = new ELine(ServerInstance->Time(), duration, source, reason, ih.first.c_str(), ih.second.c_str());\r\r       if (duration)\r  {\r              elines.push_back(item);\r                sort(elines.begin(), elines.end(),XLineManager::ESortComparison);\r      }\r      else\r   {\r              pelines.push_back(item);\r       }\r      return true;\r}\r\r// adds a q:line\r\rbool XLineManager::add_qline(long duration, const char* source, const char* reason, const char* nickname)\r{\r  if (del_qline(nickname, true))\r         return false;\r\r QLine* item = new QLine(ServerInstance->Time(), duration, source, reason, nickname);\r\r  if (duration)\r  {\r              qlines.push_back(item);\r                sort(qlines.begin(), qlines.end(),XLineManager::QSortComparison);\r      }\r      else\r   {\r              pqlines.push_back(item);\r       }\r      return true;\r}\r\r// adds a z:line\r\rbool XLineManager::add_zline(long duration, const char* source, const char* reason, const char* ipaddr)\r{\r    if (strchr(ipaddr,'@'))\r        {\r              while (*ipaddr != '@')\r                 ipaddr++;\r              ipaddr++;\r      }\r\r     if (del_zline(ipaddr, true))\r           return false;\r\r ZLine* item = new ZLine(ServerInstance->Time(), duration, source, reason, ipaddr);\r\r    if (duration)\r  {\r              zlines.push_back(item);\r                sort(zlines.begin(), zlines.end(),XLineManager::ZSortComparison);\r      }\r      else\r   {\r              pzlines.push_back(item);\r       }\r      return true;\r}\r\r// adds a k:line\r\rbool XLineManager::add_kline(long duration, const char* source, const char* reason, const char* hostmask)\r{\r  IdentHostPair ih = IdentSplit(hostmask);\r\r      if (del_kline(hostmask, true))\r         return false;\r\r KLine* item = new KLine(ServerInstance->Time(), duration, source, reason, ih.first.c_str(), ih.second.c_str());\r\r       if (duration)\r  {\r              klines.push_back(item);\r                sort(klines.begin(), klines.end(),XLineManager::KSortComparison);\r      }\r      else\r   {\r              pklines.push_back(item);\r       }\r      return true;\r}\r\r// deletes a g:line, returns true if the line existed and was removed\r\rbool XLineManager::del_gline(const char* hostmask, bool simulate)\r{\r     IdentHostPair ih = IdentSplit(hostmask);\r       for (std::vector<GLine*>::iterator i = glines.begin(); i != glines.end(); i++)\r {\r              if (!strcasecmp(ih.first.c_str(),(*i)->identmask) && !strcasecmp(ih.second.c_str(),(*i)->hostmask))\r            {\r                      if (!simulate)\r                 {\r                              delete *i;\r                             glines.erase(i);\r                       }\r                      return true;\r           }\r      }\r      for (std::vector<GLine*>::iterator i = pglines.begin(); i != pglines.end(); i++)\r       {\r              if (!strcasecmp(ih.first.c_str(),(*i)->identmask) && !strcasecmp(ih.second.c_str(),(*i)->hostmask))\r            {\r                      if (!simulate)\r                 {\r                              delete *i;\r                             pglines.erase(i);\r                      }\r                      return true;\r           }\r      }\r      return false;\r}\r\r// deletes a e:line, returns true if the line existed and was removed\r\rbool XLineManager::del_eline(const char* hostmask, bool simulate)\r{\r    IdentHostPair ih = IdentSplit(hostmask);\r       for (std::vector<ELine*>::iterator i = elines.begin(); i != elines.end(); i++)\r {\r              if (!strcasecmp(ih.first.c_str(),(*i)->identmask) && !strcasecmp(ih.second.c_str(),(*i)->hostmask))\r            {\r                      if (!simulate)\r                 {\r                              delete *i;\r                             elines.erase(i);\r                       }\r                      return true;\r           }\r      }\r      for (std::vector<ELine*>::iterator i = pelines.begin(); i != pelines.end(); i++)\r       {\r              if (!strcasecmp(ih.first.c_str(),(*i)->identmask) && !strcasecmp(ih.second.c_str(),(*i)->hostmask))\r            {\r                      if (!simulate)\r                 {\r                              delete *i;\r                             pelines.erase(i);\r                      }\r                      return true;\r           }\r      }\r      return false;\r}\r\r// deletes a q:line, returns true if the line existed and was removed\r\rbool XLineManager::del_qline(const char* nickname, bool simulate)\r{\r    for (std::vector<QLine*>::iterator i = qlines.begin(); i != qlines.end(); i++)\r {\r              if (!strcasecmp(nickname,(*i)->nick))\r          {\r                      if (!simulate)\r                 {\r                              delete *i;\r                             qlines.erase(i);\r                       }\r                      return true;\r           }\r      }\r      for (std::vector<QLine*>::iterator i = pqlines.begin(); i != pqlines.end(); i++)\r       {\r              if (!strcasecmp(nickname,(*i)->nick))\r          {\r                      if (!simulate)\r                 {\r                              delete *i;\r                             pqlines.erase(i);\r                      }\r                      return true;\r           }\r      }\r      return false;\r}\r\r// deletes a z:line, returns true if the line existed and was removed\r\rbool XLineManager::del_zline(const char* ipaddr, bool simulate)\r{\r      for (std::vector<ZLine*>::iterator i = zlines.begin(); i != zlines.end(); i++)\r {\r              if (!strcasecmp(ipaddr,(*i)->ipaddr))\r          {\r                      if (!simulate)\r                 {\r                              delete *i;\r                             zlines.erase(i);\r                       }\r                      return true;\r           }\r      }\r      for (std::vector<ZLine*>::iterator i = pzlines.begin(); i != pzlines.end(); i++)\r       {\r              if (!strcasecmp(ipaddr,(*i)->ipaddr))\r          {\r                      if (!simulate)\r                 {\r                              delete *i;\r                             pzlines.erase(i);\r                      }\r                      return true;\r           }\r      }\r      return false;\r}\r\r// deletes a k:line, returns true if the line existed and was removed\r\rbool XLineManager::del_kline(const char* hostmask, bool simulate)\r{\r    IdentHostPair ih = IdentSplit(hostmask);\r       for (std::vector<KLine*>::iterator i = klines.begin(); i != klines.end(); i++)\r {\r              if (!strcasecmp(ih.first.c_str(),(*i)->identmask) && !strcasecmp(ih.second.c_str(),(*i)->hostmask))\r            {\r                      if (!simulate)\r                 {\r                              delete *i;\r                             klines.erase(i);\r                       }\r                      return true;\r           }\r      }\r      for (std::vector<KLine*>::iterator i = pklines.begin(); i != pklines.end(); i++)\r       {\r              if (!strcasecmp(ih.first.c_str(),(*i)->identmask) && !strcasecmp(ih.second.c_str(),(*i)->hostmask))\r            {\r                      if (!simulate)\r                 {\r                              delete *i;\r                             pklines.erase(i);\r                      }\r                      return true;\r           }\r      }\r      return false;\r}\r\r// returns a pointer to the reason if a nickname matches a qline, NULL if it didnt match\r\rQLine* XLineManager::matches_qline(const char* nick, bool permonly)\r{\r       if ((qlines.empty()) && (pqlines.empty()))\r             return NULL;\r   if (!permonly)\r {\r              for (std::vector<QLine*>::iterator i = qlines.begin(); i != qlines.end(); i++)\r                 if (match(nick,(*i)->nick))\r                            return (*i);\r   }\r      for (std::vector<QLine*>::iterator i = pqlines.begin(); i != pqlines.end(); i++)\r               if (match(nick,(*i)->nick))\r                    return (*i);\r   return NULL;\r}\r\r// returns a pointer to the reason if a host matches a gline, NULL if it didnt match\r\rGLine* XLineManager::matches_gline(userrec* user, bool permonly)\r{\r       if ((glines.empty()) && (pglines.empty()))\r             return NULL;\r   if (!permonly)\r {\r              for (std::vector<GLine*>::iterator i = glines.begin(); i != glines.end(); i++)\r         {\r                      if ((match(user->ident,(*i)->identmask)))\r                      {\r                              if ((match(user->host,(*i)->hostmask, true)) || (match(user->GetIPString(),(*i)->hostmask, true)))\r                             {\r                                      return (*i);\r                           }\r                      }\r              }\r      }\r      for (std::vector<GLine*>::iterator i = pglines.begin(); i != pglines.end(); i++)\r       {\r              if ((match(user->ident,(*i)->identmask)))\r              {\r                      if ((match(user->host,(*i)->hostmask, true)) || (match(user->GetIPString(),(*i)->hostmask, true)))\r                     {\r                              return (*i);\r                   }\r              }\r      }\r      return NULL;\r}\r\rELine* XLineManager::matches_exception(userrec* user, bool permonly)\r{\r if ((elines.empty()) && (pelines.empty()))\r             return NULL;\r   char host2[MAXBUF];\r    snprintf(host2,MAXBUF,"*@%s",user->host);\r      if (!permonly)\r {\r              for (std::vector<ELine*>::iterator i = elines.begin(); i != elines.end(); i++)\r         {\r                      if ((match(user->ident,(*i)->identmask)))\r                      {\r                              if ((match(user->host,(*i)->hostmask, true)) || (match(user->GetIPString(),(*i)->hostmask, true)))\r                             {\r                                      return (*i);\r                           }\r                      }\r              }\r      }\r      for (std::vector<ELine*>::iterator i = pelines.begin(); i != pelines.end(); i++)\r       {\r              if ((match(user->ident,(*i)->identmask)))\r              {\r                      if ((match(user->host,(*i)->hostmask, true)) || (match(user->GetIPString(),(*i)->hostmask, true)))\r                     {\r                              return (*i);\r                   }\r              }\r      }\r      return NULL;\r}\r\r\rvoid XLineManager::gline_set_creation_time(const char* host, time_t create_time)\r{\r    for (std::vector<GLine*>::iterator i = glines.begin(); i != glines.end(); i++)\r {\r              if (!strcasecmp(host,(*i)->hostmask))\r          {\r                      (*i)->set_time = create_time;\r                  (*i)->expiry = create_time + (*i)->duration;\r                   return;\r                }\r      }\r      for (std::vector<GLine*>::iterator i = pglines.begin(); i != pglines.end(); i++)\r       {\r              if (!strcasecmp(host,(*i)->hostmask))\r          {\r                      (*i)->set_time = create_time;\r                  return;\r                }\r      }\r      return ;\r}\r\rvoid XLineManager::eline_set_creation_time(const char* host, time_t create_time)\r{\r for (std::vector<ELine*>::iterator i = elines.begin(); i != elines.end(); i++)\r {\r              if (!strcasecmp(host,(*i)->hostmask))\r          {\r                      (*i)->set_time = create_time;\r                  (*i)->expiry = create_time + (*i)->duration;\r                   return;\r                }\r      }\r      for (std::vector<ELine*>::iterator i = pelines.begin(); i != pelines.end(); i++)\r       {\r              if (!strcasecmp(host,(*i)->hostmask))\r          {\r                      (*i)->set_time = create_time;\r                  return;\r                }\r      }\r      return;\r}\r\rvoid XLineManager::qline_set_creation_time(const char* nick, time_t create_time)\r{\r  for (std::vector<QLine*>::iterator i = qlines.begin(); i != qlines.end(); i++)\r {\r              if (!strcasecmp(nick,(*i)->nick))\r              {\r                      (*i)->set_time = create_time;\r                  (*i)->expiry = create_time + (*i)->duration;\r                   return;\r                }\r      }\r      for (std::vector<QLine*>::iterator i = pqlines.begin(); i != pqlines.end(); i++)\r       {\r              if (!strcasecmp(nick,(*i)->nick))\r              {\r                      (*i)->set_time = create_time;\r                  return;\r                }\r      }\r      return;\r}\r\rvoid XLineManager::zline_set_creation_time(const char* ip, time_t create_time)\r{\r    for (std::vector<ZLine*>::iterator i = zlines.begin(); i != zlines.end(); i++)\r {\r              if (!strcasecmp(ip,(*i)->ipaddr))\r              {\r                      (*i)->set_time = create_time;\r                  (*i)->expiry = create_time + (*i)->duration;\r                   return;\r                }\r      }\r      for (std::vector<ZLine*>::iterator i = pzlines.begin(); i != pzlines.end(); i++)\r       {\r              if (!strcasecmp(ip,(*i)->ipaddr))\r              {\r                      (*i)->set_time = create_time;\r                  return;\r                }\r      }\r      return;\r}\r\r// returns a pointer to the reason if an ip address matches a zline, NULL if it didnt match\r\rZLine* XLineManager::matches_zline(const char* ipaddr, bool permonly)\r{\r        if ((zlines.empty()) && (pzlines.empty()))\r             return NULL;\r   if (!permonly)\r {\r              for (std::vector<ZLine*>::iterator i = zlines.begin(); i != zlines.end(); i++)\r                 if (match(ipaddr,(*i)->ipaddr, true))\r                          return (*i);\r   }\r      for (std::vector<ZLine*>::iterator i = pzlines.begin(); i != pzlines.end(); i++)\r               if (match(ipaddr,(*i)->ipaddr, true))\r                  return (*i);\r   return NULL;\r}\r\r// returns a pointer to the reason if a host matches a kline, NULL if it didnt match\r\rKLine* XLineManager::matches_kline(userrec* user, bool permonly)\r{\r       if ((klines.empty()) && (pklines.empty()))\r             return NULL;\r   if (!permonly)\r {\r              for (std::vector<KLine*>::iterator i = klines.begin(); i != klines.end(); i++)\r         {\r                      if ((match(user->ident,(*i)->identmask)))\r                      {\r                              if ((match(user->host,(*i)->hostmask, true)) || (match(user->GetIPString(),(*i)->hostmask, true)))\r                             {\r                                      return (*i);\r                           }\r                      }\r              }\r      }\r      for (std::vector<KLine*>::iterator i = pklines.begin(); i != pklines.end(); i++)\r       {\r              if ((match(user->ident,(*i)->identmask)))\r              {\r                      if ((match(user->host,(*i)->hostmask, true)) || (match(user->GetIPString(),(*i)->hostmask, true)))\r                     {\r                              return (*i);\r                   }\r              }\r      }\r      return NULL;\r}\r\rbool XLineManager::GSortComparison ( const GLine* one, const GLine* two )\r{\r    return (one->expiry) < (two->expiry);\r}\r\rbool XLineManager::ESortComparison ( const ELine* one, const ELine* two )\r{\r   return (one->expiry) < (two->expiry);\r}\r\rbool XLineManager::ZSortComparison ( const ZLine* one, const ZLine* two )\r{\r   return (one->expiry) < (two->expiry);\r}\r\rbool XLineManager::KSortComparison ( const KLine* one, const KLine* two )\r{\r   return (one->expiry) < (two->expiry);\r}\r\rbool XLineManager::QSortComparison ( const QLine* one, const QLine* two )\r{\r   return (one->expiry) < (two->expiry);\r}\r\r// removes lines that have expired\r\rvoid XLineManager::expire_lines()\r{\r       time_t current = ServerInstance->Time();\r\r      /* Because we now store all our XLines in sorted order using ((*i)->duration + (*i)->set_time) as a key, this\r   * means that to expire the XLines we just need to do a while, picking off the top few until there are\r  * none left at the head of the queue that are after the current time.\r  */\r\r   while ((glines.size()) && (current > (*glines.begin())->expiry))\r       {\r              std::vector<GLine*>::iterator i = glines.begin();\r              ServerInstance->SNO->WriteToSnoMask('x',"Expiring timed G-Line %s@%s (set by %s %d seconds ago)",(*i)->identmask,(*i)->hostmask,(*i)->source,(*i)->duration);\r          glines.erase(i);\r       }\r\r     while ((elines.size()) && (current > (*elines.begin())->expiry))\r       {\r              std::vector<ELine*>::iterator i = elines.begin();\r              ServerInstance->SNO->WriteToSnoMask('x',"Expiring timed E-Line %s@%s (set by %s %d seconds ago)",(*i)->identmask,(*i)->hostmask,(*i)->source,(*i)->duration);\r          elines.erase(i);\r       }\r\r     while ((zlines.size()) && (current > (*zlines.begin())->expiry))\r       {\r              std::vector<ZLine*>::iterator i = zlines.begin();\r              ServerInstance->SNO->WriteToSnoMask('x',"Expiring timed Z-Line %s (set by %s %d seconds ago)",(*i)->ipaddr,(*i)->source,(*i)->duration);\r               zlines.erase(i);\r       }\r\r     while ((klines.size()) && (current > (*klines.begin())->expiry))\r       {\r              std::vector<KLine*>::iterator i = klines.begin();\r              ServerInstance->SNO->WriteToSnoMask('x',"Expiring timed K-Line %s@%s (set by %s %d seconds ago)",(*i)->identmask,(*i)->hostmask,(*i)->source,(*i)->duration);\r          klines.erase(i);\r       }\r\r     while ((qlines.size()) && (current > (*qlines.begin())->expiry))\r       {\r              std::vector<QLine*>::iterator i = qlines.begin();\r              ServerInstance->SNO->WriteToSnoMask('x',"Expiring timed Q-Line %s (set by %s %d seconds ago)",(*i)->nick,(*i)->source,(*i)->duration);\r         qlines.erase(i);\r       }\r\r}\r\r// applies lines, removing clients and changing nicks etc as applicable\r\rvoid XLineManager::apply_lines(const int What)\r{\r        if (!What)\r             return;\r\r       if (What & APPLY_PERM_ONLY)\r    {\r              char reason[MAXBUF];\r\r          if ((!pglines.size()) && (!pklines.size()) && (!pzlines.size()) && (!pqlines.size()))\r                  return;\r\r               XLine* check = NULL;\r           for (std::vector<userrec*>::const_iterator u2 = ServerInstance->local_users.begin(); u2 != ServerInstance->local_users.end(); u2++)\r            {\r                      userrec* u = (userrec*)(*u2);\r\r                 if (elines.size() || pelines.size())\r                           if (matches_exception(u))\r                                      continue;\r\r                     if ((What & APPLY_GLINES) && pglines.size())\r                   {\r                              if ((check = matches_gline(u,true)))\r                           {\r                                      snprintf(reason,MAXBUF,"G-Lined: %s",check->reason);\r                                   if (*ServerInstance->Config->MoronBanner)\r                                              u->WriteServ("NOTICE %s :*** %s", u->nick, ServerInstance->Config->MoronBanner);\r                                       if (ServerInstance->Config->HideBans)\r                                          ServerInstance->GlobalCulls.AddItem(u, "G-Lined", reason);\r                                     else\r                                           ServerInstance->GlobalCulls.AddItem(u, reason);\r                                }\r                      }\r\r                     if ((What & APPLY_KLINES) && pklines.size())\r                   {\r                              if ((check = matches_kline(u,true)))\r                           {\r                                      snprintf(reason,MAXBUF,"K-Lined: %s",check->reason);\r                                   if (*ServerInstance->Config->MoronBanner)\r                                              u->WriteServ("NOTICE %s :*** %s", u->nick, ServerInstance->Config->MoronBanner);\r                                       if (ServerInstance->Config->HideBans)\r                                          ServerInstance->GlobalCulls.AddItem(u, "K-Lined", reason);\r                                     else\r                                           ServerInstance->GlobalCulls.AddItem(u, reason);\r                                }\r                      }\r\r                     if ((What & APPLY_QLINES) && pqlines.size())\r                   {\r                              if ((check = matches_qline(u->nick,true)))\r                             {\r                                      snprintf(reason,MAXBUF,"Q-Lined: %s",check->reason);\r                                   if (*ServerInstance->Config->MoronBanner)\r                                              u->WriteServ("NOTICE %s :*** %s", u->nick, ServerInstance->Config->MoronBanner);\r                                       if (ServerInstance->Config->HideBans)\r                                          ServerInstance->GlobalCulls.AddItem(u, "Q-Lined", reason);\r                                     else\r                                           ServerInstance->GlobalCulls.AddItem(u, reason);\r                                }\r                      }\r\r                     if ((What & APPLY_ZLINES) && pzlines.size())\r                   {\r                              if ((check = matches_zline(u->GetIPString(),true)))\r                            {\r                                      snprintf(reason,MAXBUF,"Z-Lined: %s",check->reason);\r                                   if (*ServerInstance->Config->MoronBanner)\r                                              u->WriteServ("NOTICE %s :*** %s", u->nick, ServerInstance->Config->MoronBanner);\r                                       if (ServerInstance->Config->HideBans)\r                                          ServerInstance->GlobalCulls.AddItem(u, "Z-Lined", reason);\r                                     else\r                                           ServerInstance->GlobalCulls.AddItem(u, reason);\r                                }\r                      }\r              }\r      }\r      else\r   {\r              char reason[MAXBUF];\r\r          if ((!glines.size()) && (!klines.size()) && (!zlines.size()) && (!qlines.size()) &&\r            (!pglines.size()) && (!pklines.size()) && (!pzlines.size()) && (!pqlines.size()))\r                      return;\r\r               XLine* check = NULL;\r           for (std::vector<userrec*>::const_iterator u2 = ServerInstance->local_users.begin(); u2 != ServerInstance->local_users.end(); u2++)\r            {\r                      userrec* u = (userrec*)(*u2);\r\r                 if (elines.size() || pelines.size())\r                   {\r                              // ignore people matching exempts\r                              if (matches_exception(u))\r                                      continue;\r                      }\r                      if ((What & APPLY_GLINES) && (glines.size() || pglines.size()))\r                        {\r                              if ((check = matches_gline(u)))\r                                {\r                                      snprintf(reason,MAXBUF,"G-Lined: %s",check->reason);\r                                   if (*ServerInstance->Config->MoronBanner)\r                                              u->WriteServ("NOTICE %s :*** %s", u->nick, ServerInstance->Config->MoronBanner);\r                                       if (ServerInstance->Config->HideBans)\r                                          ServerInstance->GlobalCulls.AddItem(u, "G-Lined", reason);\r                                     else\r                                           ServerInstance->GlobalCulls.AddItem(u, reason);\r                                }\r                      }\r                      if ((What & APPLY_KLINES) && (klines.size() || pklines.size()))\r                        {\r                              if ((check = matches_kline(u)))\r                                {\r                                      snprintf(reason,MAXBUF,"K-Lined: %s",check->reason);\r                                   if (*ServerInstance->Config->MoronBanner)\r                                              u->WriteServ("NOTICE %s :*** %s", u->nick, ServerInstance->Config->MoronBanner);\r                                       if (ServerInstance->Config->HideBans)\r                                          ServerInstance->GlobalCulls.AddItem(u, "K-Lined", reason);\r                                     else\r                                           ServerInstance->GlobalCulls.AddItem(u, reason);\r                                }\r                      }\r                      if ((What & APPLY_QLINES) && (qlines.size() || pqlines.size()))\r                        {\r                              if ((check = matches_qline(u->nick)))\r                          {\r                                      snprintf(reason,MAXBUF,"Q-Lined: %s",check->reason);\r                                   if (*ServerInstance->Config->MoronBanner)\r                                              u->WriteServ("NOTICE %s :*** %s", u->nick, ServerInstance->Config->MoronBanner);\r                                       if (ServerInstance->Config->HideBans)\r                                          ServerInstance->GlobalCulls.AddItem(u, "Q-Lined", reason);\r                                     else\r                                           ServerInstance->GlobalCulls.AddItem(u, reason);\r                                }\r                      }\r                      if ((What & APPLY_ZLINES) && (zlines.size() || pzlines.size()))\r                        {\r                              if ((check = matches_zline(u->GetIPString())))\r                         {\r                                      snprintf(reason,MAXBUF,"Z-Lined: %s", check->reason);\r                                  if (*ServerInstance->Config->MoronBanner)\r                                              u->WriteServ("NOTICE %s :*** %s", u->nick, ServerInstance->Config->MoronBanner);\r                                       if (ServerInstance->Config->HideBans)\r                                          ServerInstance->GlobalCulls.AddItem(u, "Z-Lined", reason);\r                                     else\r                                           ServerInstance->GlobalCulls.AddItem(u, reason);\r                                }\r                      }\r              }\r      }\r}\r\rvoid XLineManager::stats_k(userrec* user, string_list &results)\r{\r std::string sn = ServerInstance->Config->ServerName;\r   for (std::vector<KLine*>::iterator i = klines.begin(); i != klines.end(); i++)\r         results.push_back(sn+" 216 "+user->nick+" :"+(*i)->identmask+"@"+(*i)->hostmask+" "+ConvToStr((*i)->set_time)+" "+ConvToStr((*i)->duration)+" "+(*i)->source+" :"+(*i)->reason);\r       for (std::vector<KLine*>::iterator i = pklines.begin(); i != pklines.end(); i++)\r               results.push_back(sn+" 216 "+user->nick+" :"+(*i)->identmask+"@"+(*i)->hostmask+" "+ConvToStr((*i)->set_time)+" "+ConvToStr((*i)->duration)+" "+(*i)->source+" :"+(*i)->reason);\r}\r\rvoid XLineManager::stats_g(userrec* user, string_list &results)\r{\r  std::string sn = ServerInstance->Config->ServerName;\r   for (std::vector<GLine*>::iterator i = glines.begin(); i != glines.end(); i++)\r         results.push_back(sn+" 223 "+user->nick+" :"+(*i)->identmask+"@"+(*i)->hostmask+" "+ConvToStr((*i)->set_time)+" "+ConvToStr((*i)->duration)+" "+(*i)->source+" :"+(*i)->reason);\r       for (std::vector<GLine*>::iterator i = pglines.begin(); i != pglines.end(); i++)\r               results.push_back(sn+" 223 "+user->nick+" :"+(*i)->identmask+"@"+(*i)->hostmask+" "+ConvToStr((*i)->set_time)+" "+ConvToStr((*i)->duration)+" "+(*i)->source+" :"+(*i)->reason);\r}\r\rvoid XLineManager::stats_q(userrec* user, string_list &results)\r{\r  std::string sn = ServerInstance->Config->ServerName;\r   for (std::vector<QLine*>::iterator i = qlines.begin(); i != qlines.end(); i++)\r         results.push_back(sn+" 217 "+user->nick+" :"+(*i)->nick+" "+ConvToStr((*i)->set_time)+" "+ConvToStr((*i)->duration)+" "+(*i)->source+" :"+(*i)->reason);\r       for (std::vector<QLine*>::iterator i = pqlines.begin(); i != pqlines.end(); i++)\r               results.push_back(sn+" 217 "+user->nick+" :"+(*i)->nick+" "+ConvToStr((*i)->set_time)+" "+ConvToStr((*i)->duration)+" "+(*i)->source+" :"+(*i)->reason);\r}\r\rvoid XLineManager::stats_z(userrec* user, string_list &results)\r{\r  std::string sn = ServerInstance->Config->ServerName;\r   for (std::vector<ZLine*>::iterator i = zlines.begin(); i != zlines.end(); i++)\r         results.push_back(sn+" 223 "+user->nick+" :"+(*i)->ipaddr+" "+ConvToStr((*i)->set_time)+" "+ConvToStr((*i)->duration)+" "+(*i)->source+" :"+(*i)->reason);\r     for (std::vector<ZLine*>::iterator i = pzlines.begin(); i != pzlines.end(); i++)\r               results.push_back(sn+" 223 "+user->nick+" :"+(*i)->ipaddr+" "+ConvToStr((*i)->set_time)+" "+ConvToStr((*i)->duration)+" "+(*i)->source+" :"+(*i)->reason);\r}\r\rvoid XLineManager::stats_e(userrec* user, string_list &results)\r{\r        std::string sn = ServerInstance->Config->ServerName;\r   for (std::vector<ELine*>::iterator i = elines.begin(); i != elines.end(); i++)\r         results.push_back(sn+" 223 "+user->nick+" :"+(*i)->identmask+"@"+(*i)->hostmask+" "+ConvToStr((*i)->set_time)+" "+ConvToStr((*i)->duration)+" "+(*i)->source+" :"+(*i)->reason);\r       for (std::vector<ELine*>::iterator i = pelines.begin(); i != pelines.end(); i++)\r               results.push_back(sn+" 223 "+user->nick+" :"+(*i)->identmask+"@"+(*i)->hostmask+" "+ConvToStr((*i)->set_time)+" "+ConvToStr((*i)->duration)+" "+(*i)->source+" :"+(*i)->reason);\r}\r\rXLineManager::XLineManager(InspIRCd* Instance) : ServerInstance(Instance)\r{\r}\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd.h"
+#include "users.h"
+#include "modules.h"
+#include "wildcard.h"
+#include "xline.h"
+
+/* Version two, now with optimized expiry!
+ *
+ * Because the old way was horrendously slow, the new way of expiring xlines is very
+ * very efficient. I have improved the efficiency of the algorithm in two ways:
+ *
+ * (1) There are now two lists of items for each linetype. One list holds temporary
+ *     items, and the other list holds permanent items (ones which will expire).
+ *     Items which are on the permanent list are NEVER checked at all by the
+ *     expire_lines() function.
+ * (2) The temporary xline lists are always kept in strict numerical order, keyed by
+ *     current time + duration. This means that the line which is due to expire the
+ *     soonest is always pointed at by vector::begin(), so a simple while loop can
+ *     very efficiently, very quickly and above all SAFELY pick off the first few
+ *     items in the vector which need zapping.
+ *
+ *     -- Brain
+ */
+
+bool InitXLine(ServerConfig* conf, const char* tag)
+{
+       return true;
+}
+
+bool DoneZLine(ServerConfig* conf, const char* tag)
+{
+       conf->GetInstance()->XLines->apply_lines(APPLY_ZLINES|APPLY_PERM_ONLY);
+       return true;
+}
+
+bool DoneQLine(ServerConfig* conf, const char* tag)
+{
+       conf->GetInstance()->XLines->apply_lines(APPLY_QLINES|APPLY_PERM_ONLY);
+       return true;
+}
+
+bool DoneKLine(ServerConfig* conf, const char* tag)
+{
+       conf->GetInstance()->XLines->apply_lines(APPLY_KLINES|APPLY_PERM_ONLY);
+       return true;
+}
+
+bool DoneELine(ServerConfig* conf, const char* tag)
+{
+       /* Yes, this is supposed to do nothing, we dont 'apply' these */
+       return true;
+}
+
+bool DoZLine(ServerConfig* conf, const char* tag, char** entries, ValueList &values, int* types)
+{
+       const char* reason = values[0].GetString();
+       const char* ipmask = values[1].GetString();
+
+       conf->GetInstance()->XLines->add_zline(0,"<Config>",reason,ipmask);
+       return true;
+}
+
+bool DoQLine(ServerConfig* conf, const char* tag, char** entries, ValueList &values, int* types)
+{
+       const char* reason = values[0].GetString();
+       const char* nick = values[1].GetString();
+
+       conf->GetInstance()->XLines->add_qline(0,"<Config>",reason,nick);
+       return true;
+}
+
+bool DoKLine(ServerConfig* conf, const char* tag, char** entries, ValueList &values, int* types)
+{
+       const char* reason = values[0].GetString();
+       const char* host = values[1].GetString();
+
+       conf->GetInstance()->XLines->add_kline(0,"<Config>",reason,host);
+       return true;
+}
+
+bool DoELine(ServerConfig* conf, const char* tag, char** entries, ValueList &values, int* types)
+{
+       const char* reason = values[0].GetString();
+       const char* host = values[1].GetString();
+
+       conf->GetInstance()->XLines->add_eline(0,"<Config>",reason,host);
+       return true;
+}
+
+IdentHostPair XLineManager::IdentSplit(const std::string &ident_and_host)
+{
+       IdentHostPair n = std::make_pair<std::string,std::string>("*","*");
+       std::string::size_type x = ident_and_host.find('@');
+       if (x != std::string::npos)
+       {
+               n.second = ident_and_host.substr(x + 1,ident_and_host.length());
+               n.first = ident_and_host.substr(0, x);
+               if (!n.first.length())
+                       n.first.assign("*");
+               if (!n.second.length())
+                       n.second.assign("*");
+       }
+       else
+       {
+               n.second = ident_and_host;
+       }
+
+       return n;
+}
+
+// adds a g:line
+
+bool XLineManager::add_gline(long duration, const char* source,const char* reason,const char* hostmask)
+{
+       IdentHostPair ih = IdentSplit(hostmask);
+
+       if (del_gline(hostmask, true))
+               return false;
+
+       GLine* item = new GLine(ServerInstance->Time(), duration, source, reason, ih.first.c_str(), ih.second.c_str());
+
+       if (duration)
+       {
+               glines.push_back(item);
+               sort(glines.begin(), glines.end(),XLineManager::GSortComparison);
+       }
+       else
+       {
+               pglines.push_back(item);
+       }
+
+       return true;
+}
+
+// adds an e:line (exception to bans)
+
+bool XLineManager::add_eline(long duration, const char* source, const char* reason, const char* hostmask)
+{
+       IdentHostPair ih = IdentSplit(hostmask);
+
+       if (del_eline(hostmask, true))
+               return false;
+
+       ELine* item = new ELine(ServerInstance->Time(), duration, source, reason, ih.first.c_str(), ih.second.c_str());
+
+       if (duration)
+       {
+               elines.push_back(item);
+               sort(elines.begin(), elines.end(),XLineManager::ESortComparison);
+       }
+       else
+       {
+               pelines.push_back(item);
+       }
+       return true;
+}
+
+// adds a q:line
+
+bool XLineManager::add_qline(long duration, const char* source, const char* reason, const char* nickname)
+{
+       if (del_qline(nickname, true))
+               return false;
+
+       QLine* item = new QLine(ServerInstance->Time(), duration, source, reason, nickname);
+
+       if (duration)
+       {
+               qlines.push_back(item);
+               sort(qlines.begin(), qlines.end(),XLineManager::QSortComparison);
+       }
+       else
+       {
+               pqlines.push_back(item);
+       }
+       return true;
+}
+
+// adds a z:line
+
+bool XLineManager::add_zline(long duration, const char* source, const char* reason, const char* ipaddr)
+{
+       if (strchr(ipaddr,'@'))
+       {
+               while (*ipaddr != '@')
+                       ipaddr++;
+               ipaddr++;
+       }
+
+       if (del_zline(ipaddr, true))
+               return false;
+
+       ZLine* item = new ZLine(ServerInstance->Time(), duration, source, reason, ipaddr);
+
+       if (duration)
+       {
+               zlines.push_back(item);
+               sort(zlines.begin(), zlines.end(),XLineManager::ZSortComparison);
+       }
+       else
+       {
+               pzlines.push_back(item);
+       }
+       return true;
+}
+
+// adds a k:line
+
+bool XLineManager::add_kline(long duration, const char* source, const char* reason, const char* hostmask)
+{
+       IdentHostPair ih = IdentSplit(hostmask);
+
+       if (del_kline(hostmask, true))
+               return false;
+
+       KLine* item = new KLine(ServerInstance->Time(), duration, source, reason, ih.first.c_str(), ih.second.c_str());
+
+       if (duration)
+       {
+               klines.push_back(item);
+               sort(klines.begin(), klines.end(),XLineManager::KSortComparison);
+       }
+       else
+       {
+               pklines.push_back(item);
+       }
+       return true;
+}
+
+// deletes a g:line, returns true if the line existed and was removed
+
+bool XLineManager::del_gline(const char* hostmask, bool simulate)
+{
+       IdentHostPair ih = IdentSplit(hostmask);
+       for (std::vector<GLine*>::iterator i = glines.begin(); i != glines.end(); i++)
+       {
+               if (!strcasecmp(ih.first.c_str(),(*i)->identmask) && !strcasecmp(ih.second.c_str(),(*i)->hostmask))
+               {
+                       if (!simulate)
+                       {
+                               delete *i;
+                               glines.erase(i);
+                       }
+                       return true;
+               }
+       }
+       for (std::vector<GLine*>::iterator i = pglines.begin(); i != pglines.end(); i++)
+       {
+               if (!strcasecmp(ih.first.c_str(),(*i)->identmask) && !strcasecmp(ih.second.c_str(),(*i)->hostmask))
+               {
+                       if (!simulate)
+                       {
+                               delete *i;
+                               pglines.erase(i);
+                       }
+                       return true;
+               }
+       }
+       return false;
+}
+
+// deletes a e:line, returns true if the line existed and was removed
+
+bool XLineManager::del_eline(const char* hostmask, bool simulate)
+{
+       IdentHostPair ih = IdentSplit(hostmask);
+       for (std::vector<ELine*>::iterator i = elines.begin(); i != elines.end(); i++)
+       {
+               if (!strcasecmp(ih.first.c_str(),(*i)->identmask) && !strcasecmp(ih.second.c_str(),(*i)->hostmask))
+               {
+                       if (!simulate)
+                       {
+                               delete *i;
+                               elines.erase(i);
+                       }
+                       return true;
+               }
+       }
+       for (std::vector<ELine*>::iterator i = pelines.begin(); i != pelines.end(); i++)
+       {
+               if (!strcasecmp(ih.first.c_str(),(*i)->identmask) && !strcasecmp(ih.second.c_str(),(*i)->hostmask))
+               {
+                       if (!simulate)
+                       {
+                               delete *i;
+                               pelines.erase(i);
+                       }
+                       return true;
+               }
+       }
+       return false;
+}
+
+// deletes a q:line, returns true if the line existed and was removed
+
+bool XLineManager::del_qline(const char* nickname, bool simulate)
+{
+       for (std::vector<QLine*>::iterator i = qlines.begin(); i != qlines.end(); i++)
+       {
+               if (!strcasecmp(nickname,(*i)->nick))
+               {
+                       if (!simulate)
+                       {
+                               delete *i;
+                               qlines.erase(i);
+                       }
+                       return true;
+               }
+       }
+       for (std::vector<QLine*>::iterator i = pqlines.begin(); i != pqlines.end(); i++)
+       {
+               if (!strcasecmp(nickname,(*i)->nick))
+               {
+                       if (!simulate)
+                       {
+                               delete *i;
+                               pqlines.erase(i);
+                       }
+                       return true;
+               }
+       }
+       return false;
+}
+
+// deletes a z:line, returns true if the line existed and was removed
+
+bool XLineManager::del_zline(const char* ipaddr, bool simulate)
+{
+       for (std::vector<ZLine*>::iterator i = zlines.begin(); i != zlines.end(); i++)
+       {
+               if (!strcasecmp(ipaddr,(*i)->ipaddr))
+               {
+                       if (!simulate)
+                       {
+                               delete *i;
+                               zlines.erase(i);
+                       }
+                       return true;
+               }
+       }
+       for (std::vector<ZLine*>::iterator i = pzlines.begin(); i != pzlines.end(); i++)
+       {
+               if (!strcasecmp(ipaddr,(*i)->ipaddr))
+               {
+                       if (!simulate)
+                       {
+                               delete *i;
+                               pzlines.erase(i);
+                       }
+                       return true;
+               }
+       }
+       return false;
+}
+
+// deletes a k:line, returns true if the line existed and was removed
+
+bool XLineManager::del_kline(const char* hostmask, bool simulate)
+{
+       IdentHostPair ih = IdentSplit(hostmask);
+       for (std::vector<KLine*>::iterator i = klines.begin(); i != klines.end(); i++)
+       {
+               if (!strcasecmp(ih.first.c_str(),(*i)->identmask) && !strcasecmp(ih.second.c_str(),(*i)->hostmask))
+               {
+                       if (!simulate)
+                       {
+                               delete *i;
+                               klines.erase(i);
+                       }
+                       return true;
+               }
+       }
+       for (std::vector<KLine*>::iterator i = pklines.begin(); i != pklines.end(); i++)
+       {
+               if (!strcasecmp(ih.first.c_str(),(*i)->identmask) && !strcasecmp(ih.second.c_str(),(*i)->hostmask))
+               {
+                       if (!simulate)
+                       {
+                               delete *i;
+                               pklines.erase(i);
+                       }
+                       return true;
+               }
+       }
+       return false;
+}
+
+// returns a pointer to the reason if a nickname matches a qline, NULL if it didnt match
+
+QLine* XLineManager::matches_qline(const char* nick, bool permonly)
+{
+       if ((qlines.empty()) && (pqlines.empty()))
+               return NULL;
+       if (!permonly)
+       {
+               for (std::vector<QLine*>::iterator i = qlines.begin(); i != qlines.end(); i++)
+                       if (match(nick,(*i)->nick))
+                               return (*i);
+       }
+       for (std::vector<QLine*>::iterator i = pqlines.begin(); i != pqlines.end(); i++)
+               if (match(nick,(*i)->nick))
+                       return (*i);
+       return NULL;
+}
+
+// returns a pointer to the reason if a host matches a gline, NULL if it didnt match
+
+GLine* XLineManager::matches_gline(userrec* user, bool permonly)
+{
+       if ((glines.empty()) && (pglines.empty()))
+               return NULL;
+       if (!permonly)
+       {
+               for (std::vector<GLine*>::iterator i = glines.begin(); i != glines.end(); i++)
+               {
+                       if ((match(user->ident,(*i)->identmask)))
+                       {
+                               if ((match(user->host,(*i)->hostmask, true)) || (match(user->GetIPString(),(*i)->hostmask, true)))
+                               {
+                                       return (*i);
+                               }
+                       }
+               }
+       }
+       for (std::vector<GLine*>::iterator i = pglines.begin(); i != pglines.end(); i++)
+       {
+               if ((match(user->ident,(*i)->identmask)))
+               {
+                       if ((match(user->host,(*i)->hostmask, true)) || (match(user->GetIPString(),(*i)->hostmask, true)))
+                       {
+                               return (*i);
+                       }
+               }
+       }
+       return NULL;
+}
+
+ELine* XLineManager::matches_exception(userrec* user, bool permonly)
+{
+       if ((elines.empty()) && (pelines.empty()))
+               return NULL;
+       char host2[MAXBUF];
+       snprintf(host2,MAXBUF,"*@%s",user->host);
+       if (!permonly)
+       {
+               for (std::vector<ELine*>::iterator i = elines.begin(); i != elines.end(); i++)
+               {
+                       if ((match(user->ident,(*i)->identmask)))
+                       {
+                               if ((match(user->host,(*i)->hostmask, true)) || (match(user->GetIPString(),(*i)->hostmask, true)))
+                               {
+                                       return (*i);
+                               }
+                       }
+               }
+       }
+       for (std::vector<ELine*>::iterator i = pelines.begin(); i != pelines.end(); i++)
+       {
+               if ((match(user->ident,(*i)->identmask)))
+               {
+                       if ((match(user->host,(*i)->hostmask, true)) || (match(user->GetIPString(),(*i)->hostmask, true)))
+                       {
+                               return (*i);
+                       }
+               }
+       }
+       return NULL;
+}
+
+
+void XLineManager::gline_set_creation_time(const char* host, time_t create_time)
+{
+       for (std::vector<GLine*>::iterator i = glines.begin(); i != glines.end(); i++)
+       {
+               if (!strcasecmp(host,(*i)->hostmask))
+               {
+                       (*i)->set_time = create_time;
+                       (*i)->expiry = create_time + (*i)->duration;
+                       return;
+               }
+       }
+       for (std::vector<GLine*>::iterator i = pglines.begin(); i != pglines.end(); i++)
+       {
+               if (!strcasecmp(host,(*i)->hostmask))
+               {
+                       (*i)->set_time = create_time;
+                       return;
+               }
+       }
+       return ;
+}
+
+void XLineManager::eline_set_creation_time(const char* host, time_t create_time)
+{
+       for (std::vector<ELine*>::iterator i = elines.begin(); i != elines.end(); i++)
+       {
+               if (!strcasecmp(host,(*i)->hostmask))
+               {
+                       (*i)->set_time = create_time;
+                       (*i)->expiry = create_time + (*i)->duration;
+                       return;
+               }
+       }
+       for (std::vector<ELine*>::iterator i = pelines.begin(); i != pelines.end(); i++)
+       {
+               if (!strcasecmp(host,(*i)->hostmask))
+               {
+                       (*i)->set_time = create_time;
+                       return;
+               }
+       }
+       return;
+}
+
+void XLineManager::qline_set_creation_time(const char* nick, time_t create_time)
+{
+       for (std::vector<QLine*>::iterator i = qlines.begin(); i != qlines.end(); i++)
+       {
+               if (!strcasecmp(nick,(*i)->nick))
+               {
+                       (*i)->set_time = create_time;
+                       (*i)->expiry = create_time + (*i)->duration;
+                       return;
+               }
+       }
+       for (std::vector<QLine*>::iterator i = pqlines.begin(); i != pqlines.end(); i++)
+       {
+               if (!strcasecmp(nick,(*i)->nick))
+               {
+                       (*i)->set_time = create_time;
+                       return;
+               }
+       }
+       return;
+}
+
+void XLineManager::zline_set_creation_time(const char* ip, time_t create_time)
+{
+       for (std::vector<ZLine*>::iterator i = zlines.begin(); i != zlines.end(); i++)
+       {
+               if (!strcasecmp(ip,(*i)->ipaddr))
+               {
+                       (*i)->set_time = create_time;
+                       (*i)->expiry = create_time + (*i)->duration;
+                       return;
+               }
+       }
+       for (std::vector<ZLine*>::iterator i = pzlines.begin(); i != pzlines.end(); i++)
+       {
+               if (!strcasecmp(ip,(*i)->ipaddr))
+               {
+                       (*i)->set_time = create_time;
+                       return;
+               }
+       }
+       return;
+}
+
+// returns a pointer to the reason if an ip address matches a zline, NULL if it didnt match
+
+ZLine* XLineManager::matches_zline(const char* ipaddr, bool permonly)
+{
+       if ((zlines.empty()) && (pzlines.empty()))
+               return NULL;
+       if (!permonly)
+       {
+               for (std::vector<ZLine*>::iterator i = zlines.begin(); i != zlines.end(); i++)
+                       if (match(ipaddr,(*i)->ipaddr, true))
+                               return (*i);
+       }
+       for (std::vector<ZLine*>::iterator i = pzlines.begin(); i != pzlines.end(); i++)
+               if (match(ipaddr,(*i)->ipaddr, true))
+                       return (*i);
+       return NULL;
+}
+
+// returns a pointer to the reason if a host matches a kline, NULL if it didnt match
+
+KLine* XLineManager::matches_kline(userrec* user, bool permonly)
+{
+       if ((klines.empty()) && (pklines.empty()))
+               return NULL;
+       if (!permonly)
+       {
+               for (std::vector<KLine*>::iterator i = klines.begin(); i != klines.end(); i++)
+               {
+                       if ((match(user->ident,(*i)->identmask)))
+                       {
+                               if ((match(user->host,(*i)->hostmask, true)) || (match(user->GetIPString(),(*i)->hostmask, true)))
+                               {
+                                       return (*i);
+                               }
+                       }
+               }
+       }
+       for (std::vector<KLine*>::iterator i = pklines.begin(); i != pklines.end(); i++)
+       {
+               if ((match(user->ident,(*i)->identmask)))
+               {
+                       if ((match(user->host,(*i)->hostmask, true)) || (match(user->GetIPString(),(*i)->hostmask, true)))
+                       {
+                               return (*i);
+                       }
+               }
+       }
+       return NULL;
+}
+
+bool XLineManager::GSortComparison ( const GLine* one, const GLine* two )
+{
+       return (one->expiry) < (two->expiry);
+}
+
+bool XLineManager::ESortComparison ( const ELine* one, const ELine* two )
+{
+       return (one->expiry) < (two->expiry);
+}
+
+bool XLineManager::ZSortComparison ( const ZLine* one, const ZLine* two )
+{
+       return (one->expiry) < (two->expiry);
+}
+
+bool XLineManager::KSortComparison ( const KLine* one, const KLine* two )
+{
+       return (one->expiry) < (two->expiry);
+}
+
+bool XLineManager::QSortComparison ( const QLine* one, const QLine* two )
+{
+       return (one->expiry) < (two->expiry);
+}
+
+// removes lines that have expired
+
+void XLineManager::expire_lines()
+{
+       time_t current = ServerInstance->Time();
+
+       /* Because we now store all our XLines in sorted order using ((*i)->duration + (*i)->set_time) as a key, this
+        * means that to expire the XLines we just need to do a while, picking off the top few until there are
+        * none left at the head of the queue that are after the current time.
+        */
+
+       while ((glines.size()) && (current > (*glines.begin())->expiry))
+       {
+               std::vector<GLine*>::iterator i = glines.begin();
+               ServerInstance->SNO->WriteToSnoMask('x',"Expiring timed G-Line %s@%s (set by %s %d seconds ago)",(*i)->identmask,(*i)->hostmask,(*i)->source,(*i)->duration);
+               glines.erase(i);
+       }
+
+       while ((elines.size()) && (current > (*elines.begin())->expiry))
+       {
+               std::vector<ELine*>::iterator i = elines.begin();
+               ServerInstance->SNO->WriteToSnoMask('x',"Expiring timed E-Line %s@%s (set by %s %d seconds ago)",(*i)->identmask,(*i)->hostmask,(*i)->source,(*i)->duration);
+               elines.erase(i);
+       }
+
+       while ((zlines.size()) && (current > (*zlines.begin())->expiry))
+       {
+               std::vector<ZLine*>::iterator i = zlines.begin();
+               ServerInstance->SNO->WriteToSnoMask('x',"Expiring timed Z-Line %s (set by %s %d seconds ago)",(*i)->ipaddr,(*i)->source,(*i)->duration);
+               zlines.erase(i);
+       }
+
+       while ((klines.size()) && (current > (*klines.begin())->expiry))
+       {
+               std::vector<KLine*>::iterator i = klines.begin();
+               ServerInstance->SNO->WriteToSnoMask('x',"Expiring timed K-Line %s@%s (set by %s %d seconds ago)",(*i)->identmask,(*i)->hostmask,(*i)->source,(*i)->duration);
+               klines.erase(i);
+       }
+
+       while ((qlines.size()) && (current > (*qlines.begin())->expiry))
+       {
+               std::vector<QLine*>::iterator i = qlines.begin();
+               ServerInstance->SNO->WriteToSnoMask('x',"Expiring timed Q-Line %s (set by %s %d seconds ago)",(*i)->nick,(*i)->source,(*i)->duration);
+               qlines.erase(i);
+       }
+
+}
+
+// applies lines, removing clients and changing nicks etc as applicable
+
+void XLineManager::apply_lines(const int What)
+{
+       if (!What)
+               return;
+
+       if (What & APPLY_PERM_ONLY)
+       {
+               char reason[MAXBUF];
+
+               if ((!pglines.size()) && (!pklines.size()) && (!pzlines.size()) && (!pqlines.size()))
+                       return;
+
+               XLine* check = NULL;
+               for (std::vector<userrec*>::const_iterator u2 = ServerInstance->local_users.begin(); u2 != ServerInstance->local_users.end(); u2++)
+               {
+                       userrec* u = (userrec*)(*u2);
+
+                       if (elines.size() || pelines.size())
+                               if (matches_exception(u))
+                                       continue;
+
+                       if ((What & APPLY_GLINES) && pglines.size())
+                       {
+                               if ((check = matches_gline(u,true)))
+                               {
+                                       snprintf(reason,MAXBUF,"G-Lined: %s",check->reason);
+                                       if (*ServerInstance->Config->MoronBanner)
+                                               u->WriteServ("NOTICE %s :*** %s", u->nick, ServerInstance->Config->MoronBanner);
+                                       if (ServerInstance->Config->HideBans)
+                                               ServerInstance->GlobalCulls.AddItem(u, "G-Lined", reason);
+                                       else
+                                               ServerInstance->GlobalCulls.AddItem(u, reason);
+                               }
+                       }
+
+                       if ((What & APPLY_KLINES) && pklines.size())
+                       {
+                               if ((check = matches_kline(u,true)))
+                               {
+                                       snprintf(reason,MAXBUF,"K-Lined: %s",check->reason);
+                                       if (*ServerInstance->Config->MoronBanner)
+                                               u->WriteServ("NOTICE %s :*** %s", u->nick, ServerInstance->Config->MoronBanner);
+                                       if (ServerInstance->Config->HideBans)
+                                               ServerInstance->GlobalCulls.AddItem(u, "K-Lined", reason);
+                                       else
+                                               ServerInstance->GlobalCulls.AddItem(u, reason);
+                               }
+                       }
+
+                       if ((What & APPLY_QLINES) && pqlines.size())
+                       {
+                               if ((check = matches_qline(u->nick,true)))
+                               {
+                                       snprintf(reason,MAXBUF,"Q-Lined: %s",check->reason);
+                                       if (*ServerInstance->Config->MoronBanner)
+                                               u->WriteServ("NOTICE %s :*** %s", u->nick, ServerInstance->Config->MoronBanner);
+                                       if (ServerInstance->Config->HideBans)
+                                               ServerInstance->GlobalCulls.AddItem(u, "Q-Lined", reason);
+                                       else
+                                               ServerInstance->GlobalCulls.AddItem(u, reason);
+                               }
+                       }
+
+                       if ((What & APPLY_ZLINES) && pzlines.size())
+                       {
+                               if ((check = matches_zline(u->GetIPString(),true)))
+                               {
+                                       snprintf(reason,MAXBUF,"Z-Lined: %s",check->reason);
+                                       if (*ServerInstance->Config->MoronBanner)
+                                               u->WriteServ("NOTICE %s :*** %s", u->nick, ServerInstance->Config->MoronBanner);
+                                       if (ServerInstance->Config->HideBans)
+                                               ServerInstance->GlobalCulls.AddItem(u, "Z-Lined", reason);
+                                       else
+                                               ServerInstance->GlobalCulls.AddItem(u, reason);
+                               }
+                       }
+               }
+       }
+       else
+       {
+               char reason[MAXBUF];
+
+               if ((!glines.size()) && (!klines.size()) && (!zlines.size()) && (!qlines.size()) &&
+               (!pglines.size()) && (!pklines.size()) && (!pzlines.size()) && (!pqlines.size()))
+                       return;
+
+               XLine* check = NULL;
+               for (std::vector<userrec*>::const_iterator u2 = ServerInstance->local_users.begin(); u2 != ServerInstance->local_users.end(); u2++)
+               {
+                       userrec* u = (userrec*)(*u2);
+
+                       if (elines.size() || pelines.size())
+                       {
+                               // ignore people matching exempts
+                               if (matches_exception(u))
+                                       continue;
+                       }
+                       if ((What & APPLY_GLINES) && (glines.size() || pglines.size()))
+                       {
+                               if ((check = matches_gline(u)))
+                               {
+                                       snprintf(reason,MAXBUF,"G-Lined: %s",check->reason);
+                                       if (*ServerInstance->Config->MoronBanner)
+                                               u->WriteServ("NOTICE %s :*** %s", u->nick, ServerInstance->Config->MoronBanner);
+                                       if (ServerInstance->Config->HideBans)
+                                               ServerInstance->GlobalCulls.AddItem(u, "G-Lined", reason);
+                                       else
+                                               ServerInstance->GlobalCulls.AddItem(u, reason);
+                               }
+                       }
+                       if ((What & APPLY_KLINES) && (klines.size() || pklines.size()))
+                       {
+                               if ((check = matches_kline(u)))
+                               {
+                                       snprintf(reason,MAXBUF,"K-Lined: %s",check->reason);
+                                       if (*ServerInstance->Config->MoronBanner)
+                                               u->WriteServ("NOTICE %s :*** %s", u->nick, ServerInstance->Config->MoronBanner);
+                                       if (ServerInstance->Config->HideBans)
+                                               ServerInstance->GlobalCulls.AddItem(u, "K-Lined", reason);
+                                       else
+                                               ServerInstance->GlobalCulls.AddItem(u, reason);
+                               }
+                       }
+                       if ((What & APPLY_QLINES) && (qlines.size() || pqlines.size()))
+                       {
+                               if ((check = matches_qline(u->nick)))
+                               {
+                                       snprintf(reason,MAXBUF,"Q-Lined: %s",check->reason);
+                                       if (*ServerInstance->Config->MoronBanner)
+                                               u->WriteServ("NOTICE %s :*** %s", u->nick, ServerInstance->Config->MoronBanner);
+                                       if (ServerInstance->Config->HideBans)
+                                               ServerInstance->GlobalCulls.AddItem(u, "Q-Lined", reason);
+                                       else
+                                               ServerInstance->GlobalCulls.AddItem(u, reason);
+                               }
+                       }
+                       if ((What & APPLY_ZLINES) && (zlines.size() || pzlines.size()))
+                       {
+                               if ((check = matches_zline(u->GetIPString())))
+                               {
+                                       snprintf(reason,MAXBUF,"Z-Lined: %s", check->reason);
+                                       if (*ServerInstance->Config->MoronBanner)
+                                               u->WriteServ("NOTICE %s :*** %s", u->nick, ServerInstance->Config->MoronBanner);
+                                       if (ServerInstance->Config->HideBans)
+                                               ServerInstance->GlobalCulls.AddItem(u, "Z-Lined", reason);
+                                       else
+                                               ServerInstance->GlobalCulls.AddItem(u, reason);
+                               }
+                       }
+               }
+       }
+}
+
+void XLineManager::stats_k(userrec* user, string_list &results)
+{
+       std::string sn = ServerInstance->Config->ServerName;
+       for (std::vector<KLine*>::iterator i = klines.begin(); i != klines.end(); i++)
+               results.push_back(sn+" 216 "+user->nick+" :"+(*i)->identmask+"@"+(*i)->hostmask+" "+ConvToStr((*i)->set_time)+" "+ConvToStr((*i)->duration)+" "+(*i)->source+" :"+(*i)->reason);
+       for (std::vector<KLine*>::iterator i = pklines.begin(); i != pklines.end(); i++)
+               results.push_back(sn+" 216 "+user->nick+" :"+(*i)->identmask+"@"+(*i)->hostmask+" "+ConvToStr((*i)->set_time)+" "+ConvToStr((*i)->duration)+" "+(*i)->source+" :"+(*i)->reason);
+}
+
+void XLineManager::stats_g(userrec* user, string_list &results)
+{
+       std::string sn = ServerInstance->Config->ServerName;
+       for (std::vector<GLine*>::iterator i = glines.begin(); i != glines.end(); i++)
+               results.push_back(sn+" 223 "+user->nick+" :"+(*i)->identmask+"@"+(*i)->hostmask+" "+ConvToStr((*i)->set_time)+" "+ConvToStr((*i)->duration)+" "+(*i)->source+" :"+(*i)->reason);
+       for (std::vector<GLine*>::iterator i = pglines.begin(); i != pglines.end(); i++)
+               results.push_back(sn+" 223 "+user->nick+" :"+(*i)->identmask+"@"+(*i)->hostmask+" "+ConvToStr((*i)->set_time)+" "+ConvToStr((*i)->duration)+" "+(*i)->source+" :"+(*i)->reason);
+}
+
+void XLineManager::stats_q(userrec* user, string_list &results)
+{
+       std::string sn = ServerInstance->Config->ServerName;
+       for (std::vector<QLine*>::iterator i = qlines.begin(); i != qlines.end(); i++)
+               results.push_back(sn+" 217 "+user->nick+" :"+(*i)->nick+" "+ConvToStr((*i)->set_time)+" "+ConvToStr((*i)->duration)+" "+(*i)->source+" :"+(*i)->reason);
+       for (std::vector<QLine*>::iterator i = pqlines.begin(); i != pqlines.end(); i++)
+               results.push_back(sn+" 217 "+user->nick+" :"+(*i)->nick+" "+ConvToStr((*i)->set_time)+" "+ConvToStr((*i)->duration)+" "+(*i)->source+" :"+(*i)->reason);
+}
+
+void XLineManager::stats_z(userrec* user, string_list &results)
+{
+       std::string sn = ServerInstance->Config->ServerName;
+       for (std::vector<ZLine*>::iterator i = zlines.begin(); i != zlines.end(); i++)
+               results.push_back(sn+" 223 "+user->nick+" :"+(*i)->ipaddr+" "+ConvToStr((*i)->set_time)+" "+ConvToStr((*i)->duration)+" "+(*i)->source+" :"+(*i)->reason);
+       for (std::vector<ZLine*>::iterator i = pzlines.begin(); i != pzlines.end(); i++)
+               results.push_back(sn+" 223 "+user->nick+" :"+(*i)->ipaddr+" "+ConvToStr((*i)->set_time)+" "+ConvToStr((*i)->duration)+" "+(*i)->source+" :"+(*i)->reason);
+}
+
+void XLineManager::stats_e(userrec* user, string_list &results)
+{
+       std::string sn = ServerInstance->Config->ServerName;
+       for (std::vector<ELine*>::iterator i = elines.begin(); i != elines.end(); i++)
+               results.push_back(sn+" 223 "+user->nick+" :"+(*i)->identmask+"@"+(*i)->hostmask+" "+ConvToStr((*i)->set_time)+" "+ConvToStr((*i)->duration)+" "+(*i)->source+" :"+(*i)->reason);
+       for (std::vector<ELine*>::iterator i = pelines.begin(); i != pelines.end(); i++)
+               results.push_back(sn+" 223 "+user->nick+" :"+(*i)->identmask+"@"+(*i)->hostmask+" "+ConvToStr((*i)->set_time)+" "+ConvToStr((*i)->duration)+" "+(*i)->source+" :"+(*i)->reason);
+}
+
+XLineManager::XLineManager(InspIRCd* Instance) : ServerInstance(Instance)
+{
+}
index 1d1298d7c411cba681b3bce8f1babbbf6f0db9a1..d0eaf68e714a6a2a8c6d7eee6c02554c803aaec0 100644 (file)
@@ -1 +1,18 @@
------BEGIN CERTIFICATE-----\rMIIC1DCCAj+gAwIBAgIDcGbSMAsGCSqGSIb3DQEBBTCBgTEQMA4GA1UEBhMHRW5n\rbGFuZDElMCMGA1UEChMcRGVmYXVsdCBJbnNwSVJDZCBDZXJ0aWZpY2F0ZTEeMBwG\rA1UECxMVU2VydmVyIEFkbWluaXN0cmF0aW9uMQswCQYDVQQIEwJVSzEZMBcGA1UE\rAxMQaXJjLmluc3BpcmNkLm9yZzAeFw0wNzA2MTMyMTUyMTNaFw0wOTA1MTMyMTUy\rMTNaMIGBMRAwDgYDVQQGEwdFbmdsYW5kMSUwIwYDVQQKExxEZWZhdWx0IEluc3BJ\rUkNkIENlcnRpZmljYXRlMR4wHAYDVQQLExVTZXJ2ZXIgQWRtaW5pc3RyYXRpb24x\rCzAJBgNVBAgTAlVLMRkwFwYDVQQDExBpcmMuaW5zcGlyY2Qub3JnMIGcMAsGCSqG\rSIb3DQEBAQOBjAAwgYgCgYDIbKvMTTogBZxTi1yn4ncVK09Wr+F2AxP63HWTzxnE\rwNhcURSaUqpCzVIfcpr7/jKn+8I17MzaMvG8m+sPKngPK5WMN440p12uitkS+uzk\rLbJ7J/Z335ar6nZOtbIO+aTDRzUTnNHGHRgdQj4GGvx89l0u7vQM3R2f9Oe2lWlc\r1wIDAQABo18wXTAMBgNVHRMBAf8EAjAAMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggr\rBgEFBQcDATAPBgNVHQ8BAf8EBQMDB6AAMB0GA1UdDgQWBBQTdpXUljwHWvbEggnP\rBZMFhd1MvjALBgkqhkiG9w0BAQUDgYEARi9LL+mCxLWffiTHzGMO4ul0E0bXIzD5\rQzFI/llFzX4+fcuZJUFPgpBFJzxOqSO9RZAXHfm7x9sUMNpFP4ir4b2phQGr0QDd\r6nPHmcwuyiQISPIL3xcgrb2CuzQa/Wqmkxi5vXHf1CQQijJ1UA/FCPD6f+Dulcdq\rUAtrNsUBhLY=\r-----END CERTIFICATE-----\r
\ No newline at end of file
+-----BEGIN CERTIFICATE-----
+MIIC1DCCAj+gAwIBAgIDcGbSMAsGCSqGSIb3DQEBBTCBgTEQMA4GA1UEBhMHRW5n
+bGFuZDElMCMGA1UEChMcRGVmYXVsdCBJbnNwSVJDZCBDZXJ0aWZpY2F0ZTEeMBwG
+A1UECxMVU2VydmVyIEFkbWluaXN0cmF0aW9uMQswCQYDVQQIEwJVSzEZMBcGA1UE
+AxMQaXJjLmluc3BpcmNkLm9yZzAeFw0wNzA2MTMyMTUyMTNaFw0wOTA1MTMyMTUy
+MTNaMIGBMRAwDgYDVQQGEwdFbmdsYW5kMSUwIwYDVQQKExxEZWZhdWx0IEluc3BJ
+UkNkIENlcnRpZmljYXRlMR4wHAYDVQQLExVTZXJ2ZXIgQWRtaW5pc3RyYXRpb24x
+CzAJBgNVBAgTAlVLMRkwFwYDVQQDExBpcmMuaW5zcGlyY2Qub3JnMIGcMAsGCSqG
+SIb3DQEBAQOBjAAwgYgCgYDIbKvMTTogBZxTi1yn4ncVK09Wr+F2AxP63HWTzxnE
+wNhcURSaUqpCzVIfcpr7/jKn+8I17MzaMvG8m+sPKngPK5WMN440p12uitkS+uzk
+LbJ7J/Z335ar6nZOtbIO+aTDRzUTnNHGHRgdQj4GGvx89l0u7vQM3R2f9Oe2lWlc
+1wIDAQABo18wXTAMBgNVHRMBAf8EAjAAMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggr
+BgEFBQcDATAPBgNVHQ8BAf8EBQMDB6AAMB0GA1UdDgQWBBQTdpXUljwHWvbEggnP
+BZMFhd1MvjALBgkqhkiG9w0BAQUDgYEARi9LL+mCxLWffiTHzGMO4ul0E0bXIzD5
+QzFI/llFzX4+fcuZJUFPgpBFJzxOqSO9RZAXHfm7x9sUMNpFP4ir4b2phQGr0QDd
+6nPHmcwuyiQISPIL3xcgrb2CuzQa/Wqmkxi5vXHf1CQQijJ1UA/FCPD6f+Dulcdq
+UAtrNsUBhLY=
+-----END CERTIFICATE-----
index 8c16a98bf9c5dc7ed5eca81f3714f2ca478dddf1..6a5853c21bb30d0fb6a162d9d99f348bd75001fc 100644 (file)
@@ -1 +1,109 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __COLOURS_H\r#define __COLOURS_H\r\r#define TRED FOREGROUND_RED | FOREGROUND_INTENSITY\r#define TGREEN FOREGROUND_GREEN | FOREGROUND_INTENSITY\r#define TYELLOW FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY\r#define TNORMAL FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE\r#define TWHITE TNORMAL | FOREGROUND_INTENSITY\r#define TBLUE FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_INTENSITY\r\rinline void sc(WORD color) { SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), color); }\r\r/* Handles colors in printf */\rint printf_c(const char * format, ...)\r{\r   // Better hope we're not multithreaded, otherwise we'll have chickens crossing the road other side to get the to :P\r    static char message[500];\r      static char temp[500];\r int color1, color2;\r\r   /* parse arguments */\r  va_list ap;\r    va_start(ap, format);\r  vsnprintf(message, 500, format, ap);\r   va_end(ap);\r\r   /* search for unix-style escape sequences */\r   int t;\r int c = 0;\r     const char * p = message;\r      while (*p != 0)\r        {\r              if (*p == '\033')\r              {\r                      // Escape sequence -> copy into the temp buffer, and parse the color.\r                  p++;\r                   t = 0;\r                 while ((*p) && (*p != 'm'))\r                    {\r                              temp[t++] = *p;\r                                ++p;\r                   }\r\r                     temp[t] = 0;\r                   p++;\r\r                  if (*temp == '[')\r                      {\r                              if (sscanf(temp, "[%u;%u", &color1, &color2) == 2)\r                             {\r                                      switch(color2)\r                                 {\r                                      case 32:                // Green\r                                               SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN | FOREGROUND_INTENSITY);              // Yellow\r                                              break;\r\r                                        default:                // Unknown\r                                             // White\r                                               SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);\r                                          break;\r                                 }\r                              }\r                              else\r                           {\r                                      switch (*(temp+1))\r                                     {\r                                              case '0':\r                                                      // Returning to normal colour.\r                                                 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);\r                                                 break;\r\r                                                case '1':\r                                                      // White\r                                                       SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), TWHITE);\r                                                      break;\r\r                                                default:\r                                                       char message[50];\r                                                      sprintf(message, "Unknown color code: %s", temp);\r                                                      MessageBox(0, message, message, MB_OK);\r                                                        break;\r                                 }\r                              }\r                      }\r              }\r\r             putchar(*p);\r           ++c;\r           ++p;\r   }\r\r     return c;\r}\r\r#endif\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __COLOURS_H
+#define __COLOURS_H
+
+#define TRED FOREGROUND_RED | FOREGROUND_INTENSITY
+#define TGREEN FOREGROUND_GREEN | FOREGROUND_INTENSITY
+#define TYELLOW FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY
+#define TNORMAL FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE
+#define TWHITE TNORMAL | FOREGROUND_INTENSITY
+#define TBLUE FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_INTENSITY
+
+inline void sc(WORD color) { SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), color); }
+
+/* Handles colors in printf */
+int printf_c(const char * format, ...)
+{
+       // Better hope we're not multithreaded, otherwise we'll have chickens crossing the road other side to get the to :P
+       static char message[500];
+       static char temp[500];
+       int color1, color2;
+
+       /* parse arguments */
+       va_list ap;
+       va_start(ap, format);
+       vsnprintf(message, 500, format, ap);
+       va_end(ap);
+
+       /* search for unix-style escape sequences */
+       int t;
+       int c = 0;
+       const char * p = message;
+       while (*p != 0)
+       {
+               if (*p == '\033')
+               {
+                       // Escape sequence -> copy into the temp buffer, and parse the color.
+                       p++;
+                       t = 0;
+                       while ((*p) && (*p != 'm'))
+                       {
+                               temp[t++] = *p;
+                               ++p;
+                       }
+
+                       temp[t] = 0;
+                       p++;
+
+                       if (*temp == '[')
+                       {
+                               if (sscanf(temp, "[%u;%u", &color1, &color2) == 2)
+                               {
+                                       switch(color2)
+                                       {
+                                       case 32:                // Green
+                                               SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN | FOREGROUND_INTENSITY);              // Yellow
+                                               break;
+
+                                       default:                // Unknown
+                                               // White
+                                               SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
+                                               break;
+                                       }
+                               }
+                               else
+                               {
+                                       switch (*(temp+1))
+                                       {
+                                               case '0':
+                                                       // Returning to normal colour.
+                                                       SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
+                                                       break;
+
+                                               case '1':
+                                                       // White
+                                                       SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), TWHITE);
+                                                       break;
+
+                                               default:
+                                                       char message[50];
+                                                       sprintf(message, "Unknown color code: %s", temp);
+                                                       MessageBox(0, message, message, MB_OK);
+                                                       break;
+                                       }
+                               }
+                       }
+               }
+
+               putchar(*p);
+               ++c;
+               ++p;
+       }
+
+       return c;
+}
+
+#endif
+
index 25c9e62cf0c28bfaff93adb83f2ff6c4615f115e..adb10a6b961d6e16da64e87e936f411a5d86ce3f 100644 (file)
@@ -1 +1,509 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#define _CRT_SECURE_NO_DEPRECATE\r\r#include <windows.h>\r#include <stdio.h>\r#include <string>\r#include <time.h>\r#include "colours.h"\r\rusing namespace std;\rvoid Run();\rvoid Banner();\rvoid WriteCompileModules();\rvoid WriteCompileCommands();\r\r/* detects if we are running windows xp or higher (5.1) */\rbool iswinxp()\r{\r OSVERSIONINFO vi;\r      vi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);\r        GetVersionEx(&vi);\r     if(vi.dwMajorVersion >= 5)\r             return true;\r   \r       return false;\r}\r\rint get_int_option(const char * text, int def)\r{\r      static char buffer[500];\r       int ret;\r       printf_c("%s\n[\033[1;32m%u\033[0m] -> ", text, def);\r  fgets(buffer, 500, stdin);\r     if(sscanf(buffer, "%u", &ret) != 1)\r            ret = def;\r\r    printf("\n");\r  return ret;\r}\r\rbool get_bool_option(const char * text, bool def)\r{\r     static char buffer[500];\r       char ret[100];\r printf_c("%s [\033[1;32m%c\033[0m] -> ", text, def ? 'y' : 'n');\r       fgets(buffer, 500, stdin);\r     if(sscanf(buffer, "%s", ret) != 1)\r             strcpy(ret, def ? "y" : "n");\r\r printf("\n");\r  return !strncmp(ret, "y", 1);\r}\r\rvoid get_string_option(const char * text, char * def, char * buf)\r{\r   static char buffer[500];\r       printf_c("%s\n[\033[1;32m%s\033[0m] -> ", text, def);\r  fgets(buffer, 500, stdin);\r     if(sscanf(buffer, "%s", buf) != 1)\r             strcpy(buf, def);\r\r     printf("\n");\r}\r\r// escapes a string for use in a c++ file\rbool escape_string(char * str, size_t size)\r{\r       size_t len = strlen(str);\r      char * d_str = (char*)malloc(len * 2);\r    \r    size_t i = 0;\r  size_t j = 0;\r\r for(; i < len; ++i)\r    {\r              if(str[i] == '\\')\r             {\r                      d_str[j++] = '\\';\r                     d_str[j++] = '\\';\r             }\r              else\r           {\r                      d_str[j++] = str[i];\r           }\r      }\r\r     d_str[j++] = 0;\r\r    if(j > size)\r      {\r              free(d_str);\r           return false;\r  }\r\r     strcpy(str, d_str);\r    free(d_str);\r   return true;\r}\r\r/* gets the svn revision */\rint get_svn_revision(char * buffer, size_t len)\r{\r  /* again.. I am lazy :p cbf to pipe output of svn info to us, so i'll just read the file */\r    /*\r     8\r\r     dir\r    7033\r   */\r     char buf[1000];\r        FILE * f = fopen("..\\.svn\\entries", "r");\r    if(!f) goto bad_rev;\r    \r      if(!fgets(buf, 1000, f)) goto bad_rev;\r if(!fgets(buf, 1000, f)) goto bad_rev;\r if(!fgets(buf, 1000, f)) goto bad_rev;\r if(!fgets(buf, 1000, f)) goto bad_rev;\r int rev = atoi(buf);\r   if(rev == 0) goto bad_rev;\r     sprintf(buffer, "%u", rev);\r    fclose(f);\r     return rev;\r    \rbad_rev:\r      strcpy(buffer, "non-svn");\r     if(f) fclose(f);\r       return 0;\r}\r\rint __stdcall WinMain(IN HINSTANCE hInstance, IN HINSTANCE hPrevInstance, IN LPSTR lpCmdLine, IN int nShowCmd )\r{\r FILE * j = fopen("inspircd_config.h", "r");\r    if (j)\r {\r              if (MessageBox(0, "inspircd_config.h already exists. Remove it and build from clean?", "Configure program", MB_ICONQUESTION|MB_YESNO|MB_DEFBUTTON2) != IDYES)\r          {\r                      fclose(j);\r                     exit(0);\r               }\r      }\r\r     AllocConsole();\r\r       // pipe standard handles to this console\r       freopen("CONIN$", "r", stdin);\r freopen("CONOUT$", "w", stdout);\r       freopen("CONOUT$", "w", stderr);\r\r      Banner();\r      Run();\r WriteCompileCommands();\r        WriteCompileModules();\r FreeConsole();\r return 0;\r}\r\rvoid Banner()\r{\r   printf_c("\nWelcome to the \033[1mInspIRCd\033[0m Configuration program! (\033[1minteractive mode\033[0m)\n"\r                    "\033[1mPackage maintainers: Type ./configure --help for non-interactive help\033[0m\n\n");\r   printf_c("*** If you are unsure of any of these values, leave it blank for    ***\n"\r                    "*** standard settings that will work, and your server will run      ***\n"\r                    "*** using them. Please consult your IRC network admin if in doubt.  ***\n\n"\r                  "Press \033[1m<RETURN>\033[0m to accept the default for any option, or enter\n"\r                        "a new value. Please note: You will \033[1mHAVE\033[0m to read the docs\n"\r                     "dir, otherwise you won't have a config file!\n\n");\r\r}\r\rvoid Run()\r{\r int max_fd = 1024;\r     bool use_iocp = false;\r bool support_ip6links = false;\r char mod_path[MAX_PATH];\r       char config_file[MAX_PATH];\r    char library_dir[MAX_PATH];\r    char base_path[MAX_PATH];\r      char bin_dir[MAX_PATH];\r        char revision_text[MAX_PATH];\r\r int max_clients = 1024;\r        int nicklen = 31;\r      int chanlen = 64;\r      int modechanges = 20;\r  int identlen = 12;\r     int quitlen = 255;\r     int topiclen = 500;\r    int kicklen = 255;\r     int rllen = 128;\r       int awaylen = 200;\r     int revision = get_svn_revision(revision_text, MAX_PATH);\r      char version[514];\r\r    // grab version\r        FILE * fI = fopen("..\\src\\version.sh", "r");\r if(fI)\r {\r              fgets(version, 514, fI);\r               fgets(version, 514, fI);\r               char * p2 = version;\r           while(*p2 != '\"')\r                     ++p2;\r          ++p2;\r          strcpy(version, p2);\r           p2 = version;\r          while(*p2 != '\"')\r                     ++p2;\r          *p2 = 0;\r               fclose(fI);\r    }\r      else\r           strcpy(version, "InspIRCD-Unknown");\r#ifdef WIN64\r      printf_c("Your operating system is: \033[1;32mwindows_x64 \033[0m\n");\r#else\r   printf_c("Your operating system is: \033[1;32mwindows_x32 \033[0m\n");\r#endif\r  printf_c("InspIRCd revision ID: \033[1;32m%s \033[0m\n\n", revision ? revision_text : "(Non-SVN build)");\r\r     max_fd = get_int_option("What is the maximum file descriptor count you would like to allow?", 1024);\r\r  // detect windows\r      if(iswinxp())\r  {\r              printf_c("You are running Windows 2000 or above, and IOCP support is most likely available.\n"\r                      "This removes the socket number limitation of select and is much more efficent.\n"\r                                 "If you are unsure, answer yes.\n\n");\r\r               use_iocp = get_bool_option("Do you want to use the IOCP implementation?", true);\r       }\r\r     support_ip6links = get_bool_option("\nYou have chosen to build an \033[1;32mIPV4-only\033[0m server.\nWould you like to enable support for linking to IPV6-enabled InspIRCd servers?\nIf you are using a recent operating system and are unsure, answer yes.\nIf you answer 'no' here, your InspIRCd server will be unable\nto parse IPV6 addresses (e.g. for CIDR bans)", \r            true);\r \r       printf_c("\033[1mAll paths are relative to the binary directory.\033[0m\n");\r   get_string_option("In what directory do you wish to install the InspIRCd base?", "..", base_path);\r     get_string_option("In what directory are the configuration files?", "../conf", config_file);\r   get_string_option("In what directory are the modules to be compiled to?", "../modules", mod_path);\r     get_string_option("In what directory is the IRCd binary to be placed?", ".", bin_dir);\r get_string_option("In what directory are the IRCd libraries to be placed?", "../lib", library_dir);\r\r   printf_c("The following questions will ask you for various figures relating\n"\r         "To your IRCd install. Please note that these should usually be left\n"\r                "as defaults unless you have a real reason to change them. If they\n"\r          "changed, then the values must be identical on all servers on your\n"\r          "network, or malfunctions and/or crashes may occur, with the exception\n"\r              "of the 'maximum number of clients' setting which may be different on\n"\r               "different servers on the network.\n\n");\r\r    \r        max_clients = get_int_option("Please enter the maximum number of clients at any one time?", 1024);\r     nicklen = get_int_option("Please enter the maximum length of nicknames?", 31);\r chanlen = get_int_option("Please enter the maximum length of channel names?", 64);\r     modechanges = get_int_option("Please enter the maximum number of mode changes in one line?", 20);\r      identlen = get_int_option("Please enter the maximum length of an ident (username)?", 12);\r      quitlen = get_int_option("Please enter the maximum length of a quit message?", 255);\r   topiclen = get_int_option("Please enter the maximum length of a channel topic?", 307);\r kicklen = get_int_option("Please enter the maximum length of a kick message?", 255);\r   rllen = get_int_option("Please enter the maximum length of a GECOS (real name)?", 128);\r        awaylen = get_int_option("Please enter the maximum length of an away message?", 200);\r\r printf_c("\n\033[1;32mPre-build configuration is complete!\n\n");       sc(TNORMAL);\r\r  // dump all the options back out\r       printf_c("\033[0mBase install path:\033[1;32m        %s\n", base_path);\r        printf_c("\033[0mConfig path:\033[1;32m              %s\n", config_file);\r      printf_c("\033[0mModule path:\033[1;32m              %s\n", mod_path);\r printf_c("\033[0mLibrary path:\033[1;32m             %s\n", library_dir);\r      printf_c("\033[0mSocket Engine:\033[1;32m            %s\n", use_iocp ? "iocp" : "select");\r     printf_c("\033[0mMax file descriptors:\033[1;32m     %u\n", max_fd);\r   printf_c("\033[0mMax connections:\033[1;32m          %u\n", max_clients);\r      printf_c("\033[0mMax nickname length:\033[1;32m      %u\n", nicklen);\r  printf_c("\033[0mMax channel length:\033[1;32m       %u\n", chanlen);\r  printf_c("\033[0mMax mode length:\033[1;32m          %u\n", modechanges);\r      printf_c("\033[0mMax ident length:\033[1;32m         %u\n", identlen);\r printf_c("\033[0mMax quit length:\033[1;32m          %u\n", quitlen);\r  printf_c("\033[0mMax topic length:\033[1;32m         %u\n", topiclen);\r printf_c("\033[0mMax kick length:\033[1;32m          %u\n", kicklen);\r  printf_c("\033[0mMax name length:\033[1;32m          %u\n", rllen);\r    printf_c("\033[0mMax away length:\033[1;32m          %u\n", awaylen);\r  printf("\n"); sc(TNORMAL);\r     if(get_bool_option("Are these settings correct?", true) == false)\r      {\r              Run();\r         return;\r        }\r      printf("\n");\r\r // escape the pathes\r   escape_string(config_file, MAX_PATH);\r  escape_string(mod_path, MAX_PATH);\r     escape_string(library_dir, MAX_PATH);\r\r printf("\nWriting inspircd_config.h...");\r      FILE * f = fopen("inspircd_config.h", "w");\r    fprintf(f, "/* Auto generated by configure, do not modify! */\n");\r     fprintf(f, "#ifndef __CONFIGURATION_AUTO__\n");\r        fprintf(f, "#define __CONFIGURATION_AUTO__\n\n");\r      if(use_iocp)\r           fprintf(f, "#define CONFIG_USE_IOCP 1\n\n");\r\r  fprintf(f, "#define CONFIG_FILE \"%s/inspircd.conf\"\n", config_file);\r fprintf(f, "#define MOD_PATH \"%s\"\n", mod_path);\r     fprintf(f, "#define MAX_DESCRIPTORS %u\n", max_fd);\r    fprintf(f, "#define MAXCLIENTS %u\n", max_clients);\r    fprintf(f, "#define MAXCLIENTS_S \"%u\"\n", max_clients);\r      fprintf(f, "#define SOMAXCONN_S \"128\"\n");\r   fprintf(f, "#define NICKMAX %u\n", nicklen+1);\r fprintf(f, "#define CHANMAX %u\n", chanlen+1);\r fprintf(f, "#define MAXMODES %u\n", modechanges);\r      fprintf(f, "#define IDENTMAX %u\n", identlen);\r fprintf(f, "#define MAXQUIT %u\n", quitlen);\r   fprintf(f, "#define MAXTOPIC %u\n", topiclen);\r fprintf(f, "#define MAXKICK %u\n", kicklen);\r   fprintf(f, "#define MAXGECOS %u\n", rllen);\r    fprintf(f, "#define MAXAWAY %u\n", awaylen);\r   fprintf(f, "#define LIBRARYDIR \"%s\"\n", library_dir);\r        fprintf(f, "#define VERSION \"%s\"\n", version);\r       fprintf(f, "#define REVISION \"%s\"\n", revision_text);\r        if(support_ip6links)\r           fprintf(f, "#define SUPPORT_IP6LINKS 1\n");\r\r   OSVERSIONINFO vi;\r      vi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);\r        GetVersionEx(&vi);\r#ifdef WIN64\r        fprintf(f, "#define SYSTEM \"Windows_x64 %u.%u.%u %s\"\n", vi.dwMajorVersion, vi.dwMinorVersion, vi.dwBuildNumber, vi.szCSDVersion);\r#else\r     fprintf(f, "#define SYSTEM \"Windows_x32 %u.%u.%u %s\"\n", vi.dwMajorVersion, vi.dwMinorVersion, vi.dwBuildNumber, vi.szCSDVersion);\r#endif\r    fprintf(f, "#define MAXBUF 514\n");\r\r   fprintf(f, "\n#include \"inspircd_win32wrapper.h\"\n\n");\r      fprintf(f, "#endif\n\n");\r      fclose(f);\r\r    sc(TGREEN); printf(" done\n"); sc(TNORMAL);\r    printf("Writing inspircd_se_config.h...");\r\r    f = fopen("inspircd_se_config.h", "w");\r        fprintf(f, "/* Auto generated by configure, do not modify or commit to svn! */\n");\r    fprintf(f, "#ifndef __CONFIGURATION_SOCKETENGINE__\n");\r        fprintf(f, "#define __CONFIGURATION_SOCKETENGINE__\n\n");\r      fprintf(f, "#include \"socketengine_%s.h\"\n\n", use_iocp ? "iocp" : "select");\r        fprintf(f, "#endif\n\n");\r      fclose(f);\r\r    sc(TGREEN); printf(" done\n"); sc(TNORMAL);\r    printf("Writing command and module compilation scripts...");\r   WriteCompileCommands();\r        WriteCompileModules();\r sc(TGREEN); printf(" done\n"); sc(TNORMAL);\r\r   printf("\nconfigure is done.. exiting!\n");\r}\r\rvoid WriteCompileCommands()\r{\r   char commands[300][100];\r       int command_count = 0;\r printf("\n  Finding Command Sources...\n");\r    WIN32_FIND_DATA fd;\r    HANDLE fh = FindFirstFile("..\\src\\cmd_*.cpp", &fd);\r  if(fh == INVALID_HANDLE_VALUE)\r         printf_c("\033[1;32m  No command sources could be found! This \033[1m*could*\033[1;32m be a bad thing.. :P\033[0m");\r   else\r   {\r              sc(TGREEN);\r            do \r            {\r                      strcpy(commands[command_count], fd.cFileName);\r                 commands[command_count][strlen(fd.cFileName) - 4] = 0;\r                 printf("    %s\n", commands[command_count]);\r                   ++command_count;\r               } while(FindNextFile(fh, &fd));\r                sc(TNORMAL);\r   }\r    \r // Write our spiffy new makefile :D\r    // I am such a lazy fucker :P\r  FILE * f = fopen("..\\src\\commands.mak", "w");\r\r       time_t t = time(NULL);\r fprintf(f, "# Generated at %s\n", ctime(&t));\r  fprintf(f, "all: makedir ");\r\r  // dump modules.. first time :)\r        for(int i = 0; i < command_count; ++i)\r         fprintf(f, "%s.so ", commands[i]);\r\r    fprintf(f, "\n.cpp.obj:\n");\r#ifdef WIN64\r      // /MACHINE:X64\r        #ifdef _DEBUG\r          fprintf(f, "  cl /nologo /LD /Od /I \".\" /I \"../include\" /I \"../include/modes\" /I \"../include/commands\" /I \"../win\" /D \"WIN32\" /D \"_DEBUG\" /D \"_CONSOLE\" /D \"_MBCS\" /D \"DLL_BUILD\" /Gm /EHsc /Gm /RTC1 /MTd /Fo\"Debug/\" /Fd\"Debug/vc70.pdb\" /W2 /Wp64 /Zi /TP $*.cpp ..\\win\\inspircd_memory_functions.cpp /link ..\\bin\\debug_x64\\bin\\inspircd.lib /OUT:\"..\\bin\\debug_x64\\lib\\$*.so\" /PDB:\"..\\bin\\debug_x64\\lib\\$*.pdb\" /MACHINE:X64 /IMPLIB:\"..\\bin\\debug_x64\\lib\\$*.lib\"\n\n");\r                CreateDirectory("..\\src\\debug", NULL);\r               CreateDirectory("..\\bin\\debug\\bin", NULL);\r          CreateDirectory("..\\bin\\debug\\lib", NULL);\r          CreateDirectory("..\\bin\\debug\\modules", NULL);\r      #else\r          fprintf(f, "  cl /nologo /LD /Od /I \".\" /I \"../include\" /I \"../include/modes\" /I \"../include/commands\" /I \"../win\" /D \"WIN32\" /D \"_CONSOLE\" /D \"_MBCS\" /D \"DLL_BUILD\" /EHsc /Gm /MT /Fo\"Release/\" /Fd\"Release/vc70.pdb\" /W2 /Wp64 /Zi /TP $*.cpp ..\\win\\inspircd_memory_functions.cpp /link ..\\bin\\release_x64\\bin\\inspircd.lib /OUT:\"..\\bin\\release_x64\\lib\\$*.so\" /PDB:\"..\\bin\\release_x64\\lib\\$*.pdb\" /MACHINE:X64 /IMPLIB:\"..\\bin\\release_x64\\lib\\$*.lib\"\n\n");\r             CreateDirectory("..\\src\\release", NULL);\r             CreateDirectory("..\\bin\\release\\bin", NULL);\r                CreateDirectory("..\\bin\\release\\lib", NULL);\r                CreateDirectory("..\\bin\\release\\modules", NULL);\r    #endif\r#else\r   #ifdef _DEBUG\r          fprintf(f, "  cl /nologo /LD /Od /I \".\" /I \"../include\" /I \"../include/modes\" /I \"../include/commands\" /I \"../win\" /D \"WIN32\" /D \"_DEBUG\" /D \"_CONSOLE\" /D \"_MBCS\" /D \"DLL_BUILD\" /Gm /EHsc /Gm /RTC1 /MTd /Fo\"Debug/\" /Fd\"Debug/vc70.pdb\" /W2 /Wp64 /Zi /TP $*.cpp ..\\win\\inspircd_memory_functions.cpp /link ..\\bin\\debug\\bin\\inspircd.lib /OUT:\"..\\bin\\debug\\lib\\$*.so\" /PDB:\"..\\bin\\debug\\lib\\$*.pdb\" /IMPLIB:\"..\\bin\\debug\\lib\\$*.lib\"\n\n");\r             CreateDirectory("..\\src\\debug", NULL);\r               CreateDirectory("..\\bin\\debug\\bin", NULL);\r          CreateDirectory("..\\bin\\debug\\lib", NULL);\r          CreateDirectory("..\\bin\\debug\\modules", NULL);\r      #else\r          fprintf(f, "  cl /nologo /LD /Od /I \".\" /I \"../include\" /I \"../include/modes\" /I \"../include/commands\" /I \"../win\" /D \"WIN32\" /D \"_CONSOLE\" /D \"_MBCS\" /D \"DLL_BUILD\" /EHsc /Gm /MT /Fo\"Release/\" /Fd\"Release/vc70.pdb\" /W2 /Wp64 /Zi /TP $*.cpp ..\\win\\inspircd_memory_functions.cpp /link ..\\bin\\release\\bin\\inspircd.lib /OUT:\"..\\bin\\release\\lib\\$*.so\" /PDB:\"..\\bin\\release\\lib\\$*.pdb\" /IMPLIB:\"..\\bin\\release\\lib\\$*.lib\"\n\n");\r          CreateDirectory("..\\src\\release", NULL);\r             CreateDirectory("..\\bin\\release\\bin", NULL);\r                CreateDirectory("..\\bin\\release\\lib", NULL);\r                CreateDirectory("..\\bin\\release\\modules", NULL);\r    #endif\r#endif\r\r fprintf(f, "makedir:\n  if not exist debug mkdir debug\n\n");\r  \r       // dump modules.. again the second and last time :)\r    for(int i = 0; i < command_count; ++i)\r         fprintf(f, "%s.so : %s.obj\n", commands[i], commands[i]);\r\r     fprintf(f, "\n");\r      fclose(f);\r}\r\rvoid WriteCompileModules()\r{\r     char modules[300][100];\r        int module_count = 0;\r\r printf("Finding Modules...\n");\r        WIN32_FIND_DATA fd;\r    HANDLE fh = FindFirstFile("..\\src\\modules\\m_*.cpp", &fd);\r   if(fh == INVALID_HANDLE_VALUE)\r         printf_c("\033[1;32m  No module sources could be found! This \033[1m*could*\033[1;32m be a bad thing.. :P\033[0m");\r    else\r   {\r              sc(TGREEN);\r            do \r            {\r                      strcpy(modules[module_count], fd.cFileName);\r                   modules[module_count][strlen(fd.cFileName) - 4] = 0;\r                   printf("  %s\n", modules[module_count]);\r                       ++module_count;\r                } while(FindNextFile(fh, &fd));\r                sc(TNORMAL);\r   }\r\r     // Write our spiffy new makefile :D\r    // I am such a lazy fucker :P\r  FILE * f = fopen("..\\src\\modules\\modules.mak", "w");\r\r       time_t t = time(NULL);\r fprintf(f, "# Generated at %s\n", ctime(&t));\r  fprintf(f, "all: makedir ");\r\r  // dump modules.. first time :)\r        for(int i = 0; i < module_count; ++i)\r          fprintf(f, "%s.so ", modules[i]);\r\r     fprintf(f, "\n.cpp.obj:\n");\r#ifdef WIN64\r      // /MACHINE:X64\r        #ifdef _DEBUG\r          fprintf(f, "  cl /nologo /LD /Od /I \".\" /I \"../../include\" /I \"../../include/modes\" /I \"../../include/modules\" /I \"../../win\" /D \"WIN32\" /D \"_DEBUG\" /D \"_CONSOLE\" /D \"_MBCS\" /D \"DLL_BUILD\" /Gm /EHsc /Gm /RTC1 /MTd /Fo\"Debug/\" /Fd\"Debug/vc70.pdb\" /W2 /Wp64 /Zi /TP $*.cpp ..\\..\\win\\inspircd_memory_functions.cpp /link ..\\..\\bin\\debug_x64\\bin\\inspircd.lib ws2_32.lib /OUT:\"..\\..\\bin\\debug_x64\\modules\\$*.so\" /PDB:\"..\\..\\bin\\debug_x64\\modules\\$*.pdb\" /MACHINE:X64 /IMPLIB:\"..\\..\\bin\\debug_x64\\modules\\$*.lib\"\n\n");\r          CreateDirectory("..\\src\\modules\\debug_x64", NULL);\r  #else\r          fprintf(f, "  cl /nologo /LD /Od /I \".\" /I \"../../include\" /I \"../../include/modes\" /I \"../../include/modules\" /I \"../../win\" /D \"WIN32\" /D \"_CONSOLE\" /D \"_MBCS\" /D \"DLL_BUILD\" /EHsc /Gm /MT /Fo\"Release/\" /Fd\"Release/vc70.pdb\" /W2 /Wp64 /Zi /TP $*.cpp ..\\..\\win\\inspircd_memory_functions.cpp /link ..\\..\\bin\\release_x64\\bin\\inspircd.lib ws2_32.lib /OUT:\"..\\..\\bin\\release_x64\\modules\\$*.so\" /PDB:\"..\\..\\bin\\release_x64\\modules\\$*.pdb\" /MACHINE:X64 /IMPLIB:\"..\\..\\bin\\release_x64\\modules\\$*.lib\"\n\n");\r               CreateDirectory("..\\src\\modules\\release_x64", NULL);\r        #endif\r#else\r   #ifdef _DEBUG\r          fprintf(f, "  cl /nologo -Dssize_t=long /LD /Od /I \".\" /I \"../../include\" /I \"../../include/modes\" /I \"../../include/modules\" /I \"../../win\" /D \"WIN32\" /D \"_DEBUG\" /D \"_CONSOLE\" /D \"_MBCS\" /D \"DLL_BUILD\" /Gm /EHsc /Gm /RTC1 /MTd /Fo\"Debug/\" /Fd\"Debug/vc70.pdb\" /W2 /Wp64 /Zi /TP $*.cpp ..\\..\\win\\inspircd_memory_functions.cpp /link ..\\..\\bin\\debug\\bin\\inspircd.lib ws2_32.lib /OUT:\"..\\..\\bin\\debug\\modules\\$*.so\" /PDB:\"..\\..\\bin\\debug\\modules\\$*.pdb\" /IMPLIB:\"..\\..\\bin\\debug\\modules\\$*.lib\"\n\n");\r                CreateDirectory("..\\src\\modules\\debug", NULL);\r      #else\r          fprintf(f, "  cl /nologo -Dssize_t=long /LD /Od /I \".\" /I \"../../include\" /I \"../../include/modes\" /I \"../../include/modules\" /I \"../../win\" /D \"WIN32\" /D \"_CONSOLE\" /D \"_MBCS\" /D \"DLL_BUILD\" /EHsc /Gm /MT /Fo\"Release/\" /Fd\"Release/vc70.pdb\" /W2 /Wp64 /Zi /TP $*.cpp ..\\..\\win\\inspircd_memory_functions.cpp /link ..\\..\\bin\\release\\bin\\inspircd.lib ws2_32.lib /OUT:\"..\\..\\bin\\release\\modules\\$*.so\" /PDB:\"..\\..\\bin\\release\\modules\\$*.pdb\" /IMPLIB:\"..\\..\\bin\\release\\modules\\$*.lib\"\n\n");\r             CreateDirectory("..\\src\\modules\\release", NULL);\r    #endif\r#endif\r  \r       fprintf(f, "makedir:\n  if not exist debug mkdir debug\n\n");\r\r // dump modules.. again the second and last time :)\r    for(int i = 0; i < module_count; ++i)\r          fprintf(f, "%s.so : %s.obj\n", modules[i], modules[i]);\r\r       fprintf(f, "\n");\r      fclose(f);\r}\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#define _CRT_SECURE_NO_DEPRECATE
+
+#include <windows.h>
+#include <stdio.h>
+#include <string>
+#include <time.h>
+#include "colours.h"
+
+using namespace std;
+void Run();
+void Banner();
+void WriteCompileModules();
+void WriteCompileCommands();
+
+/* detects if we are running windows xp or higher (5.1) */
+bool iswinxp()
+{
+       OSVERSIONINFO vi;
+       vi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+       GetVersionEx(&vi);
+       if(vi.dwMajorVersion >= 5)
+               return true;
+       
+       return false;
+}
+
+int get_int_option(const char * text, int def)
+{
+       static char buffer[500];
+       int ret;
+       printf_c("%s\n[\033[1;32m%u\033[0m] -> ", text, def);
+       fgets(buffer, 500, stdin);
+       if(sscanf(buffer, "%u", &ret) != 1)
+               ret = def;
+
+       printf("\n");
+       return ret;
+}
+
+bool get_bool_option(const char * text, bool def)
+{
+       static char buffer[500];
+       char ret[100];
+       printf_c("%s [\033[1;32m%c\033[0m] -> ", text, def ? 'y' : 'n');
+       fgets(buffer, 500, stdin);
+       if(sscanf(buffer, "%s", ret) != 1)
+               strcpy(ret, def ? "y" : "n");
+
+       printf("\n");
+       return !strncmp(ret, "y", 1);
+}
+
+void get_string_option(const char * text, char * def, char * buf)
+{
+       static char buffer[500];
+       printf_c("%s\n[\033[1;32m%s\033[0m] -> ", text, def);
+       fgets(buffer, 500, stdin);
+       if(sscanf(buffer, "%s", buf) != 1)
+               strcpy(buf, def);
+
+       printf("\n");
+}
+
+// escapes a string for use in a c++ file
+bool escape_string(char * str, size_t size)
+{
+       size_t len = strlen(str);
+       char * d_str = (char*)malloc(len * 2);
+    
+       size_t i = 0;
+       size_t j = 0;
+
+       for(; i < len; ++i)
+       {
+               if(str[i] == '\\')
+               {
+                       d_str[j++] = '\\';
+                       d_str[j++] = '\\';
+               }
+               else
+               {
+                       d_str[j++] = str[i];
+               }
+       }
+
+       d_str[j++] = 0;
+
+    if(j > size)
+       {
+               free(d_str);
+               return false;
+       }
+
+       strcpy(str, d_str);
+       free(d_str);
+       return true;
+}
+
+/* gets the svn revision */
+int get_svn_revision(char * buffer, size_t len)
+{
+       /* again.. I am lazy :p cbf to pipe output of svn info to us, so i'll just read the file */
+       /*
+       8
+
+       dir
+       7033
+       */
+       char buf[1000];
+       FILE * f = fopen("..\\.svn\\entries", "r");
+       if(!f) goto bad_rev;
+    
+       if(!fgets(buf, 1000, f)) goto bad_rev;
+       if(!fgets(buf, 1000, f)) goto bad_rev;
+       if(!fgets(buf, 1000, f)) goto bad_rev;
+       if(!fgets(buf, 1000, f)) goto bad_rev;
+       int rev = atoi(buf);
+       if(rev == 0) goto bad_rev;
+       sprintf(buffer, "%u", rev);
+       fclose(f);
+       return rev;
+       
+bad_rev:
+       strcpy(buffer, "non-svn");
+       if(f) fclose(f);
+       return 0;
+}
+
+int __stdcall WinMain(IN HINSTANCE hInstance, IN HINSTANCE hPrevInstance, IN LPSTR lpCmdLine, IN int nShowCmd )
+{
+       FILE * j = fopen("inspircd_config.h", "r");
+       if (j)
+       {
+               if (MessageBox(0, "inspircd_config.h already exists. Remove it and build from clean?", "Configure program", MB_ICONQUESTION|MB_YESNO|MB_DEFBUTTON2) != IDYES)
+               {
+                       fclose(j);
+                       exit(0);
+               }
+       }
+
+       AllocConsole();
+
+       // pipe standard handles to this console
+       freopen("CONIN$", "r", stdin);
+       freopen("CONOUT$", "w", stdout);
+       freopen("CONOUT$", "w", stderr);
+
+       Banner();
+       Run();
+       WriteCompileCommands();
+       WriteCompileModules();
+       FreeConsole();
+       return 0;
+}
+
+void Banner()
+{
+       printf_c("\nWelcome to the \033[1mInspIRCd\033[0m Configuration program! (\033[1minteractive mode\033[0m)\n"
+                        "\033[1mPackage maintainers: Type ./configure --help for non-interactive help\033[0m\n\n");
+       printf_c("*** If you are unsure of any of these values, leave it blank for    ***\n"
+                        "*** standard settings that will work, and your server will run      ***\n"
+                        "*** using them. Please consult your IRC network admin if in doubt.  ***\n\n"
+                        "Press \033[1m<RETURN>\033[0m to accept the default for any option, or enter\n"
+                        "a new value. Please note: You will \033[1mHAVE\033[0m to read the docs\n"
+                        "dir, otherwise you won't have a config file!\n\n");
+
+}
+
+void Run()
+{
+       int max_fd = 1024;
+       bool use_iocp = false;
+       bool support_ip6links = false;
+       char mod_path[MAX_PATH];
+       char config_file[MAX_PATH];
+       char library_dir[MAX_PATH];
+       char base_path[MAX_PATH];
+       char bin_dir[MAX_PATH];
+       char revision_text[MAX_PATH];
+
+       int max_clients = 1024;
+       int nicklen = 31;
+       int chanlen = 64;
+       int modechanges = 20;
+       int identlen = 12;
+       int quitlen = 255;
+       int topiclen = 500;
+       int kicklen = 255;
+       int rllen = 128;
+       int awaylen = 200;
+       int revision = get_svn_revision(revision_text, MAX_PATH);
+       char version[514];
+
+       // grab version
+       FILE * fI = fopen("..\\src\\version.sh", "r");
+       if(fI)
+       {
+               fgets(version, 514, fI);
+               fgets(version, 514, fI);
+               char * p2 = version;
+               while(*p2 != '\"')
+                       ++p2;
+               ++p2;
+               strcpy(version, p2);
+               p2 = version;
+               while(*p2 != '\"')
+                       ++p2;
+               *p2 = 0;
+               fclose(fI);
+       }
+       else
+               strcpy(version, "InspIRCD-Unknown");
+#ifdef WIN64
+       printf_c("Your operating system is: \033[1;32mwindows_x64 \033[0m\n");
+#else
+       printf_c("Your operating system is: \033[1;32mwindows_x32 \033[0m\n");
+#endif
+       printf_c("InspIRCd revision ID: \033[1;32m%s \033[0m\n\n", revision ? revision_text : "(Non-SVN build)");
+
+       max_fd = get_int_option("What is the maximum file descriptor count you would like to allow?", 1024);
+
+       // detect windows
+       if(iswinxp())
+       {
+               printf_c("You are running Windows 2000 or above, and IOCP support is most likely available.\n"
+                            "This removes the socket number limitation of select and is much more efficent.\n"
+                                "If you are unsure, answer yes.\n\n");
+
+               use_iocp = get_bool_option("Do you want to use the IOCP implementation?", true);
+       }
+
+       support_ip6links = get_bool_option("\nYou have chosen to build an \033[1;32mIPV4-only\033[0m server.\nWould you like to enable support for linking to IPV6-enabled InspIRCd servers?\nIf you are using a recent operating system and are unsure, answer yes.\nIf you answer 'no' here, your InspIRCd server will be unable\nto parse IPV6 addresses (e.g. for CIDR bans)", 
+               true);
+       
+       printf_c("\033[1mAll paths are relative to the binary directory.\033[0m\n");
+       get_string_option("In what directory do you wish to install the InspIRCd base?", "..", base_path);
+       get_string_option("In what directory are the configuration files?", "../conf", config_file);
+       get_string_option("In what directory are the modules to be compiled to?", "../modules", mod_path);
+       get_string_option("In what directory is the IRCd binary to be placed?", ".", bin_dir);
+       get_string_option("In what directory are the IRCd libraries to be placed?", "../lib", library_dir);
+
+       printf_c("The following questions will ask you for various figures relating\n"
+               "To your IRCd install. Please note that these should usually be left\n"
+               "as defaults unless you have a real reason to change them. If they\n"
+               "changed, then the values must be identical on all servers on your\n"
+               "network, or malfunctions and/or crashes may occur, with the exception\n"
+               "of the 'maximum number of clients' setting which may be different on\n"
+               "different servers on the network.\n\n");
+
+    
+       max_clients = get_int_option("Please enter the maximum number of clients at any one time?", 1024);
+       nicklen = get_int_option("Please enter the maximum length of nicknames?", 31);
+       chanlen = get_int_option("Please enter the maximum length of channel names?", 64);
+       modechanges = get_int_option("Please enter the maximum number of mode changes in one line?", 20);
+       identlen = get_int_option("Please enter the maximum length of an ident (username)?", 12);
+       quitlen = get_int_option("Please enter the maximum length of a quit message?", 255);
+       topiclen = get_int_option("Please enter the maximum length of a channel topic?", 307);
+       kicklen = get_int_option("Please enter the maximum length of a kick message?", 255);
+       rllen = get_int_option("Please enter the maximum length of a GECOS (real name)?", 128);
+       awaylen = get_int_option("Please enter the maximum length of an away message?", 200);
+
+       printf_c("\n\033[1;32mPre-build configuration is complete!\n\n");       sc(TNORMAL);
+
+       // dump all the options back out
+       printf_c("\033[0mBase install path:\033[1;32m        %s\n", base_path);
+       printf_c("\033[0mConfig path:\033[1;32m              %s\n", config_file);
+       printf_c("\033[0mModule path:\033[1;32m              %s\n", mod_path);
+       printf_c("\033[0mLibrary path:\033[1;32m             %s\n", library_dir);
+       printf_c("\033[0mSocket Engine:\033[1;32m            %s\n", use_iocp ? "iocp" : "select");
+       printf_c("\033[0mMax file descriptors:\033[1;32m     %u\n", max_fd);
+       printf_c("\033[0mMax connections:\033[1;32m          %u\n", max_clients);
+       printf_c("\033[0mMax nickname length:\033[1;32m      %u\n", nicklen);
+       printf_c("\033[0mMax channel length:\033[1;32m       %u\n", chanlen);
+       printf_c("\033[0mMax mode length:\033[1;32m          %u\n", modechanges);
+       printf_c("\033[0mMax ident length:\033[1;32m         %u\n", identlen);
+       printf_c("\033[0mMax quit length:\033[1;32m          %u\n", quitlen);
+       printf_c("\033[0mMax topic length:\033[1;32m         %u\n", topiclen);
+       printf_c("\033[0mMax kick length:\033[1;32m          %u\n", kicklen);
+       printf_c("\033[0mMax name length:\033[1;32m          %u\n", rllen);
+       printf_c("\033[0mMax away length:\033[1;32m          %u\n", awaylen);
+       printf("\n"); sc(TNORMAL);
+       if(get_bool_option("Are these settings correct?", true) == false)
+       {
+               Run();
+               return;
+       }
+       printf("\n");
+
+       // escape the pathes
+       escape_string(config_file, MAX_PATH);
+       escape_string(mod_path, MAX_PATH);
+       escape_string(library_dir, MAX_PATH);
+
+       printf("\nWriting inspircd_config.h...");
+       FILE * f = fopen("inspircd_config.h", "w");
+       fprintf(f, "/* Auto generated by configure, do not modify! */\n");
+       fprintf(f, "#ifndef __CONFIGURATION_AUTO__\n");
+       fprintf(f, "#define __CONFIGURATION_AUTO__\n\n");
+       if(use_iocp)
+               fprintf(f, "#define CONFIG_USE_IOCP 1\n\n");
+
+       fprintf(f, "#define CONFIG_FILE \"%s/inspircd.conf\"\n", config_file);
+       fprintf(f, "#define MOD_PATH \"%s\"\n", mod_path);
+       fprintf(f, "#define MAX_DESCRIPTORS %u\n", max_fd);
+       fprintf(f, "#define MAXCLIENTS %u\n", max_clients);
+       fprintf(f, "#define MAXCLIENTS_S \"%u\"\n", max_clients);
+       fprintf(f, "#define SOMAXCONN_S \"128\"\n");
+       fprintf(f, "#define NICKMAX %u\n", nicklen+1);
+       fprintf(f, "#define CHANMAX %u\n", chanlen+1);
+       fprintf(f, "#define MAXMODES %u\n", modechanges);
+       fprintf(f, "#define IDENTMAX %u\n", identlen);
+       fprintf(f, "#define MAXQUIT %u\n", quitlen);
+       fprintf(f, "#define MAXTOPIC %u\n", topiclen);
+       fprintf(f, "#define MAXKICK %u\n", kicklen);
+       fprintf(f, "#define MAXGECOS %u\n", rllen);
+       fprintf(f, "#define MAXAWAY %u\n", awaylen);
+       fprintf(f, "#define LIBRARYDIR \"%s\"\n", library_dir);
+       fprintf(f, "#define VERSION \"%s\"\n", version);
+       fprintf(f, "#define REVISION \"%s\"\n", revision_text);
+       if(support_ip6links)
+               fprintf(f, "#define SUPPORT_IP6LINKS 1\n");
+
+       OSVERSIONINFO vi;
+       vi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+       GetVersionEx(&vi);
+#ifdef WIN64
+       fprintf(f, "#define SYSTEM \"Windows_x64 %u.%u.%u %s\"\n", vi.dwMajorVersion, vi.dwMinorVersion, vi.dwBuildNumber, vi.szCSDVersion);
+#else
+       fprintf(f, "#define SYSTEM \"Windows_x32 %u.%u.%u %s\"\n", vi.dwMajorVersion, vi.dwMinorVersion, vi.dwBuildNumber, vi.szCSDVersion);
+#endif
+       fprintf(f, "#define MAXBUF 514\n");
+
+       fprintf(f, "\n#include \"inspircd_win32wrapper.h\"\n\n");
+       fprintf(f, "#endif\n\n");
+       fclose(f);
+
+       sc(TGREEN); printf(" done\n"); sc(TNORMAL);
+       printf("Writing inspircd_se_config.h...");
+
+       f = fopen("inspircd_se_config.h", "w");
+       fprintf(f, "/* Auto generated by configure, do not modify or commit to svn! */\n");
+       fprintf(f, "#ifndef __CONFIGURATION_SOCKETENGINE__\n");
+       fprintf(f, "#define __CONFIGURATION_SOCKETENGINE__\n\n");
+       fprintf(f, "#include \"socketengine_%s.h\"\n\n", use_iocp ? "iocp" : "select");
+       fprintf(f, "#endif\n\n");
+       fclose(f);
+
+       sc(TGREEN); printf(" done\n"); sc(TNORMAL);
+       printf("Writing command and module compilation scripts...");
+       WriteCompileCommands();
+       WriteCompileModules();
+       sc(TGREEN); printf(" done\n"); sc(TNORMAL);
+
+       printf("\nconfigure is done.. exiting!\n");
+}
+
+void WriteCompileCommands()
+{
+       char commands[300][100];
+       int command_count = 0;
+       printf("\n  Finding Command Sources...\n");
+       WIN32_FIND_DATA fd;
+       HANDLE fh = FindFirstFile("..\\src\\cmd_*.cpp", &fd);
+       if(fh == INVALID_HANDLE_VALUE)
+               printf_c("\033[1;32m  No command sources could be found! This \033[1m*could*\033[1;32m be a bad thing.. :P\033[0m");
+       else
+       {
+               sc(TGREEN);
+               do 
+               {
+                       strcpy(commands[command_count], fd.cFileName);
+                       commands[command_count][strlen(fd.cFileName) - 4] = 0;
+                       printf("    %s\n", commands[command_count]);
+                       ++command_count;
+               } while(FindNextFile(fh, &fd));
+               sc(TNORMAL);
+       }
+    
+       // Write our spiffy new makefile :D
+       // I am such a lazy fucker :P
+       FILE * f = fopen("..\\src\\commands.mak", "w");
+
+       time_t t = time(NULL);
+       fprintf(f, "# Generated at %s\n", ctime(&t));
+       fprintf(f, "all: makedir ");
+
+       // dump modules.. first time :)
+       for(int i = 0; i < command_count; ++i)
+               fprintf(f, "%s.so ", commands[i]);
+
+       fprintf(f, "\n.cpp.obj:\n");
+#ifdef WIN64
+       // /MACHINE:X64
+       #ifdef _DEBUG
+               fprintf(f, "  cl /nologo /LD /Od /I \".\" /I \"../include\" /I \"../include/modes\" /I \"../include/commands\" /I \"../win\" /D \"WIN32\" /D \"_DEBUG\" /D \"_CONSOLE\" /D \"_MBCS\" /D \"DLL_BUILD\" /Gm /EHsc /Gm /RTC1 /MTd /Fo\"Debug/\" /Fd\"Debug/vc70.pdb\" /W2 /Wp64 /Zi /TP $*.cpp ..\\win\\inspircd_memory_functions.cpp /link ..\\bin\\debug_x64\\bin\\inspircd.lib /OUT:\"..\\bin\\debug_x64\\lib\\$*.so\" /PDB:\"..\\bin\\debug_x64\\lib\\$*.pdb\" /MACHINE:X64 /IMPLIB:\"..\\bin\\debug_x64\\lib\\$*.lib\"\n\n");
+               CreateDirectory("..\\src\\debug", NULL);
+               CreateDirectory("..\\bin\\debug\\bin", NULL);
+               CreateDirectory("..\\bin\\debug\\lib", NULL);
+               CreateDirectory("..\\bin\\debug\\modules", NULL);
+       #else
+               fprintf(f, "  cl /nologo /LD /Od /I \".\" /I \"../include\" /I \"../include/modes\" /I \"../include/commands\" /I \"../win\" /D \"WIN32\" /D \"_CONSOLE\" /D \"_MBCS\" /D \"DLL_BUILD\" /EHsc /Gm /MT /Fo\"Release/\" /Fd\"Release/vc70.pdb\" /W2 /Wp64 /Zi /TP $*.cpp ..\\win\\inspircd_memory_functions.cpp /link ..\\bin\\release_x64\\bin\\inspircd.lib /OUT:\"..\\bin\\release_x64\\lib\\$*.so\" /PDB:\"..\\bin\\release_x64\\lib\\$*.pdb\" /MACHINE:X64 /IMPLIB:\"..\\bin\\release_x64\\lib\\$*.lib\"\n\n");
+               CreateDirectory("..\\src\\release", NULL);
+               CreateDirectory("..\\bin\\release\\bin", NULL);
+               CreateDirectory("..\\bin\\release\\lib", NULL);
+               CreateDirectory("..\\bin\\release\\modules", NULL);
+       #endif
+#else
+       #ifdef _DEBUG
+               fprintf(f, "  cl /nologo /LD /Od /I \".\" /I \"../include\" /I \"../include/modes\" /I \"../include/commands\" /I \"../win\" /D \"WIN32\" /D \"_DEBUG\" /D \"_CONSOLE\" /D \"_MBCS\" /D \"DLL_BUILD\" /Gm /EHsc /Gm /RTC1 /MTd /Fo\"Debug/\" /Fd\"Debug/vc70.pdb\" /W2 /Wp64 /Zi /TP $*.cpp ..\\win\\inspircd_memory_functions.cpp /link ..\\bin\\debug\\bin\\inspircd.lib /OUT:\"..\\bin\\debug\\lib\\$*.so\" /PDB:\"..\\bin\\debug\\lib\\$*.pdb\" /IMPLIB:\"..\\bin\\debug\\lib\\$*.lib\"\n\n");
+               CreateDirectory("..\\src\\debug", NULL);
+               CreateDirectory("..\\bin\\debug\\bin", NULL);
+               CreateDirectory("..\\bin\\debug\\lib", NULL);
+               CreateDirectory("..\\bin\\debug\\modules", NULL);
+       #else
+               fprintf(f, "  cl /nologo /LD /Od /I \".\" /I \"../include\" /I \"../include/modes\" /I \"../include/commands\" /I \"../win\" /D \"WIN32\" /D \"_CONSOLE\" /D \"_MBCS\" /D \"DLL_BUILD\" /EHsc /Gm /MT /Fo\"Release/\" /Fd\"Release/vc70.pdb\" /W2 /Wp64 /Zi /TP $*.cpp ..\\win\\inspircd_memory_functions.cpp /link ..\\bin\\release\\bin\\inspircd.lib /OUT:\"..\\bin\\release\\lib\\$*.so\" /PDB:\"..\\bin\\release\\lib\\$*.pdb\" /IMPLIB:\"..\\bin\\release\\lib\\$*.lib\"\n\n");
+               CreateDirectory("..\\src\\release", NULL);
+               CreateDirectory("..\\bin\\release\\bin", NULL);
+               CreateDirectory("..\\bin\\release\\lib", NULL);
+               CreateDirectory("..\\bin\\release\\modules", NULL);
+       #endif
+#endif
+
+       fprintf(f, "makedir:\n  if not exist debug mkdir debug\n\n");
+       
+       // dump modules.. again the second and last time :)
+       for(int i = 0; i < command_count; ++i)
+               fprintf(f, "%s.so : %s.obj\n", commands[i], commands[i]);
+
+       fprintf(f, "\n");
+       fclose(f);
+}
+
+void WriteCompileModules()
+{
+       char modules[300][100];
+       int module_count = 0;
+
+       printf("Finding Modules...\n");
+       WIN32_FIND_DATA fd;
+       HANDLE fh = FindFirstFile("..\\src\\modules\\m_*.cpp", &fd);
+       if(fh == INVALID_HANDLE_VALUE)
+               printf_c("\033[1;32m  No module sources could be found! This \033[1m*could*\033[1;32m be a bad thing.. :P\033[0m");
+       else
+       {
+               sc(TGREEN);
+               do 
+               {
+                       strcpy(modules[module_count], fd.cFileName);
+                       modules[module_count][strlen(fd.cFileName) - 4] = 0;
+                       printf("  %s\n", modules[module_count]);
+                       ++module_count;
+               } while(FindNextFile(fh, &fd));
+               sc(TNORMAL);
+       }
+
+       // Write our spiffy new makefile :D
+       // I am such a lazy fucker :P
+       FILE * f = fopen("..\\src\\modules\\modules.mak", "w");
+
+       time_t t = time(NULL);
+       fprintf(f, "# Generated at %s\n", ctime(&t));
+       fprintf(f, "all: makedir ");
+
+       // dump modules.. first time :)
+       for(int i = 0; i < module_count; ++i)
+               fprintf(f, "%s.so ", modules[i]);
+
+       fprintf(f, "\n.cpp.obj:\n");
+#ifdef WIN64
+       // /MACHINE:X64
+       #ifdef _DEBUG
+               fprintf(f, "  cl /nologo /LD /Od /I \".\" /I \"../../include\" /I \"../../include/modes\" /I \"../../include/modules\" /I \"../../win\" /D \"WIN32\" /D \"_DEBUG\" /D \"_CONSOLE\" /D \"_MBCS\" /D \"DLL_BUILD\" /Gm /EHsc /Gm /RTC1 /MTd /Fo\"Debug/\" /Fd\"Debug/vc70.pdb\" /W2 /Wp64 /Zi /TP $*.cpp ..\\..\\win\\inspircd_memory_functions.cpp /link ..\\..\\bin\\debug_x64\\bin\\inspircd.lib ws2_32.lib /OUT:\"..\\..\\bin\\debug_x64\\modules\\$*.so\" /PDB:\"..\\..\\bin\\debug_x64\\modules\\$*.pdb\" /MACHINE:X64 /IMPLIB:\"..\\..\\bin\\debug_x64\\modules\\$*.lib\"\n\n");
+               CreateDirectory("..\\src\\modules\\debug_x64", NULL);
+       #else
+               fprintf(f, "  cl /nologo /LD /Od /I \".\" /I \"../../include\" /I \"../../include/modes\" /I \"../../include/modules\" /I \"../../win\" /D \"WIN32\" /D \"_CONSOLE\" /D \"_MBCS\" /D \"DLL_BUILD\" /EHsc /Gm /MT /Fo\"Release/\" /Fd\"Release/vc70.pdb\" /W2 /Wp64 /Zi /TP $*.cpp ..\\..\\win\\inspircd_memory_functions.cpp /link ..\\..\\bin\\release_x64\\bin\\inspircd.lib ws2_32.lib /OUT:\"..\\..\\bin\\release_x64\\modules\\$*.so\" /PDB:\"..\\..\\bin\\release_x64\\modules\\$*.pdb\" /MACHINE:X64 /IMPLIB:\"..\\..\\bin\\release_x64\\modules\\$*.lib\"\n\n");
+               CreateDirectory("..\\src\\modules\\release_x64", NULL);
+       #endif
+#else
+       #ifdef _DEBUG
+               fprintf(f, "  cl /nologo -Dssize_t=long /LD /Od /I \".\" /I \"../../include\" /I \"../../include/modes\" /I \"../../include/modules\" /I \"../../win\" /D \"WIN32\" /D \"_DEBUG\" /D \"_CONSOLE\" /D \"_MBCS\" /D \"DLL_BUILD\" /Gm /EHsc /Gm /RTC1 /MTd /Fo\"Debug/\" /Fd\"Debug/vc70.pdb\" /W2 /Wp64 /Zi /TP $*.cpp ..\\..\\win\\inspircd_memory_functions.cpp /link ..\\..\\bin\\debug\\bin\\inspircd.lib ws2_32.lib /OUT:\"..\\..\\bin\\debug\\modules\\$*.so\" /PDB:\"..\\..\\bin\\debug\\modules\\$*.pdb\" /IMPLIB:\"..\\..\\bin\\debug\\modules\\$*.lib\"\n\n");
+               CreateDirectory("..\\src\\modules\\debug", NULL);
+       #else
+               fprintf(f, "  cl /nologo -Dssize_t=long /LD /Od /I \".\" /I \"../../include\" /I \"../../include/modes\" /I \"../../include/modules\" /I \"../../win\" /D \"WIN32\" /D \"_CONSOLE\" /D \"_MBCS\" /D \"DLL_BUILD\" /EHsc /Gm /MT /Fo\"Release/\" /Fd\"Release/vc70.pdb\" /W2 /Wp64 /Zi /TP $*.cpp ..\\..\\win\\inspircd_memory_functions.cpp /link ..\\..\\bin\\release\\bin\\inspircd.lib ws2_32.lib /OUT:\"..\\..\\bin\\release\\modules\\$*.so\" /PDB:\"..\\..\\bin\\release\\modules\\$*.pdb\" /IMPLIB:\"..\\..\\bin\\release\\modules\\$*.lib\"\n\n");
+               CreateDirectory("..\\src\\modules\\release", NULL);
+       #endif
+#endif
+       
+       fprintf(f, "makedir:\n  if not exist debug mkdir debug\n\n");
+
+       // dump modules.. again the second and last time :)
+       for(int i = 0; i < module_count; ++i)
+               fprintf(f, "%s.so : %s.obj\n", modules[i], modules[i]);
+
+       fprintf(f, "\n");
+       fclose(f);
+}
index 092fae309bd879e77a4ef4739b4f3bae2d88c780..96b2e498ed4f9f51a3bff6b48bddf6865455b4ad 100644 (file)
@@ -1 +1,272 @@
-; *       +------------------------------------+\r; *       | Inspire Internet Relay Chat Daemon |\r; *       +------------------------------------+\r; *\r; *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r; * See: http://www.inspircd.org/wiki/index.php/Credits\r; *\r; * This program is free but copyrighted software; see\r; *            the file COPYING for details.\r; *\r; * ---------------------------------------------------\r\r;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\r\r                       ;;;; SET THE BUILD TO BE PACKAGED HERE ;;;;\r\r!define BUILD "release"\r\r;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\r\r; HM NIS Edit Wizard helper defines\r!define PRODUCT_NAME "InspIRCd"\r!define PRODUCT_VERSION "1.1"\r!define PRODUCT_PUBLISHER "InspIRCd Development Team"\r!define PRODUCT_WEB_SITE "http://www.inspircd.org/"\r!define PRODUCT_DIR_REGKEY "Software\Microsoft\Windows\CurrentVersion\App Paths\inspircd.exe"\r!define PRODUCT_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}"\r!define PRODUCT_UNINST_ROOT_KEY "HKLM"\r!define DOT_MAJOR "2"\r!define DOT_MINOR "0"\r\rSetCompressor bzip2\r\r; MUI 1.67 compatible ------\r!include "MUI.nsh"\r\r; MUI Settings\r!define MUI_ABORTWARNING\r!define MUI_ICON "inspircd.ico"\r!define MUI_UNICON "inspircd.ico"\r\r; Welcome page\r!insertmacro MUI_PAGE_WELCOME\r; License page\r!define MUI_LICENSEPAGE_CHECKBOX\r!insertmacro MUI_PAGE_LICENSE "..\docs\COPYING"\r; directory page\rPage directory\r; Components page\r!insertmacro MUI_PAGE_COMPONENTS\r; Instfiles page\r!insertmacro MUI_PAGE_INSTFILES\r; Finish page\r!define MUI_FINISHPAGE_RUN "$INSTDIR\InspGUI.exe"\r!insertmacro MUI_PAGE_FINISH\r\r; Uninstaller pages\r!insertmacro MUI_UNPAGE_INSTFILES\r\r; Language files\r!insertmacro MUI_LANGUAGE "English"\r\r; Reserve files\r!insertmacro MUI_RESERVEFILE_INSTALLOPTIONS\r\r; MUI end ------\r\rName "${PRODUCT_NAME} ${PRODUCT_VERSION}"\rOutFile "Setup.exe"\rInstallDir "$PROGRAMFILES\InspIRCd"\rInstallDirRegKey HKLM "${PRODUCT_DIR_REGKEY}" ""\rShowInstDetails show\rShowUnInstDetails show\r\rFunction IsDotNetInstalled\r \r  StrCpy $0 "0"\r  StrCpy $1 "SOFTWARE\Microsoft\.NETFramework" ;registry entry to look in.\r  StrCpy $2 0\r \r  StartEnum:\r    ;Enumerate the versions installed.\r    EnumRegKey $3 HKLM "$1\policy" $2\r    \r    ;If we don't find any versions installed, it's not here.\r    StrCmp $3 "" noDotNet notEmpty\r    \r    ;We found something.\r    notEmpty:\r      ;Find out if the RegKey starts with 'v'.  \r      ;If it doesn't, goto the next key.\r      StrCpy $4 $3 1 0\r      StrCmp $4 "v" +1 goNext\r      StrCpy $4 $3 1 1\r      \r      ;It starts with 'v'.  Now check to see how the installed major version\r      ;relates to our required major version.\r      ;If it's equal check the minor version, if it's greater, \r      ;we found a good RegKey.\r      IntCmp $4 ${DOT_MAJOR} +1 goNext yesDotNetReg\r      ;Check the minor version.  If it's equal or greater to our requested \r      ;version then we're good.\r      StrCpy $4 $3 1 3\r      IntCmp $4 ${DOT_MINOR} yesDotNetReg goNext yesDotNetReg\r \r    goNext:\r      ;Go to the next RegKey.\r      IntOp $2 $2 + 1\r      goto StartEnum\r \r  yesDotNetReg:\r    ;Now that we've found a good RegKey, let's make sure it's actually\r    ;installed by getting the install path and checking to see if the \r    ;mscorlib.dll exists.\r    EnumRegValue $2 HKLM "$1\policy\$3" 0\r    ;$2 should equal whatever comes after the major and minor versions \r    ;(ie, v1.1.4322)\r    StrCmp $2 "" noDotNet\r    ReadRegStr $4 HKLM $1 "InstallRoot"\r    ;Hopefully the install root isn't empty.\r    StrCmp $4 "" noDotNet\r    ;build the actuall directory path to mscorlib.dll.\r    StrCpy $4 "$4$3.$2\mscorlib.dll"\r    IfFileExists $4 yesDotNet noDotNet\r \r  noDotNet:\r    MessageBox MB_OK "You do not have have v${DOT_MAJOR}.${DOT_MINOR} or greater of the .NET framework installed. This is required for the InspIRCd Monitor, however you can still launch the IRCd manually."\r \r  yesDotNet:\r    ;Everything checks out.  Go on with the rest of the installation.\r    \rFunctionEnd\r\rSection "Binary Executable" SEC01\r  Call IsDotNetInstalled\r  SetOutPath "$INSTDIR"\r  SetOverwrite ifnewer\r  File "..\bin\${BUILD}\InspGUI.exe"\r  CreateDirectory "$SMPROGRAMS\InspIRCd"\r  CreateShortCut "$SMPROGRAMS\InspIRCd\InspIRCd.lnk" "$INSTDIR\InspGUI.exe"\r  SetOutPath "$INSTDIR\bin"\r  SetOverwrite ifnewer\r  File "..\bin\${BUILD}\bin\inspircd.exe"\rSectionEnd\r\rSection "Config Files" SEC02\r  SetOutPath "$INSTDIR\conf"\r  File "..\conf\inspircd.motd.example"\r  File "..\conf\inspircd.helpop-full.example"\r  File "..\conf\inspircd.helpop.example"\r  File "..\conf\inspircd.filter.example"\r  File "..\docs\inspircd.conf.example"\r  File "..\conf\inspircd.censor.example"\r  File "..\conf\inspircd.rules.example"\r  File "..\conf\inspircd.quotes.example"\rSectionEnd\r\rSection "Command Handlers" SEC03\r  SetOutPath "$INSTDIR\lib"\r  File "..\bin\${BUILD}\lib\cmd_*.so"\rSectionEnd\r\rSection "Modules" SEC04\r  SetOutPath "$INSTDIR\modules"\r  File "..\bin\${BUILD}\modules\m_*.so"\rSectionEnd\r\rSection  "SSL Modules" SEC05\r  SetOutPath "$INSTDIR\bin"\r  SetOverwrite ifnewer\r  File "..\bin\${BUILD}\bin\libgcrypt-11.dll"\r  File "..\bin\${BUILD}\bin\libgnutls-13.dll"\r  File "..\bin\${BUILD}\bin\libgnutls-extra-13.dll"\r  File "..\bin\${BUILD}\bin\libgnutls-openssl-13.dll"\r  File "..\bin\${BUILD}\bin\libgpg-error-0.dll"\r  File "..\bin\${BUILD}\bin\libopencdk-8.dll"\r  File "..\bin\${BUILD}\bin\libtasn1-3.dll"\r  SetOutPath "$INSTDIR\modules"\r  File "d:\temp\m_ssl_gnutls.so"\r  File "d:\temp\m_sslinfo.so"\r  File "d:\temp\m_ssl_oper_cert.so"\r  SetOutPath "$INSTDIR\conf"\r  SetOverwrite off\r  File "key.pem"\r  File "cert.pem"\rSectionEnd\r\rSection  "Regexp Modules" SEC06\r  SetOutPath "$INSTDIR\bin"\r  SetOverwrite ifnewer\r  File "..\bin\${BUILD}\bin\pcre.dll"\r  SetOutPath "$INSTDIR\modules"\r  File "d:\temp\m_filter_pcre.so"\rSectionEnd\r\rSection -AdditionalIcons\r  SetOutPath $INSTDIR\r  WriteIniStr "$INSTDIR\${PRODUCT_NAME}.url" "InternetShortcut" "URL" "${PRODUCT_WEB_SITE}"\r  CreateShortCut "$SMPROGRAMS\InspIRCd\InspIRCd Website.lnk" "$INSTDIR\${PRODUCT_NAME}.url"\r  CreateShortCut "$SMPROGRAMS\InspIRCd\Uninstall.lnk" "$INSTDIR\uninst.exe"\rSectionEnd\r\rSection -Post\r  WriteUninstaller "$INSTDIR\uninst.exe"\r  WriteRegStr HKLM "${PRODUCT_DIR_REGKEY}" "" "$INSTDIR\bin\inspircd.exe"\r  WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayName" "$(^Name)"\r  WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "UninstallString" "$INSTDIR\uninst.exe"\r  WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayIcon" "$INSTDIR\bin\inspircd.exe"\r  WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayVersion" "${PRODUCT_VERSION}"\r  WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "URLInfoAbout" "${PRODUCT_WEB_SITE}"\r  WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "Publisher" "${PRODUCT_PUBLISHER}"\r  MessageBox MB_ICONINFORMATION|MB_OK "InspIRCd was successfully installed. Remember to edit your configuration file in $INSTDIR\conf!"\rSectionEnd\r\r; Section descriptions\r!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN\r  !insertmacro MUI_DESCRIPTION_TEXT ${SEC01} "Actual executable"\r  !insertmacro MUI_DESCRIPTION_TEXT ${SEC03} "Command modules"\r  !insertmacro MUI_DESCRIPTION_TEXT ${SEC02} "Default configuration files"\r  !insertmacro MUI_DESCRIPTION_TEXT ${SEC04} "Optional non-SSL modules"\r  !insertmacro MUI_DESCRIPTION_TEXT ${SEC05} "SSL modules and GnuTLS DLL libraries"\r  !insertmacro MUI_DESCRIPTION_TEXT ${SEC06} "Regular expression module and PCRE DLL library"\r!insertmacro MUI_FUNCTION_DESCRIPTION_END\r\r\rFunction un.onUninstSuccess\r  HideWindow\r  MessageBox MB_ICONINFORMATION|MB_OK "$(^Name) was successfully removed from your computer."\rFunctionEnd\r\rFunction .onInit\r  SectionSetFlags ${SEC01} 17\r  SectionSetFlags ${SEC03} 17\r  StrCpy $INSTDIR "$PROGRAMFILES\InspIRCd"\rFunctionEnd\r\rFunction un.onInit\r  MessageBox MB_ICONQUESTION|MB_YESNO|MB_DEFBUTTON2 "Are you sure you want to completely remove $(^Name) and all of its components?" IDYES +2\r  Abort\rFunctionEnd\r\rSection Uninstall\r  Delete "$INSTDIR\${PRODUCT_NAME}.url"\r  Delete "$INSTDIR\uninst.exe"\r  Delete "$INSTDIR\modules\m_*.so"\r  Delete "$INSTDIR\lib\cmd_*.so"\r  Delete "$INSTDIR\conf\inspircd.quotes.example"\r  Delete "$INSTDIR\conf\inspircd.rules.example"\r  Delete "$INSTDIR\conf\inspircd.censor.example"\r  Delete "$INSTDIR\conf\inspircd.conf.example"\r  Delete "$INSTDIR\conf\inspircd.filter.example"\r  Delete "$INSTDIR\conf\inspircd.helpop.example"\r  Delete "$INSTDIR\conf\inspircd.helpop-full.example"\r  Delete "$INSTDIR\conf\inspircd.motd.example"\r  Delete "$INSTDIR\bin\inspircd.exe"\r  Delete "$INSTDIR\bin\*.dll"\r  Delete "$INSTDIR\InspGUI.exe"\r  Delete "$SMPROGRAMS\InspIRCd\Uninstall.lnk"\r  Delete "$SMPROGRAMS\InspIRCd\InspIRCd Website.lnk"\r  Delete "$SMPROGRAMS\InspIRCd\InspIRCd.lnk"\r\r  RMDir "$SMPROGRAMS\InspIRCd"\r  RMDir "$INSTDIR\modules"\r  RMDir "$INSTDIR\lib"\r  RMDir "$INSTDIR\conf"\r  RMDir "$INSTDIR\bin"\r  RMDir "$INSTDIR"\r\r  DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}"\r  DeleteRegKey HKLM "${PRODUCT_DIR_REGKEY}"\r  SetAutoClose true\rSectionEnd\r
\ No newline at end of file
+; *       +------------------------------------+
+; *       | Inspire Internet Relay Chat Daemon |
+; *       +------------------------------------+
+; *
+; *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+; * See: http://www.inspircd.org/wiki/index.php/Credits
+; *
+; * This program is free but copyrighted software; see
+; *            the file COPYING for details.
+; *
+; * ---------------------------------------------------
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+                       ;;;; SET THE BUILD TO BE PACKAGED HERE ;;;;
+
+!define BUILD "release"
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; HM NIS Edit Wizard helper defines
+!define PRODUCT_NAME "InspIRCd"
+!define PRODUCT_VERSION "1.1"
+!define PRODUCT_PUBLISHER "InspIRCd Development Team"
+!define PRODUCT_WEB_SITE "http://www.inspircd.org/"
+!define PRODUCT_DIR_REGKEY "Software\Microsoft\Windows\CurrentVersion\App Paths\inspircd.exe"
+!define PRODUCT_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}"
+!define PRODUCT_UNINST_ROOT_KEY "HKLM"
+!define DOT_MAJOR "2"
+!define DOT_MINOR "0"
+
+SetCompressor bzip2
+
+; MUI 1.67 compatible ------
+!include "MUI.nsh"
+
+; MUI Settings
+!define MUI_ABORTWARNING
+!define MUI_ICON "inspircd.ico"
+!define MUI_UNICON "inspircd.ico"
+
+; Welcome page
+!insertmacro MUI_PAGE_WELCOME
+; License page
+!define MUI_LICENSEPAGE_CHECKBOX
+!insertmacro MUI_PAGE_LICENSE "..\docs\COPYING"
+; directory page
+Page directory
+; Components page
+!insertmacro MUI_PAGE_COMPONENTS
+; Instfiles page
+!insertmacro MUI_PAGE_INSTFILES
+; Finish page
+!define MUI_FINISHPAGE_RUN "$INSTDIR\InspGUI.exe"
+!insertmacro MUI_PAGE_FINISH
+
+; Uninstaller pages
+!insertmacro MUI_UNPAGE_INSTFILES
+
+; Language files
+!insertmacro MUI_LANGUAGE "English"
+
+; Reserve files
+!insertmacro MUI_RESERVEFILE_INSTALLOPTIONS
+
+; MUI end ------
+
+Name "${PRODUCT_NAME} ${PRODUCT_VERSION}"
+OutFile "Setup.exe"
+InstallDir "$PROGRAMFILES\InspIRCd"
+InstallDirRegKey HKLM "${PRODUCT_DIR_REGKEY}" ""
+ShowInstDetails show
+ShowUnInstDetails show
+
+Function IsDotNetInstalled
+  StrCpy $0 "0"
+  StrCpy $1 "SOFTWARE\Microsoft\.NETFramework" ;registry entry to look in.
+  StrCpy $2 0
+  StartEnum:
+    ;Enumerate the versions installed.
+    EnumRegKey $3 HKLM "$1\policy" $2
+    
+    ;If we don't find any versions installed, it's not here.
+    StrCmp $3 "" noDotNet notEmpty
+    
+    ;We found something.
+    notEmpty:
+      ;Find out if the RegKey starts with 'v'.  
+      ;If it doesn't, goto the next key.
+      StrCpy $4 $3 1 0
+      StrCmp $4 "v" +1 goNext
+      StrCpy $4 $3 1 1
+      
+      ;It starts with 'v'.  Now check to see how the installed major version
+      ;relates to our required major version.
+      ;If it's equal check the minor version, if it's greater, 
+      ;we found a good RegKey.
+      IntCmp $4 ${DOT_MAJOR} +1 goNext yesDotNetReg
+      ;Check the minor version.  If it's equal or greater to our requested 
+      ;version then we're good.
+      StrCpy $4 $3 1 3
+      IntCmp $4 ${DOT_MINOR} yesDotNetReg goNext yesDotNetReg
+    goNext:
+      ;Go to the next RegKey.
+      IntOp $2 $2 + 1
+      goto StartEnum
+  yesDotNetReg:
+    ;Now that we've found a good RegKey, let's make sure it's actually
+    ;installed by getting the install path and checking to see if the 
+    ;mscorlib.dll exists.
+    EnumRegValue $2 HKLM "$1\policy\$3" 0
+    ;$2 should equal whatever comes after the major and minor versions 
+    ;(ie, v1.1.4322)
+    StrCmp $2 "" noDotNet
+    ReadRegStr $4 HKLM $1 "InstallRoot"
+    ;Hopefully the install root isn't empty.
+    StrCmp $4 "" noDotNet
+    ;build the actuall directory path to mscorlib.dll.
+    StrCpy $4 "$4$3.$2\mscorlib.dll"
+    IfFileExists $4 yesDotNet noDotNet
+  noDotNet:
+    MessageBox MB_OK "You do not have have v${DOT_MAJOR}.${DOT_MINOR} or greater of the .NET framework installed. This is required for the InspIRCd Monitor, however you can still launch the IRCd manually."
+  yesDotNet:
+    ;Everything checks out.  Go on with the rest of the installation.
+    
+FunctionEnd
+
+Section "Binary Executable" SEC01
+  Call IsDotNetInstalled
+  SetOutPath "$INSTDIR"
+  SetOverwrite ifnewer
+  File "..\bin\${BUILD}\InspGUI.exe"
+  CreateDirectory "$SMPROGRAMS\InspIRCd"
+  CreateShortCut "$SMPROGRAMS\InspIRCd\InspIRCd.lnk" "$INSTDIR\InspGUI.exe"
+  SetOutPath "$INSTDIR\bin"
+  SetOverwrite ifnewer
+  File "..\bin\${BUILD}\bin\inspircd.exe"
+SectionEnd
+
+Section "Config Files" SEC02
+  SetOutPath "$INSTDIR\conf"
+  File "..\conf\inspircd.motd.example"
+  File "..\conf\inspircd.helpop-full.example"
+  File "..\conf\inspircd.helpop.example"
+  File "..\conf\inspircd.filter.example"
+  File "..\docs\inspircd.conf.example"
+  File "..\conf\inspircd.censor.example"
+  File "..\conf\inspircd.rules.example"
+  File "..\conf\inspircd.quotes.example"
+SectionEnd
+
+Section "Command Handlers" SEC03
+  SetOutPath "$INSTDIR\lib"
+  File "..\bin\${BUILD}\lib\cmd_*.so"
+SectionEnd
+
+Section "Modules" SEC04
+  SetOutPath "$INSTDIR\modules"
+  File "..\bin\${BUILD}\modules\m_*.so"
+SectionEnd
+
+Section  "SSL Modules" SEC05
+  SetOutPath "$INSTDIR\bin"
+  SetOverwrite ifnewer
+  File "..\bin\${BUILD}\bin\libgcrypt-11.dll"
+  File "..\bin\${BUILD}\bin\libgnutls-13.dll"
+  File "..\bin\${BUILD}\bin\libgnutls-extra-13.dll"
+  File "..\bin\${BUILD}\bin\libgnutls-openssl-13.dll"
+  File "..\bin\${BUILD}\bin\libgpg-error-0.dll"
+  File "..\bin\${BUILD}\bin\libopencdk-8.dll"
+  File "..\bin\${BUILD}\bin\libtasn1-3.dll"
+  SetOutPath "$INSTDIR\modules"
+  File "d:\temp\m_ssl_gnutls.so"
+  File "d:\temp\m_sslinfo.so"
+  File "d:\temp\m_ssl_oper_cert.so"
+  SetOutPath "$INSTDIR\conf"
+  SetOverwrite off
+  File "key.pem"
+  File "cert.pem"
+SectionEnd
+
+Section  "Regexp Modules" SEC06
+  SetOutPath "$INSTDIR\bin"
+  SetOverwrite ifnewer
+  File "..\bin\${BUILD}\bin\pcre.dll"
+  SetOutPath "$INSTDIR\modules"
+  File "d:\temp\m_filter_pcre.so"
+SectionEnd
+
+Section -AdditionalIcons
+  SetOutPath $INSTDIR
+  WriteIniStr "$INSTDIR\${PRODUCT_NAME}.url" "InternetShortcut" "URL" "${PRODUCT_WEB_SITE}"
+  CreateShortCut "$SMPROGRAMS\InspIRCd\InspIRCd Website.lnk" "$INSTDIR\${PRODUCT_NAME}.url"
+  CreateShortCut "$SMPROGRAMS\InspIRCd\Uninstall.lnk" "$INSTDIR\uninst.exe"
+SectionEnd
+
+Section -Post
+  WriteUninstaller "$INSTDIR\uninst.exe"
+  WriteRegStr HKLM "${PRODUCT_DIR_REGKEY}" "" "$INSTDIR\bin\inspircd.exe"
+  WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayName" "$(^Name)"
+  WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "UninstallString" "$INSTDIR\uninst.exe"
+  WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayIcon" "$INSTDIR\bin\inspircd.exe"
+  WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayVersion" "${PRODUCT_VERSION}"
+  WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "URLInfoAbout" "${PRODUCT_WEB_SITE}"
+  WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "Publisher" "${PRODUCT_PUBLISHER}"
+  MessageBox MB_ICONINFORMATION|MB_OK "InspIRCd was successfully installed. Remember to edit your configuration file in $INSTDIR\conf!"
+SectionEnd
+
+; Section descriptions
+!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN
+  !insertmacro MUI_DESCRIPTION_TEXT ${SEC01} "Actual executable"
+  !insertmacro MUI_DESCRIPTION_TEXT ${SEC03} "Command modules"
+  !insertmacro MUI_DESCRIPTION_TEXT ${SEC02} "Default configuration files"
+  !insertmacro MUI_DESCRIPTION_TEXT ${SEC04} "Optional non-SSL modules"
+  !insertmacro MUI_DESCRIPTION_TEXT ${SEC05} "SSL modules and GnuTLS DLL libraries"
+  !insertmacro MUI_DESCRIPTION_TEXT ${SEC06} "Regular expression module and PCRE DLL library"
+!insertmacro MUI_FUNCTION_DESCRIPTION_END
+
+
+Function un.onUninstSuccess
+  HideWindow
+  MessageBox MB_ICONINFORMATION|MB_OK "$(^Name) was successfully removed from your computer."
+FunctionEnd
+
+Function .onInit
+  SectionSetFlags ${SEC01} 17
+  SectionSetFlags ${SEC03} 17
+  StrCpy $INSTDIR "$PROGRAMFILES\InspIRCd"
+FunctionEnd
+
+Function un.onInit
+  MessageBox MB_ICONQUESTION|MB_YESNO|MB_DEFBUTTON2 "Are you sure you want to completely remove $(^Name) and all of its components?" IDYES +2
+  Abort
+FunctionEnd
+
+Section Uninstall
+  Delete "$INSTDIR\${PRODUCT_NAME}.url"
+  Delete "$INSTDIR\uninst.exe"
+  Delete "$INSTDIR\modules\m_*.so"
+  Delete "$INSTDIR\lib\cmd_*.so"
+  Delete "$INSTDIR\conf\inspircd.quotes.example"
+  Delete "$INSTDIR\conf\inspircd.rules.example"
+  Delete "$INSTDIR\conf\inspircd.censor.example"
+  Delete "$INSTDIR\conf\inspircd.conf.example"
+  Delete "$INSTDIR\conf\inspircd.filter.example"
+  Delete "$INSTDIR\conf\inspircd.helpop.example"
+  Delete "$INSTDIR\conf\inspircd.helpop-full.example"
+  Delete "$INSTDIR\conf\inspircd.motd.example"
+  Delete "$INSTDIR\bin\inspircd.exe"
+  Delete "$INSTDIR\bin\*.dll"
+  Delete "$INSTDIR\InspGUI.exe"
+  Delete "$SMPROGRAMS\InspIRCd\Uninstall.lnk"
+  Delete "$SMPROGRAMS\InspIRCd\InspIRCd Website.lnk"
+  Delete "$SMPROGRAMS\InspIRCd\InspIRCd.lnk"
+
+  RMDir "$SMPROGRAMS\InspIRCd"
+  RMDir "$INSTDIR\modules"
+  RMDir "$INSTDIR\lib"
+  RMDir "$INSTDIR\conf"
+  RMDir "$INSTDIR\bin"
+  RMDir "$INSTDIR"
+
+  DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}"
+  DeleteRegKey HKLM "${PRODUCT_DIR_REGKEY}"
+  SetAutoClose true
+SectionEnd
index 29c37a42e0badd899dc95308ceb6d6510cd196e0..afff4287eb591cf42337f41941a6eb5c5db508d0 100644 (file)
@@ -1 +1,44 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd_win32wrapper.h"\r#include <exception>\r#include <new>\r#include <new.h>\r\r/** On windows, all dll files and executables have their own private heap,\r * whereas on POSIX systems, shared objects loaded into an executable share\r * the executable's heap. This means that if we pass an arbitrary pointer to\r * a windows DLL which is not allocated in that dll, without some form of\r * marshalling, we get a page fault. To fix this, these overrided operators\r * new and delete use the windows HeapAlloc and HeapFree functions to claim\r * memory from the windows global heap. This makes windows 'act like' POSIX\r * when it comes to memory usage between dlls and exes.\r */\r\rvoid * ::operator new(size_t iSize)\r{\r     void* ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, iSize);               /* zero memory for unix compatibility */\r       /* This is the correct behaviour according to C++ standards for out of memory,\r  * not returning null -- Brain\r  */\r    if (!ptr)\r              throw std::bad_alloc();\r        else\r           return ptr;\r}\r\rvoid ::operator delete(void * ptr)\r{\r    HeapFree(GetProcessHeap(), 0, ptr);\r}\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd_win32wrapper.h"
+#include <exception>
+#include <new>
+#include <new.h>
+
+/** On windows, all dll files and executables have their own private heap,
+ * whereas on POSIX systems, shared objects loaded into an executable share
+ * the executable's heap. This means that if we pass an arbitrary pointer to
+ * a windows DLL which is not allocated in that dll, without some form of
+ * marshalling, we get a page fault. To fix this, these overrided operators
+ * new and delete use the windows HeapAlloc and HeapFree functions to claim
+ * memory from the windows global heap. This makes windows 'act like' POSIX
+ * when it comes to memory usage between dlls and exes.
+ */
+
+void * ::operator new(size_t iSize)
+{
+       void* ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, iSize);               /* zero memory for unix compatibility */
+       /* This is the correct behaviour according to C++ standards for out of memory,
+        * not returning null -- Brain
+        */
+       if (!ptr)
+               throw std::bad_alloc();
+       else
+               return ptr;
+}
+
+void ::operator delete(void * ptr)
+{
+       HeapFree(GetProcessHeap(), 0, ptr);
+}
index 1557c8f6e958d053b720d96a706b4a3f19aa3456..b3af867cff67c387685e2041950f2462d78030e7 100644 (file)
@@ -1 +1,513 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#include "inspircd_win32wrapper.h"\r#include "inspircd.h"\r#include <string>\r#include <errno.h>\r#include <assert.h>\rusing namespace std;\r\r#ifndef INADDR_NONE\r#define INADDR_NONE 0xffffffff\r#endif\r\rHANDLE hIPCPipe;\r\rint inet_aton(const char *cp, struct in_addr *addr)\r{\r        unsigned long ip = inet_addr(cp);\r      addr->s_addr = ip;\r     return (addr->s_addr == INADDR_NONE) ? 0 : 1;\r}\r\rconst char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt)\r{\r\r   if (af == AF_INET)\r     {\r              struct sockaddr_in in;\r         memset(&in, 0, sizeof(in));\r            in.sin_family = AF_INET;\r               memcpy(&in.sin_addr, src, sizeof(struct in_addr));\r             getnameinfo((struct sockaddr *)&in, sizeof(struct sockaddr_in), dst, cnt, NULL, 0, NI_NUMERICHOST);\r            return dst;\r    }\r      else if (af == AF_INET6)\r       {\r              struct sockaddr_in6 in;\r                memset(&in, 0, sizeof(in));\r            in.sin6_family = AF_INET6;\r             memcpy(&in.sin6_addr, src, sizeof(struct in_addr6));\r           getnameinfo((struct sockaddr *)&in, sizeof(struct sockaddr_in6), dst, cnt, NULL, 0, NI_NUMERICHOST);\r           return dst;\r    }\r      return NULL;\r}\r\rint geteuid()\r{\r        return 1;\r}\r\rint inet_pton(int af, const char *src, void *dst)\r{\r       sockaddr_in sa;\r        int len = sizeof(SOCKADDR);\r    int rv = WSAStringToAddress((LPSTR)src, af, NULL, (LPSOCKADDR)&sa, &len);\r      if(rv >= 0)\r    {\r              if(WSAGetLastError() == 10022)                  // Invalid Argument\r                    rv = 0;\r                else\r                   rv = 1;\r        }\r      memcpy(dst, &sa.sin_addr, sizeof(struct in_addr));\r     return rv;\r}\r\rchar * strtok_r(char *_String, const char *_Control, char **_Context)\r{\r  unsigned char *str;\r    const unsigned char *ctl = (const unsigned char*)_Control;\r     unsigned char map[32];\r\r        if (_Context == 0 || !_Control)\r                return 0;\r\r     if (!(_String != NULL || *_Context != NULL))\r           return 0;\r\r     memset(map, 0, 32);\r\r   do {\r           map[*ctl >> 3] |= (1 << (*ctl & 7));\r   } while (*ctl++);\r\r     /* If string is NULL, set str to the saved\r     * pointer (i.e., continue breaking tokens out of the string\r    * from the last strtok call) */\r        if (_String != NULL)\r   {\r              str = (unsigned char*)_String;\r }\r      else\r   {\r              str = (unsigned char*)*_Context;\r       }\r\r     /* Find beginning of token (skip over leading delimiters). Note that\r   * there is no token iff this loop sets str to point to the terminal\r    * null (*str == 0) */\r  while ((map[*str >> 3] & (1 << (*str & 7))) && *str != 0)\r      {\r              str++;\r }\r\r     _String = (char*)str;\r\r /* Find the end of the token. If it is not the end of the string,\r      * put a null there. */\r for ( ; *str != 0 ; str++ )\r    {\r              if (map[*str >> 3] & (1 << (*str & 7)))\r                {\r                      *str++ = 0;\r                    break;\r         }\r      }\r\r     /* Update context */\r   *_Context = (char*)str;\r\r       /* Determine if a token has been found. */\r     if (_String == (char*)str)\r     {\r              return NULL;\r   }\r      else\r   {\r              return _String;\r        }\r}\r\rvoid setcolor(int color_code)\r{\r   SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), color_code);\r}\r\rDIR * opendir(const char * path)\r{\r    std::string search_path = string(path) + "\\*.*";\r      WIN32_FIND_DATA fd;\r    HANDLE f = FindFirstFile(search_path.c_str(), &fd);\r    if (f != INVALID_HANDLE_VALUE)\r {\r              DIR * d = new DIR;\r             memcpy(&d->find_data, &fd, sizeof(WIN32_FIND_DATA));\r           d->find_handle = f;\r            d->first = true;\r               return d;\r      }\r      else\r   {\r              return 0;\r      }\r}\r\rdirent * readdir(DIR * handle)\r{\r  if (handle->first)\r             handle->first = false;\r else\r   {\r              if (!FindNextFile(handle->find_handle, &handle->find_data))\r                    return 0;\r      }\r\r     strncpy(handle->dirent_pointer.d_name, handle->find_data.cFileName, MAX_PATH);\r return &handle->dirent_pointer;\r}\r\rvoid closedir(DIR * handle)\r{\r       FindClose(handle->find_handle);\r        delete handle;\r}\r\rconst char * dlerror()\r{\r     static char errormessage[500];\r DWORD error = GetLastError();\r  SetLastError(0);\r       if (error == 0)\r                return 0;\r\r     FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 0, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)errormessage, 500, 0);\r  return errormessage;\r}\r\r#define TRED FOREGROUND_RED | FOREGROUND_INTENSITY\r#define TGREEN FOREGROUND_GREEN | FOREGROUND_INTENSITY\r#define TYELLOW FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY\r#define TNORMAL FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE\r#define TWHITE TNORMAL | FOREGROUND_INTENSITY\r#define TBLUE FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_INTENSITY\r\r/* Handles colors in printf */\rint printf_c(const char * format, ...)\r{\r  // Better hope we're not multithreaded, otherwise we'll have chickens crossing the road other side to get the to :P\r    static char message[MAXBUF];\r   static char temp[MAXBUF];\r      int color1, color2;\r\r   /* parse arguments */\r  va_list ap;\r    va_start(ap, format);\r  vsnprintf(message, 500, format, ap);\r   va_end(ap);\r\r   /* search for unix-style escape sequences */\r   int t;\r int c = 0;\r     const char * p = message;\r      while (*p != 0)\r        {\r              if (*p == '\033')\r              {\r                      // Escape sequence -> copy into the temp buffer, and parse the color.\r                  p++;\r                   t = 0;\r                 while ((*p) && (*p != 'm'))\r                    {\r                              temp[t++] = *p;\r                                ++p;\r                   }\r\r                     temp[t] = 0;\r                   p++;\r\r                  if (*temp == '[')\r                      {\r                              if (sscanf(temp, "[%u;%u", &color1, &color2) == 2)\r                             {\r                                      switch(color2)\r                                 {\r                                      case 32:                // Green\r                                               SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN | FOREGROUND_INTENSITY);              // Yellow\r                                              break;\r\r                                        default:                // Unknown\r                                             // White\r                                               SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);\r                                          break;\r                                 }\r                              }\r                              else\r                           {\r                                      switch (*(temp+1))\r                                     {\r                                              case '0':\r                                                      // Returning to normal colour.\r                                                 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);\r                                                 break;\r\r                                                case '1':\r                                                      // White\r                                                       SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), TWHITE);\r                                                      break;\r\r                                                default:\r                                                       char message[50];\r                                                      sprintf(message, "Unknown color code: %s", temp);\r                                                      MessageBox(0, message, message, MB_OK);\r                                                        break;\r                                 }\r                              }\r                      }\r              }\r\r             putchar(*p);\r           ++c;\r           ++p;\r   }\r\r     return c;\r}\r\rint arg_counter = 1;\rchar optarg[514];\rint getopt_long_only(int ___argc, char *const *___argv, const char *__shortopts, const struct option *__longopts, int *__longind)\r{\r        // burlex todo: handle the shortops, at the moment it only works with longopts.\r\r       if (___argc == 1 || arg_counter == ___argc)                     // No arguments (apart from filename)\r          return -1;\r\r    const char * opt = ___argv[arg_counter];\r       int return_val = 0;\r\r   // if we're not an option, return an error.\r    if (strnicmp(opt, "--", 2) != 0)\r               return 1;\r      else\r           opt += 2;\r\r\r    // parse argument list\r int i = 0;\r     for (; __longopts[i].name != 0; ++i)\r   {\r              if (!strnicmp(__longopts[i].name, opt, strlen(__longopts[i].name)))\r            {\r                      // woot, found a valid argument =)\r                     char * par = 0;\r                        if ((arg_counter + 1) != ___argc)\r                      {\r                              // grab the parameter from the next argument (if its not another argument)\r                             if (strnicmp(___argv[arg_counter+1], "--", 2) != 0)\r                            {\r                                      arg_counter++;          // Trash this next argument, we won't be needing it.\r                                   par = ___argv[arg_counter];\r                            }\r                      }                       \r\r                      // increment the argument for next time\r                        arg_counter++;\r\r                        // determine action based on type\r                      if (__longopts[i].has_arg == required_argument && !par)\r                        {\r                              // parameter missing and its a required parameter option\r                               return 1;\r                      }\r\r                     // store argument in optarg\r                    if (par)\r                               strncpy(optarg, par, 514);\r\r                    if (__longopts[i].flag != 0)\r                   {\r                              // this is a variable, we have to set it if this argument is found.\r                            *__longopts[i].flag = 1;\r                               return 0;\r                      }\r                      else\r                   {\r                              if (__longopts[i].val == -1 || par == 0)\r                                       return 1;\r                              \r                               return __longopts[i].val;\r                      }                       \r                       break;\r         }\r      }\r\r     // return 1 (invalid argument)\r return 1;\r}\r\r/* IPC Messages */\r#define IPC_MESSAGE_REHASH      1\r#define IPC_MESSAGE_DIE               2\r#define IPC_MESSAGE_RESTART   3\r\rvoid InitIPC()\r{\r    static DWORD buflen = 1024;\r    static const char * pipename = "\\\\.\\mailslot\\Inspircd";\r    hIPCPipe = CreateMailslot(pipename, buflen, 0, 0);\r     if (hIPCPipe == INVALID_HANDLE_VALUE)\r          printf("IPC Pipe could not be created. Are you sure you didn't start InspIRCd twice?\n");\r}\r\rvoid CheckIPC(InspIRCd * Instance)\r{\r      if (hIPCPipe == INVALID_HANDLE_VALUE)\r          return;\r\r       DWORD bytes;\r   DWORD action;\r\r BOOL res = ReadFile(hIPCPipe, &action, sizeof(DWORD), &bytes, 0);\r      if (!res)\r      {\r              if (GetLastError() != ERROR_SEM_TIMEOUT)\r                       Instance->Log(DEFAULT, "IPC Pipe Error %u: %s", GetLastError(), dlerror());\r            return;\r        }\r\r     switch (action)\r        {\r              case IPC_MESSAGE_REHASH:\r                       InspIRCd::Rehash(0);\r           break;\r         \r               case IPC_MESSAGE_DIE:\r                  InspIRCd::Exit(0);\r             break;\r\r                case IPC_MESSAGE_RESTART:\r                      Instance->Restart("IPC_MESSAGE_RESTART received by mailslot.");\r                break;\r }\r}\r\rvoid CloseIPC()\r{\r CloseHandle(hIPCPipe);\r}\r\r\r/* These three functions were created from looking at how ares does it\r * (...and they look far tidier in C++)\r */\r\r/* Get active nameserver */\rbool GetNameServer(HKEY regkey, const char *key, char* &output)\r{\r   DWORD size = 0;\r        DWORD result = RegQueryValueEx(regkey, key, 0, NULL, NULL, &size);\r     if (((result != ERROR_SUCCESS) && (result != ERROR_MORE_DATA)) || (!size))\r             return false;\r\r output = new char[size+1];\r\r    if ((RegQueryValueEx(regkey, key, 0, NULL, (LPBYTE)output, &size) != ERROR_SUCCESS) || (!*output))\r     {\r              delete output;\r         return false;\r  }\r      return true;\r}\r\r/* Check a network interface for its nameserver */\rbool GetInterface(HKEY regkey, const char *key, char* &output)\r{\r    char buf[39];\r  DWORD size = 39;\r       int idx = 0;\r   HKEY top;\r\r     while (RegEnumKeyEx(regkey, idx++, buf, &size, 0, NULL, NULL, NULL) != ERROR_NO_MORE_ITEMS)\r    {\r              size = 39;\r             if (RegOpenKeyEx(regkey, buf, 0, KEY_QUERY_VALUE, &top) != ERROR_SUCCESS)\r                      continue;\r              int rc = GetNameServer(top, key, output);\r              RegCloseKey(top);\r              if (rc)\r                        return true;\r   }\r      return false;\r}\r\r\rstd::string FindNameServerWin()\r{\r    std::string returnval = "127.0.0.1";\r   HKEY top, key;\r char* dns = NULL;\r\r     /* Lets see if the correct registry hive and tree exist */\r     if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "System\\CurrentControlSet\\Services\\Tcpip\\Parameters", 0, KEY_READ, &top) == ERROR_SUCCESS)\r    {\r              /* If they do, attempt to get the nameserver name */\r           RegOpenKeyEx(top, "Interfaces", 0, KEY_QUERY_VALUE|KEY_ENUMERATE_SUB_KEYS, &key);\r              if ((GetNameServer(top, "NameServer", dns)) || (GetNameServer(top, "DhcpNameServer", dns))\r                     || (GetInterface(key, "NameServer", dns)) || (GetInterface(key, "DhcpNameServer", dns)))\r               {\r                      if (dns)\r                       {\r                              returnval = dns;\r                               delete dns;\r                    }\r              }\r              RegCloseKey(key);\r              RegCloseKey(top);\r      }\r      return returnval;\r}\r\r\rvoid ClearConsole()\r{\r    COORD coordScreen = { 0, 0 };    /* here's where we'll home the cursor */\r      HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);\r     DWORD cCharsWritten;\r   CONSOLE_SCREEN_BUFFER_INFO csbi; /* to get buffer info */ \r     DWORD dwConSize;                 /* number of character cells in the current buffer */ \r\r       /* get the number of character cells in the current buffer */ \r\r        if (GetConsoleScreenBufferInfo( hConsole, &csbi ))\r     {\r              dwConSize = csbi.dwSize.X * csbi.dwSize.Y;\r             /* fill the entire screen with blanks */ \r              if (FillConsoleOutputCharacter( hConsole, (TCHAR) ' ', dwConSize, coordScreen, &cCharsWritten ))\r               {\r                      /* get the current text attribute */ \r                  if (GetConsoleScreenBufferInfo( hConsole, &csbi ))\r                     {\r                              /* now set the buffer's attributes accordingly */\r                              if (FillConsoleOutputAttribute( hConsole, csbi.wAttributes, dwConSize, coordScreen, &cCharsWritten ))\r                          {\r                                      /* put the cursor at (0, 0) */\r                                 SetConsoleCursorPosition( hConsole, coordScreen );\r                             }\r                      }\r              }\r      }\r      return;\r}\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#include "inspircd_win32wrapper.h"
+#include "inspircd.h"
+#include <string>
+#include <errno.h>
+#include <assert.h>
+using namespace std;
+
+#ifndef INADDR_NONE
+#define INADDR_NONE 0xffffffff
+#endif
+
+HANDLE hIPCPipe;
+
+int inet_aton(const char *cp, struct in_addr *addr)
+{
+       unsigned long ip = inet_addr(cp);
+       addr->s_addr = ip;
+       return (addr->s_addr == INADDR_NONE) ? 0 : 1;
+}
+
+const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt)
+{
+
+       if (af == AF_INET)
+       {
+               struct sockaddr_in in;
+               memset(&in, 0, sizeof(in));
+               in.sin_family = AF_INET;
+               memcpy(&in.sin_addr, src, sizeof(struct in_addr));
+               getnameinfo((struct sockaddr *)&in, sizeof(struct sockaddr_in), dst, cnt, NULL, 0, NI_NUMERICHOST);
+               return dst;
+       }
+       else if (af == AF_INET6)
+       {
+               struct sockaddr_in6 in;
+               memset(&in, 0, sizeof(in));
+               in.sin6_family = AF_INET6;
+               memcpy(&in.sin6_addr, src, sizeof(struct in_addr6));
+               getnameinfo((struct sockaddr *)&in, sizeof(struct sockaddr_in6), dst, cnt, NULL, 0, NI_NUMERICHOST);
+               return dst;
+       }
+       return NULL;
+}
+
+int geteuid()
+{
+       return 1;
+}
+
+int inet_pton(int af, const char *src, void *dst)
+{
+       sockaddr_in sa;
+       int len = sizeof(SOCKADDR);
+       int rv = WSAStringToAddress((LPSTR)src, af, NULL, (LPSOCKADDR)&sa, &len);
+       if(rv >= 0)
+       {
+               if(WSAGetLastError() == 10022)                  // Invalid Argument
+                       rv = 0;
+               else
+                       rv = 1;
+       }
+       memcpy(dst, &sa.sin_addr, sizeof(struct in_addr));
+       return rv;
+}
+
+char * strtok_r(char *_String, const char *_Control, char **_Context)
+{
+       unsigned char *str;
+       const unsigned char *ctl = (const unsigned char*)_Control;
+       unsigned char map[32];
+
+       if (_Context == 0 || !_Control)
+               return 0;
+
+       if (!(_String != NULL || *_Context != NULL))
+               return 0;
+
+       memset(map, 0, 32);
+
+       do {
+               map[*ctl >> 3] |= (1 << (*ctl & 7));
+       } while (*ctl++);
+
+       /* If string is NULL, set str to the saved
+       * pointer (i.e., continue breaking tokens out of the string
+       * from the last strtok call) */
+       if (_String != NULL)
+       {
+               str = (unsigned char*)_String;
+       }
+       else
+       {
+               str = (unsigned char*)*_Context;
+       }
+
+       /* Find beginning of token (skip over leading delimiters). Note that
+       * there is no token iff this loop sets str to point to the terminal
+       * null (*str == 0) */
+       while ((map[*str >> 3] & (1 << (*str & 7))) && *str != 0)
+       {
+               str++;
+       }
+
+       _String = (char*)str;
+
+       /* Find the end of the token. If it is not the end of the string,
+       * put a null there. */
+       for ( ; *str != 0 ; str++ )
+       {
+               if (map[*str >> 3] & (1 << (*str & 7)))
+               {
+                       *str++ = 0;
+                       break;
+               }
+       }
+
+       /* Update context */
+       *_Context = (char*)str;
+
+       /* Determine if a token has been found. */
+       if (_String == (char*)str)
+       {
+               return NULL;
+       }
+       else
+       {
+               return _String;
+       }
+}
+
+void setcolor(int color_code)
+{
+       SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), color_code);
+}
+
+DIR * opendir(const char * path)
+{
+       std::string search_path = string(path) + "\\*.*";
+       WIN32_FIND_DATA fd;
+       HANDLE f = FindFirstFile(search_path.c_str(), &fd);
+       if (f != INVALID_HANDLE_VALUE)
+       {
+               DIR * d = new DIR;
+               memcpy(&d->find_data, &fd, sizeof(WIN32_FIND_DATA));
+               d->find_handle = f;
+               d->first = true;
+               return d;
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+dirent * readdir(DIR * handle)
+{
+       if (handle->first)
+               handle->first = false;
+       else
+       {
+               if (!FindNextFile(handle->find_handle, &handle->find_data))
+                       return 0;
+       }
+
+       strncpy(handle->dirent_pointer.d_name, handle->find_data.cFileName, MAX_PATH);
+       return &handle->dirent_pointer;
+}
+
+void closedir(DIR * handle)
+{
+       FindClose(handle->find_handle);
+       delete handle;
+}
+
+const char * dlerror()
+{
+       static char errormessage[500];
+       DWORD error = GetLastError();
+       SetLastError(0);
+       if (error == 0)
+               return 0;
+
+       FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 0, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)errormessage, 500, 0);
+       return errormessage;
+}
+
+#define TRED FOREGROUND_RED | FOREGROUND_INTENSITY
+#define TGREEN FOREGROUND_GREEN | FOREGROUND_INTENSITY
+#define TYELLOW FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY
+#define TNORMAL FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE
+#define TWHITE TNORMAL | FOREGROUND_INTENSITY
+#define TBLUE FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_INTENSITY
+
+/* Handles colors in printf */
+int printf_c(const char * format, ...)
+{
+       // Better hope we're not multithreaded, otherwise we'll have chickens crossing the road other side to get the to :P
+       static char message[MAXBUF];
+       static char temp[MAXBUF];
+       int color1, color2;
+
+       /* parse arguments */
+       va_list ap;
+       va_start(ap, format);
+       vsnprintf(message, 500, format, ap);
+       va_end(ap);
+
+       /* search for unix-style escape sequences */
+       int t;
+       int c = 0;
+       const char * p = message;
+       while (*p != 0)
+       {
+               if (*p == '\033')
+               {
+                       // Escape sequence -> copy into the temp buffer, and parse the color.
+                       p++;
+                       t = 0;
+                       while ((*p) && (*p != 'm'))
+                       {
+                               temp[t++] = *p;
+                               ++p;
+                       }
+
+                       temp[t] = 0;
+                       p++;
+
+                       if (*temp == '[')
+                       {
+                               if (sscanf(temp, "[%u;%u", &color1, &color2) == 2)
+                               {
+                                       switch(color2)
+                                       {
+                                       case 32:                // Green
+                                               SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN | FOREGROUND_INTENSITY);              // Yellow
+                                               break;
+
+                                       default:                // Unknown
+                                               // White
+                                               SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
+                                               break;
+                                       }
+                               }
+                               else
+                               {
+                                       switch (*(temp+1))
+                                       {
+                                               case '0':
+                                                       // Returning to normal colour.
+                                                       SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
+                                                       break;
+
+                                               case '1':
+                                                       // White
+                                                       SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), TWHITE);
+                                                       break;
+
+                                               default:
+                                                       char message[50];
+                                                       sprintf(message, "Unknown color code: %s", temp);
+                                                       MessageBox(0, message, message, MB_OK);
+                                                       break;
+                                       }
+                               }
+                       }
+               }
+
+               putchar(*p);
+               ++c;
+               ++p;
+       }
+
+       return c;
+}
+
+int arg_counter = 1;
+char optarg[514];
+int getopt_long_only(int ___argc, char *const *___argv, const char *__shortopts, const struct option *__longopts, int *__longind)
+{
+       // burlex todo: handle the shortops, at the moment it only works with longopts.
+
+       if (___argc == 1 || arg_counter == ___argc)                     // No arguments (apart from filename)
+               return -1;
+
+       const char * opt = ___argv[arg_counter];
+       int return_val = 0;
+
+       // if we're not an option, return an error.
+       if (strnicmp(opt, "--", 2) != 0)
+               return 1;
+       else
+               opt += 2;
+
+
+       // parse argument list
+       int i = 0;
+       for (; __longopts[i].name != 0; ++i)
+       {
+               if (!strnicmp(__longopts[i].name, opt, strlen(__longopts[i].name)))
+               {
+                       // woot, found a valid argument =)
+                       char * par = 0;
+                       if ((arg_counter + 1) != ___argc)
+                       {
+                               // grab the parameter from the next argument (if its not another argument)
+                               if (strnicmp(___argv[arg_counter+1], "--", 2) != 0)
+                               {
+                                       arg_counter++;          // Trash this next argument, we won't be needing it.
+                                       par = ___argv[arg_counter];
+                               }
+                       }                       
+
+                       // increment the argument for next time
+                       arg_counter++;
+
+                       // determine action based on type
+                       if (__longopts[i].has_arg == required_argument && !par)
+                       {
+                               // parameter missing and its a required parameter option
+                               return 1;
+                       }
+
+                       // store argument in optarg
+                       if (par)
+                               strncpy(optarg, par, 514);
+
+                       if (__longopts[i].flag != 0)
+                       {
+                               // this is a variable, we have to set it if this argument is found.
+                               *__longopts[i].flag = 1;
+                               return 0;
+                       }
+                       else
+                       {
+                               if (__longopts[i].val == -1 || par == 0)
+                                       return 1;
+                               
+                               return __longopts[i].val;
+                       }                       
+                       break;
+               }
+       }
+
+       // return 1 (invalid argument)
+       return 1;
+}
+
+/* IPC Messages */
+#define IPC_MESSAGE_REHASH     1
+#define IPC_MESSAGE_DIE                2
+#define IPC_MESSAGE_RESTART    3
+
+void InitIPC()
+{
+       static DWORD buflen = 1024;
+       static const char * pipename = "\\\\.\\mailslot\\Inspircd";
+       hIPCPipe = CreateMailslot(pipename, buflen, 0, 0);
+       if (hIPCPipe == INVALID_HANDLE_VALUE)
+               printf("IPC Pipe could not be created. Are you sure you didn't start InspIRCd twice?\n");
+}
+
+void CheckIPC(InspIRCd * Instance)
+{
+       if (hIPCPipe == INVALID_HANDLE_VALUE)
+               return;
+
+       DWORD bytes;
+       DWORD action;
+
+       BOOL res = ReadFile(hIPCPipe, &action, sizeof(DWORD), &bytes, 0);
+       if (!res)
+       {
+               if (GetLastError() != ERROR_SEM_TIMEOUT)
+                       Instance->Log(DEFAULT, "IPC Pipe Error %u: %s", GetLastError(), dlerror());
+               return;
+       }
+
+       switch (action)
+       {
+               case IPC_MESSAGE_REHASH:
+                       InspIRCd::Rehash(0);
+               break;
+               
+               case IPC_MESSAGE_DIE:
+                       InspIRCd::Exit(0);
+               break;
+
+               case IPC_MESSAGE_RESTART:
+                       Instance->Restart("IPC_MESSAGE_RESTART received by mailslot.");
+               break;
+       }
+}
+
+void CloseIPC()
+{
+       CloseHandle(hIPCPipe);
+}
+
+
+/* These three functions were created from looking at how ares does it
+ * (...and they look far tidier in C++)
+ */
+
+/* Get active nameserver */
+bool GetNameServer(HKEY regkey, const char *key, char* &output)
+{
+       DWORD size = 0;
+       DWORD result = RegQueryValueEx(regkey, key, 0, NULL, NULL, &size);
+       if (((result != ERROR_SUCCESS) && (result != ERROR_MORE_DATA)) || (!size))
+               return false;
+
+       output = new char[size+1];
+
+       if ((RegQueryValueEx(regkey, key, 0, NULL, (LPBYTE)output, &size) != ERROR_SUCCESS) || (!*output))
+       {
+               delete output;
+               return false;
+       }
+       return true;
+}
+
+/* Check a network interface for its nameserver */
+bool GetInterface(HKEY regkey, const char *key, char* &output)
+{
+       char buf[39];
+       DWORD size = 39;
+       int idx = 0;
+       HKEY top;
+
+       while (RegEnumKeyEx(regkey, idx++, buf, &size, 0, NULL, NULL, NULL) != ERROR_NO_MORE_ITEMS)
+       {
+               size = 39;
+               if (RegOpenKeyEx(regkey, buf, 0, KEY_QUERY_VALUE, &top) != ERROR_SUCCESS)
+                       continue;
+               int rc = GetNameServer(top, key, output);
+               RegCloseKey(top);
+               if (rc)
+                       return true;
+       }
+       return false;
+}
+
+
+std::string FindNameServerWin()
+{
+       std::string returnval = "127.0.0.1";
+       HKEY top, key;
+       char* dns = NULL;
+
+       /* Lets see if the correct registry hive and tree exist */
+       if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "System\\CurrentControlSet\\Services\\Tcpip\\Parameters", 0, KEY_READ, &top) == ERROR_SUCCESS)
+       {
+               /* If they do, attempt to get the nameserver name */
+               RegOpenKeyEx(top, "Interfaces", 0, KEY_QUERY_VALUE|KEY_ENUMERATE_SUB_KEYS, &key);
+               if ((GetNameServer(top, "NameServer", dns)) || (GetNameServer(top, "DhcpNameServer", dns))
+                       || (GetInterface(key, "NameServer", dns)) || (GetInterface(key, "DhcpNameServer", dns)))
+               {
+                       if (dns)
+                       {
+                               returnval = dns;
+                               delete dns;
+                       }
+               }
+               RegCloseKey(key);
+               RegCloseKey(top);
+       }
+       return returnval;
+}
+
+
+void ClearConsole()
+{
+       COORD coordScreen = { 0, 0 };    /* here's where we'll home the cursor */
+       HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
+       DWORD cCharsWritten;
+       CONSOLE_SCREEN_BUFFER_INFO csbi; /* to get buffer info */ 
+       DWORD dwConSize;                 /* number of character cells in the current buffer */ 
+
+       /* get the number of character cells in the current buffer */ 
+
+       if (GetConsoleScreenBufferInfo( hConsole, &csbi ))
+       {
+               dwConSize = csbi.dwSize.X * csbi.dwSize.Y;
+               /* fill the entire screen with blanks */ 
+               if (FillConsoleOutputCharacter( hConsole, (TCHAR) ' ', dwConSize, coordScreen, &cCharsWritten ))
+               {
+                       /* get the current text attribute */ 
+                       if (GetConsoleScreenBufferInfo( hConsole, &csbi ))
+                       {
+                               /* now set the buffer's attributes accordingly */
+                               if (FillConsoleOutputAttribute( hConsole, csbi.wAttributes, dwConSize, coordScreen, &cCharsWritten ))
+                               {
+                                       /* put the cursor at (0, 0) */
+                                       SetConsoleCursorPosition( hConsole, coordScreen );
+                               }
+                       }
+               }
+       }
+       return;
+}
index ee0feb77ef85038a98095ec7aaee2db29027c0fc..fb688237868dd94fc5352056a0d805afb355cc94 100644 (file)
@@ -1 +1,189 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r/* Windows Port\r   Wrapper Functions/Definitions\r   By Burlex */\r\r#ifndef INSPIRCD_WIN32WRAPPER_H\r#define INSPIRCD_WIN32WRAPPER_H\r\r/* Define the WINDOWS macro. This means we're building on windows to the rest of the server.\r   I think this is more reasonable than using WIN32, especially if we're gonna be doing 64-bit compiles */\r#define WINDOWS 1\r\r/* Make builds smaller, leaner and faster */\r#define VC_EXTRALEAN\r\r/* They just have to be *different*, don't they. */\r#define PATH_MAX MAX_PATH\r\r/* Begone shitty 'safe STL' warnings */\r#define _SCL_SECURE_NO_WARNINGS\r#define _CRT_SECURE_NO_WARNINGS\r#define _AFX_SECURE_NO_WARNINGS\r#define _ATL_SECURE_NO_WARNINGS\r\r/* Macros for exporting symbols - dependant on what is being compiled */\r\r#ifdef DLL_BUILD\r#define CoreExport __declspec(dllimport)\r#define DllExport __declspec(dllexport)\r#else\r#define CoreExport __declspec(dllexport)\r#define DllExport __declspec(dllimport)\r#endif\r\r/* Disable the deprecation warnings.. it spams :P */\r#define _CRT_SECURE_NO_DEPRECATE\r#define _SCL_SECURE_NO_DEPRECATE\r\r#include <string>\r\r/* Say we're building on windows 2000. Anyone running something older than this\r * reeeeeeeally needs to upgrade! */\r\r#define _WIN32_WINNT 0x500\r\r/* Normal windows (platform-specific) includes */\r#include <winsock2.h>\r#include <windows.h>\r#include <ws2tcpip.h>\r#include <sys/types.h>\r#include <sys/stat.h>\r#include <direct.h>\r#include <process.h>\r#include <stdio.h>\r#include <algorithm>\r\r/* strcasecmp is not defined on windows by default */\r#define strcasecmp _stricmp\r\r/* Error macros need to be redirected to winsock error codes */\r#define ETIMEDOUT WSAETIMEDOUT\r#define ECONNREFUSED WSAECONNREFUSED\r#define EADDRINUSE WSAEADDRINUSE\r#define EINPROGRESS WSAEWOULDBLOCK\r\r/* Remember file descriptors are treated differently on windows ;) */\r__inline int close(int socket) { return closesocket(socket); }\r\r/* Convert formatted (xxx.xxx.xxx.xxx) string to in_addr struct */\rCoreExport int inet_pton(int af, const char * src, void * dst);\r\r/* Convert struct to formatted (xxx.xxx.xxx.xxx) string */\rCoreExport const char * inet_ntop(int af, const void * src, char * dst, socklen_t cnt);\r\r/* Safe printf functions aren't defined in VC2003 */\r#define snprintf _snprintf\r#define vsnprintf _vsnprintf\r\r/* Recursive token function doesn't exist in VC++ */\rCoreExport char * strtok_r(char *_String, const char *_Control, char **_Context);\r\r/* Unix-style sleep (argument is in seconds) */\r__inline void sleep(int seconds) { Sleep(seconds * 1000); }\r\r/* IPV4 only convert string to address struct */\rCoreExport int inet_aton(const char *, struct in_addr *);\r\r/* Unix-style get running user id */\rCoreExport int geteuid();\r\r/* Handles colors in printf */\rCoreExport int printf_c(const char * format, ...);\r\r/* getopt() wrapper */\r# define no_argument            0\r# define required_argument      1\r# define optional_argument      2\rstruct option\r{\r       char *name;\r    int has_arg;\r   int *flag;\r     int val;\r};\rextern char optarg[514];\rint getopt_long_only (int ___argc, char *const *___argv, const char *__shortopts, const struct option *__longopts, int *__longind);\r\r/* Accept Handlers */\rstruct udp_overlap;\rCoreExport int __accept_socket(SOCKET s, sockaddr * addr, int * addrlen, void * acceptevent);\rCoreExport int __getsockname(SOCKET s, sockaddr * name, int * namelen, void * acceptevent);\rCoreExport int __recvfrom(SOCKET s, char * buf, int len, int flags, struct sockaddr * from, int * fromlen, udp_overlap * ov);\r\r/* Module Loading */\r#define dlopen(path, state) (void*)LoadLibrary(path)\r#define dlsym(handle, export) (void*)GetProcAddress((HMODULE)handle, export)\r#define dlclose(handle) FreeLibrary((HMODULE)handle)\rconst char * dlerror();\r\r/* Unix-style directory searching functions */\r#define chmod(filename, mode)  \rstruct dirent\r{\r       char d_name[MAX_PATH];\r};\r\rstruct DIR\r{\r        dirent dirent_pointer;\r HANDLE find_handle;\r    WIN32_FIND_DATA find_data;\r     bool first;\r};\r\rCoreExport DIR * opendir(const char * path);\rCoreExport dirent * readdir(DIR * handle);\rCoreExport void closedir(DIR * handle);\r\r/* Disable these stupid warnings.. */\r#pragma warning(disable:4800)\r#pragma warning(disable:4251)\r#pragma warning(disable:4275)\r#pragma warning(disable:4244)          // warning C4244: '=' : conversion from 'long' to 'short', possible loss of data\r#pragma warning(disable:4267)          // warning C4267: 'argument' : conversion from 'size_t' to 'int', possible loss of data\r#pragma warning(disable:4805)           // warning C4805: '!=' : unsafe mix of type 'char' and type 'bool' in operation\r#pragma warning(disable:4311)           // warning C4311: 'type cast' : pointer truncation from 'accept_overlap *' to 'int'\r#pragma warning(disable:4312)               // warning C4312: 'type cast' : conversion from 'int' to 'HANDLE' of greater size\r#pragma warning(disable:4355)         // warning C4355: 'this' : used in base member initializer list\r#pragma warning(disable:4996)           // warning C4996: 'std::_Traits_helper::move_s' was declared deprecated\r\r/* Mehhhh... typedefs. */\r\rtypedef unsigned char uint8_t;\rtypedef unsigned long long uint64_t;\rtypedef signed char int8_t;\rtypedef signed long int32_t;\rtypedef signed long long int64_t;\r\r/* Shared memory allocation functions */\rvoid * ::operator new(size_t iSize);\rvoid ::operator delete(void * ptr);\r\r/* IPC Handlers */\rclass InspIRCd;\r\rvoid InitIPC();\rvoid CheckIPC(InspIRCd * Instance);\rvoid CloseIPC();\r\r/* Look up the nameserver in use from the registry on windows */\rstd::string FindNameServerWin();\r\r/* Clear a windows console */\rvoid ClearConsole();\r\r#endif\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+/* Windows Port
+   Wrapper Functions/Definitions
+   By Burlex */
+
+#ifndef INSPIRCD_WIN32WRAPPER_H
+#define INSPIRCD_WIN32WRAPPER_H
+
+/* Define the WINDOWS macro. This means we're building on windows to the rest of the server.
+   I think this is more reasonable than using WIN32, especially if we're gonna be doing 64-bit compiles */
+#define WINDOWS 1
+
+/* Make builds smaller, leaner and faster */
+#define VC_EXTRALEAN
+
+/* They just have to be *different*, don't they. */
+#define PATH_MAX MAX_PATH
+
+/* Begone shitty 'safe STL' warnings */
+#define _SCL_SECURE_NO_WARNINGS
+#define _CRT_SECURE_NO_WARNINGS
+#define _AFX_SECURE_NO_WARNINGS
+#define _ATL_SECURE_NO_WARNINGS
+
+/* Macros for exporting symbols - dependant on what is being compiled */
+
+#ifdef DLL_BUILD
+#define CoreExport __declspec(dllimport)
+#define DllExport __declspec(dllexport)
+#else
+#define CoreExport __declspec(dllexport)
+#define DllExport __declspec(dllimport)
+#endif
+
+/* Disable the deprecation warnings.. it spams :P */
+#define _CRT_SECURE_NO_DEPRECATE
+#define _SCL_SECURE_NO_DEPRECATE
+
+#include <string>
+
+/* Say we're building on windows 2000. Anyone running something older than this
+ * reeeeeeeally needs to upgrade! */
+
+#define _WIN32_WINNT 0x500
+
+/* Normal windows (platform-specific) includes */
+#include <winsock2.h>
+#include <windows.h>
+#include <ws2tcpip.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <direct.h>
+#include <process.h>
+#include <stdio.h>
+#include <algorithm>
+
+/* strcasecmp is not defined on windows by default */
+#define strcasecmp _stricmp
+
+/* Error macros need to be redirected to winsock error codes */
+#define ETIMEDOUT WSAETIMEDOUT
+#define ECONNREFUSED WSAECONNREFUSED
+#define EADDRINUSE WSAEADDRINUSE
+#define EINPROGRESS WSAEWOULDBLOCK
+
+/* Remember file descriptors are treated differently on windows ;) */
+__inline int close(int socket) { return closesocket(socket); }
+
+/* Convert formatted (xxx.xxx.xxx.xxx) string to in_addr struct */
+CoreExport int inet_pton(int af, const char * src, void * dst);
+
+/* Convert struct to formatted (xxx.xxx.xxx.xxx) string */
+CoreExport const char * inet_ntop(int af, const void * src, char * dst, socklen_t cnt);
+
+/* Safe printf functions aren't defined in VC2003 */
+#define snprintf _snprintf
+#define vsnprintf _vsnprintf
+
+/* Recursive token function doesn't exist in VC++ */
+CoreExport char * strtok_r(char *_String, const char *_Control, char **_Context);
+
+/* Unix-style sleep (argument is in seconds) */
+__inline void sleep(int seconds) { Sleep(seconds * 1000); }
+
+/* IPV4 only convert string to address struct */
+CoreExport int inet_aton(const char *, struct in_addr *);
+
+/* Unix-style get running user id */
+CoreExport int geteuid();
+
+/* Handles colors in printf */
+CoreExport int printf_c(const char * format, ...);
+
+/* getopt() wrapper */
+# define no_argument            0
+# define required_argument      1
+# define optional_argument      2
+struct option
+{
+       char *name;
+       int has_arg;
+       int *flag;
+       int val;
+};
+extern char optarg[514];
+int getopt_long_only (int ___argc, char *const *___argv, const char *__shortopts, const struct option *__longopts, int *__longind);
+
+/* Accept Handlers */
+struct udp_overlap;
+CoreExport int __accept_socket(SOCKET s, sockaddr * addr, int * addrlen, void * acceptevent);
+CoreExport int __getsockname(SOCKET s, sockaddr * name, int * namelen, void * acceptevent);
+CoreExport int __recvfrom(SOCKET s, char * buf, int len, int flags, struct sockaddr * from, int * fromlen, udp_overlap * ov);
+
+/* Module Loading */
+#define dlopen(path, state) (void*)LoadLibrary(path)
+#define dlsym(handle, export) (void*)GetProcAddress((HMODULE)handle, export)
+#define dlclose(handle) FreeLibrary((HMODULE)handle)
+const char * dlerror();
+
+/* Unix-style directory searching functions */
+#define chmod(filename, mode)  
+struct dirent
+{
+       char d_name[MAX_PATH];
+};
+
+struct DIR
+{
+       dirent dirent_pointer;
+       HANDLE find_handle;
+       WIN32_FIND_DATA find_data;
+       bool first;
+};
+
+CoreExport DIR * opendir(const char * path);
+CoreExport dirent * readdir(DIR * handle);
+CoreExport void closedir(DIR * handle);
+
+/* Disable these stupid warnings.. */
+#pragma warning(disable:4800)
+#pragma warning(disable:4251)
+#pragma warning(disable:4275)
+#pragma warning(disable:4244)          // warning C4244: '=' : conversion from 'long' to 'short', possible loss of data
+#pragma warning(disable:4267)          // warning C4267: 'argument' : conversion from 'size_t' to 'int', possible loss of data
+#pragma warning(disable:4805)          // warning C4805: '!=' : unsafe mix of type 'char' and type 'bool' in operation
+#pragma warning(disable:4311)          // warning C4311: 'type cast' : pointer truncation from 'accept_overlap *' to 'int'
+#pragma warning(disable:4312)          // warning C4312: 'type cast' : conversion from 'int' to 'HANDLE' of greater size
+#pragma warning(disable:4355)          // warning C4355: 'this' : used in base member initializer list
+#pragma warning(disable:4996)          // warning C4996: 'std::_Traits_helper::move_s' was declared deprecated
+
+/* Mehhhh... typedefs. */
+
+typedef unsigned char uint8_t;
+typedef unsigned long long uint64_t;
+typedef signed char int8_t;
+typedef signed long int32_t;
+typedef signed long long int64_t;
+
+/* Shared memory allocation functions */
+void * ::operator new(size_t iSize);
+void ::operator delete(void * ptr);
+
+/* IPC Handlers */
+class InspIRCd;
+
+void InitIPC();
+void CheckIPC(InspIRCd * Instance);
+void CloseIPC();
+
+/* Look up the nameserver in use from the registry on windows */
+std::string FindNameServerWin();
+
+/* Clear a windows console */
+void ClearConsole();
+
+#endif
+
index 2cb3eda40a50838ab7b9ae62a41be4f7560e93e6..09b298260e7349569f43728a893ffd33003d735e 100644 (file)
@@ -1 +1,15 @@
------BEGIN RSA PRIVATE KEY-----\rMIICWwIBAAKBgQDIbKvMTTogBZxTi1yn4ncVK09Wr+F2AxP63HWTzxnEwNhcURSa\rUqpCzVIfcpr7/jKn+8I17MzaMvG8m+sPKngPK5WMN440p12uitkS+uzkLbJ7J/Z3\r35ar6nZOtbIO+aTDRzUTnNHGHRgdQj4GGvx89l0u7vQM3R2f9Oe2lWlc1wIDAQAB\rAoGABh+/7hmr/X9+Y9Udyylxzw1IOtNb9cGpUiB7XT1WQbtMwSFfGkoNVsY0TK6x\rSqLdRGG+cOxf5AjrdwJin8+B5JLsoFUJ79ouUSye4IpywH6pQPzTW5L/Pqw+lM81\rYZB/I7OKwSOkmFvKM8l9Y3U/UdvPeVPU44jAsnTyN9gZ/q0CQQDb+qGe7T8AIm1U\rrz9Wf8/BBQy6ShoaL5sv0dqLE1/CWkGPnkhm8HA/6udlUiVNBcWlirKeSuzctC23\ru/mGU179AkEA6T5TyZ798qKyKpZXqNzyfnq5RMjCdr12rtk+sTYThbHndGonhjKk\rPqWgQ/Aq3t33J740jsNpz6za6/hPRGp1YwJANE4o5eAljcOh2XP+DHRBkvS/bQA3\rqqhNLxan70/BAjZxxlNthcR//EK/mJDqu6C2uUD8bbUFEwlooXp5v13NhQJALGbN\rFIjL1zDZsfnE3kSRdTpvooSFYI1Y1phMsveUZ9MiOKssswNY+QQWqlhCEQM4VbyD\rzNmufvZtBpbSoDeT+QJAasQ/yEgYJnC+nbWmiJVuIFYFiWkxYToSUv4yFq2zHj6O\rhVVCUr60FTMzqzS4BXzWVQVX2ylDJA40dUBTZ9HI7g==\r-----END RSA PRIVATE KEY-----\r
\ No newline at end of file
+-----BEGIN RSA PRIVATE KEY-----
+MIICWwIBAAKBgQDIbKvMTTogBZxTi1yn4ncVK09Wr+F2AxP63HWTzxnEwNhcURSa
+UqpCzVIfcpr7/jKn+8I17MzaMvG8m+sPKngPK5WMN440p12uitkS+uzkLbJ7J/Z3
+35ar6nZOtbIO+aTDRzUTnNHGHRgdQj4GGvx89l0u7vQM3R2f9Oe2lWlc1wIDAQAB
+AoGABh+/7hmr/X9+Y9Udyylxzw1IOtNb9cGpUiB7XT1WQbtMwSFfGkoNVsY0TK6x
+SqLdRGG+cOxf5AjrdwJin8+B5JLsoFUJ79ouUSye4IpywH6pQPzTW5L/Pqw+lM81
+YZB/I7OKwSOkmFvKM8l9Y3U/UdvPeVPU44jAsnTyN9gZ/q0CQQDb+qGe7T8AIm1U
+rz9Wf8/BBQy6ShoaL5sv0dqLE1/CWkGPnkhm8HA/6udlUiVNBcWlirKeSuzctC23
+u/mGU179AkEA6T5TyZ798qKyKpZXqNzyfnq5RMjCdr12rtk+sTYThbHndGonhjKk
+PqWgQ/Aq3t33J740jsNpz6za6/hPRGp1YwJANE4o5eAljcOh2XP+DHRBkvS/bQA3
+qqhNLxan70/BAjZxxlNthcR//EK/mJDqu6C2uUD8bbUFEwlooXp5v13NhQJALGbN
+FIjL1zDZsfnE3kSRdTpvooSFYI1Y1phMsveUZ9MiOKssswNY+QQWqlhCEQM4VbyD
+zNmufvZtBpbSoDeT+QJAasQ/yEgYJnC+nbWmiJVuIFYFiWkxYToSUv4yFq2zHj6O
+hVVCUr60FTMzqzS4BXzWVQVX2ylDJA40dUBTZ9HI7g==
+-----END RSA PRIVATE KEY-----
index cd3895a1ebff5c74a76cad53e59fc54ea5d3317f..e7ba79abd161fb391b57592ad494a45216b6331a 100644 (file)
@@ -1 +1,7 @@
-@mkdir d:\temp\\rmove ..\bin\release\modules\m_ssl_gnutls.so d:\temp\\rmove ..\bin\release\modules\m_sslinfo.so d:\temp\\rmove ..\bin\release\modules\m_ssl_oper_cert.so d:\temp\\rmove ..\bin\release\modules\m_filter_pcre.so d:\temp\r"C:\Program Files\NSIS\makensisw.exe" "inspircd.nsi"\rmove d:\temp\*.so ..\bin\release\modules\\r
\ No newline at end of file
+@mkdir d:\temp\
+move ..\bin\release\modules\m_ssl_gnutls.so d:\temp\
+move ..\bin\release\modules\m_sslinfo.so d:\temp\
+move ..\bin\release\modules\m_ssl_oper_cert.so d:\temp\
+move ..\bin\release\modules\m_filter_pcre.so d:\temp
+"C:\Program Files\NSIS\makensisw.exe" "inspircd.nsi"
+move d:\temp\*.so ..\bin\release\modules\